Browse Source

Initial support for monaco hover provider

Shaddock Heath 9 years ago
parent
commit
b808fbd1aa

+ 42 - 0
Script/AtomicWebViewEditor/clientExtensions/languageExtensions/typescript/TypescriptLanguageExtension.ts

@@ -166,6 +166,7 @@ export default class TypescriptLanguageExtension implements Editor.ClientExtensi
 
                 // Register editor feature providers
                 monaco.languages.registerCompletionItemProvider("javascript", new CustomCompletionProvider(this));
+                monaco.languages.registerHoverProvider("javascript", new CustomHoverProvider(this));
             } else {
                 monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
                     noEmit: true,
@@ -181,6 +182,7 @@ export default class TypescriptLanguageExtension implements Editor.ClientExtensi
 
                 // Register editor feature providers
                 monaco.languages.registerCompletionItemProvider("typescript", new CustomCompletionProvider(this));
+                monaco.languages.registerHoverProvider("typescript", new CustomHoverProvider(this));
             }
         }
     }
@@ -446,3 +448,43 @@ class CustomCompletionProvider implements monaco.languages.CompletionItemProvide
             });
     }
 }
+
+class CustomHoverProvider implements monaco.languages.HoverProvider {
+    constructor(extension: TypescriptLanguageExtension) {
+        this.extension = extension;
+    }
+    private extension: TypescriptLanguageExtension;
+
+    protected _offsetToPosition(uri: monaco.Uri, offset: number): monaco.IPosition {
+        let model = monaco.editor.getModel(uri);
+        return model.getPositionAt(offset);
+    }
+
+    protected _textSpanToRange(uri: monaco.Uri, span: ts.TextSpan): monaco.IRange {
+        let p1 = this._offsetToPosition(uri, span.start);
+        let p2 = this._offsetToPosition(uri, span.start + span.length);
+        let {lineNumber: startLineNumber, column: startColumn} = p1;
+        let {lineNumber: endLineNumber, column: endColumn} = p2;
+        return { startLineNumber, startColumn, endLineNumber, endColumn };
+    }
+
+    provideHover(model, position) {
+        let resource = model.uri;
+        const message: WorkerProcessTypes.MonacoGetQuickInfoMessageData = {
+            command: WorkerProcessTypes.MonacoGetQuickInfo,
+            uri: this.extension.filename,
+            source: model.getValue(),
+            positionOffset: model.getOffsetAt(position)
+        };
+
+        return this.extension.workerRequest(WorkerProcessTypes.MonacoGetQuickInfoResponse, message)
+            .then((e: WorkerProcessTypes.MonacoGetQuickInfoResponseMessageData) => {
+                if (e.contents) {
+                    return {
+                        range: this._textSpanToRange(resource, e.textSpan),
+                        contents: [e.contents]
+                    };
+                }
+            });
+    }
+}

+ 30 - 0
Script/AtomicWebViewEditor/clientExtensions/languageExtensions/typescript/workerprocess/TypescriptLanguageService.ts

@@ -182,6 +182,19 @@ export class TypescriptLanguageService {
         }
     }
 
+    /**
+     * returns a file previously registered
+     * @param  {string} filename
+     * @return {ts.SourceFile}
+     */
+    getSourceFile(filename: string): ts.SourceFile {
+        return this.documentRegistry.acquireDocument(
+            filename,
+            this.compilerOptions,
+            this.versionMap[filename].snapshot,
+            this.versionMap[filename].version.toString());
+    }
+
     /**
      * Updates the internal file version number
      * @param  {string} filename name of the file
@@ -274,6 +287,23 @@ export class TypescriptLanguageService {
         return this.languageService.getCompletionEntryDetails(filename, pos, entryname);
     }
 
+    /**
+     * Returns hover information about a position
+     * @param  {string} filename
+     * @param  {number} pos
+     */
+    getQuickInfoAtPosition(filename: string, pos: number) {
+        let results = this.languageService.getQuickInfoAtPosition(filename, pos);
+        if (results) {
+            return {
+                contents: ts.displayPartsToString(results.displayParts),
+                range: results.textSpan
+            };
+        } else {
+            return null;
+        }
+    }
+
     /**
      * Compile the provided file to javascript with full type checking etc
      * @param  {string}  a list of file names to compile

+ 21 - 5
Script/AtomicWebViewEditor/clientExtensions/languageExtensions/typescript/workerprocess/TypescriptLanguageServiceWebWorker.ts

@@ -214,6 +214,10 @@ export default class TypescriptLanguageServiceWebWorker {
                     case WorkerProcessTypes.MonacoResolveCompletionItem:
                         this.monacoHandleResolveCompletionItem(port, e.data);
                         break;
+
+                    case WorkerProcessTypes.MonacoGetQuickInfo:
+                        this.monacoGetQuickInfo(port, e.data);
+                        break;
                 }
             } catch (e) {
                 port.postMessage({ command: WorkerProcessTypes.Message, message: `Error in TypescriptLanguageServiceWebWorker: ${e}\n${e.stack}` });
@@ -406,6 +410,7 @@ export default class TypescriptLanguageServiceWebWorker {
         }
     }
 
+
     /**
      * Perform a full compile of the typescript
      * @param  {MessagePort} port
@@ -416,11 +421,6 @@ export default class TypescriptLanguageServiceWebWorker {
 
         this.fs.setCommunicationPort(port);
 
-        // update all the files
-        this.tsConfig.files.forEach(file => {
-            this.languageService.updateProjectFileVersionNumber(file);
-        });
-
         let results = [];
         let start = Date.now();
         this.languageService.compile([], (filename, errors) => {
@@ -524,6 +524,22 @@ export default class TypescriptLanguageServiceWebWorker {
         port.postMessage(message);
     }
 
+    monacoGetQuickInfo(port: MessagePort, eventData: WorkerProcessTypes.MonacoGetQuickInfoMessageData) {
+        let filename = this.resolvePartialFilename(eventData.uri);
+        let quickInfo = this.languageService.getQuickInfoAtPosition(filename, eventData.positionOffset);
+
+        let message: WorkerProcessTypes.MonacoGetQuickInfoResponseMessageData = {
+            command: WorkerProcessTypes.MonacoGetQuickInfoResponse,
+        };
+
+        if (quickInfo) {
+            message.contents = quickInfo.contents;
+            message.textSpan = quickInfo.range;
+        }
+
+        port.postMessage(message);
+    }
+
     /**
      * Called when a file has been deleted
      * @param  {MessagePort} port

+ 17 - 2
Script/AtomicWebViewEditor/clientExtensions/languageExtensions/typescript/workerprocess/workerProcessTypes.ts

@@ -28,7 +28,7 @@ export interface WorkerProcessMessageData {
     command: string;
 }
 
-export interface SaveMessageData extends WorkerProcessMessageData, Editor.EditorEvents.CodeSavedEvent {}
+export interface SaveMessageData extends WorkerProcessMessageData, Editor.EditorEvents.CodeSavedEvent { }
 
 export interface DeleteMessageData extends WorkerProcessMessageData, Editor.EditorEvents.DeleteResourceEvent { }
 export interface RenameMessageData extends WorkerProcessMessageData, Editor.EditorEvents.RenameResourceEvent { }
@@ -57,7 +57,6 @@ export interface GetCompletionsMessageData extends WorkerProcessMessageData {
     sourceText: string;
     filename: string;
     pos: { row: number, column: number };
-    prefix: string;
 }
 
 export interface GetCompletionsResponseMessageData extends WorkerProcessMessageData {
@@ -133,3 +132,19 @@ export interface MonacoResolveCompletionItemMessageData extends WorkerProcessMes
 }
 
 export interface MonacoResolveCompletionItemResponseMessageData extends WorkerProcessMessageData, monaco.languages.CompletionItem { }
+
+export const MonacoGetQuickInfo = "QUICK_INFO";
+export const MonacoGetQuickInfoResponse = "QUICK_INFO_RESPONSE";
+export interface MonacoGetQuickInfoMessageData extends WorkerProcessMessageData {
+    source: string;
+    uri: string;
+    positionOffset: number;
+}
+
+export interface MonacoGetQuickInfoResponseMessageData extends WorkerProcessMessageData {
+    contents?: string;
+    textSpan?: {
+        start: number,
+        length: number
+    };
+}