Browse Source

cleanup as well as implemented function parameter hints

Shaddock Heath 9 years ago
parent
commit
0162420901

+ 88 - 10
Script/AtomicWebViewEditor/clientExtensions/languageExtensions/typescript/TypescriptLanguageExtension.ts

@@ -141,6 +141,8 @@ export default class TypescriptLanguageExtension implements Editor.ClientExtensi
         if (this.isValidFiletype(ev.filename)) {
         if (this.isValidFiletype(ev.filename)) {
             this.active = true;
             this.active = true;
 
 
+            this.overrideBuiltinServiceProviders();
+
             // Hook in the routine to allow the host to perform a full compile
             // Hook in the routine to allow the host to perform a full compile
             this.serviceLocator.clientServices.getHostInterop().addCustomHostRoutine("TypeScript_DoFullCompile", this.doFullCompile.bind(this));
             this.serviceLocator.clientServices.getHostInterop().addCustomHostRoutine("TypeScript_DoFullCompile", this.doFullCompile.bind(this));
 
 
@@ -148,7 +150,6 @@ export default class TypescriptLanguageExtension implements Editor.ClientExtensi
 
 
             let editor = ev.editor as monaco.editor.IStandaloneCodeEditor;
             let editor = ev.editor as monaco.editor.IStandaloneCodeEditor;
             this.editor = editor; // cache this so that we can reference it later
             this.editor = editor; // cache this so that we can reference it later
-
             // Let's turn some things off in the editor.  These will be provided by the shared web worker
             // Let's turn some things off in the editor.  These will be provided by the shared web worker
             if (this.isJsFile(ev.filename)) {
             if (this.isJsFile(ev.filename)) {
                 monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
                 monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
@@ -167,7 +168,11 @@ export default class TypescriptLanguageExtension implements Editor.ClientExtensi
                 // Register editor feature providers
                 // Register editor feature providers
                 monaco.languages.registerCompletionItemProvider("javascript", new CustomCompletionProvider(this));
                 monaco.languages.registerCompletionItemProvider("javascript", new CustomCompletionProvider(this));
                 monaco.languages.registerHoverProvider("javascript", new CustomHoverProvider(this));
                 monaco.languages.registerHoverProvider("javascript", new CustomHoverProvider(this));
+                monaco.languages.registerSignatureHelpProvider("javascript", new CustomSignatureProvider(this));
             } else {
             } else {
+                monaco.languages.register({
+                    id: "atomic-ts"
+                });
                 monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
                 monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
                     noEmit: true,
                     noEmit: true,
                     noResolve: true,
                     noResolve: true,
@@ -182,11 +187,43 @@ export default class TypescriptLanguageExtension implements Editor.ClientExtensi
 
 
                 // Register editor feature providers
                 // Register editor feature providers
                 monaco.languages.registerCompletionItemProvider("typescript", new CustomCompletionProvider(this));
                 monaco.languages.registerCompletionItemProvider("typescript", new CustomCompletionProvider(this));
+                monaco.languages.registerSignatureHelpProvider("typescript", new CustomSignatureProvider(this));
                 monaco.languages.registerHoverProvider("typescript", new CustomHoverProvider(this));
                 monaco.languages.registerHoverProvider("typescript", new CustomHoverProvider(this));
             }
             }
         }
         }
     }
     }
 
 
+    /**
+     * Monkeypatch the TypeScript language provider so that our service providers get loaded
+     * and not the built-in ones.  Ours use a shared web worker so that state can be shared
+     * across tabs.
+     */
+    private overrideBuiltinServiceProviders() {
+        monaco.languages.registerSignatureHelpProvider = ((original) => {
+            return function(languageId: string, provider: monaco.languages.SignatureHelpProvider): monaco.IDisposable {
+                if (provider["isOverride"]) {
+                    return original(languageId, provider);
+                }
+            };
+        })(monaco.languages.registerSignatureHelpProvider);
+
+        monaco.languages.registerCompletionItemProvider = ((original) => {
+            return function(languageId: string, provider: monaco.languages.CompletionItemProvider): monaco.IDisposable {
+                if (provider["isOverride"]) {
+                    return original(languageId, provider);
+                }
+            };
+        })(monaco.languages.registerCompletionItemProvider);
+
+        monaco.languages.registerHoverProvider = ((original) => {
+            return function(languageId: string, provider: monaco.languages.HoverProvider): monaco.IDisposable {
+                if (provider["isOverride"]) {
+                    return original(languageId, provider);
+                }
+            };
+        })(monaco.languages.registerHoverProvider);
+    }
+
     /**
     /**
      * Called when code is first loaded into the editor
      * Called when code is first loaded into the editor
      * @param  {CodeLoadedEvent} ev
      * @param  {CodeLoadedEvent} ev
@@ -405,15 +442,29 @@ export default class TypescriptLanguageExtension implements Editor.ClientExtensi
     }
     }
 }
 }
 
 
+
 /**
 /**
- * Customized completion provider that will delegate to the shared web worker for it's completions
+ * Class used as a base for our custom providers to let the patched loader
+ * know to allow this through.
  */
  */
-class CustomCompletionProvider implements monaco.languages.CompletionItemProvider {
+class BuiltinServiceProviderOverride {
+
     constructor(extension: TypescriptLanguageExtension) {
     constructor(extension: TypescriptLanguageExtension) {
         this.extension = extension;
         this.extension = extension;
     }
     }
-    private extension: TypescriptLanguageExtension;
+    protected extension: TypescriptLanguageExtension;
+
+    /**
+     * Used to tell the loader that we want to load this extension.  Others will be skipped
+     * @type {Boolean}
+     */
+    public isOverride = true;
+}
 
 
+/**
+ * Customized completion provider that will delegate to the shared web worker for it's completions
+ */
+class CustomCompletionProvider extends BuiltinServiceProviderOverride implements monaco.languages.CompletionItemProvider {
     get triggerCharacters(): string[] {
     get triggerCharacters(): string[] {
         return ["."];
         return ["."];
     }
     }
@@ -432,6 +483,9 @@ class CustomCompletionProvider implements monaco.languages.CompletionItemProvide
                 return e.completions.map(completion => {
                 return e.completions.map(completion => {
                     completion.kind = tsLanguageSupport.Kind.convertKind(completion.completionKind);
                     completion.kind = tsLanguageSupport.Kind.convertKind(completion.completionKind);
                     return completion;
                     return completion;
+                }).filter(completion => {
+                    // Filter out built-in keywords since most of them don't apply to Atomic
+                    return completion.kind != monaco.languages.CompletionItemKind.Keyword;
                 });
                 });
             });
             });
     }
     }
@@ -449,12 +503,7 @@ class CustomCompletionProvider implements monaco.languages.CompletionItemProvide
     }
     }
 }
 }
 
 
-class CustomHoverProvider implements monaco.languages.HoverProvider {
-    constructor(extension: TypescriptLanguageExtension) {
-        this.extension = extension;
-    }
-    private extension: TypescriptLanguageExtension;
-
+class CustomHoverProvider extends BuiltinServiceProviderOverride implements monaco.languages.HoverProvider {
     protected _offsetToPosition(uri: monaco.Uri, offset: number): monaco.IPosition {
     protected _offsetToPosition(uri: monaco.Uri, offset: number): monaco.IPosition {
         let model = monaco.editor.getModel(uri);
         let model = monaco.editor.getModel(uri);
         return model.getPositionAt(offset);
         return model.getPositionAt(offset);
@@ -488,3 +537,32 @@ class CustomHoverProvider implements monaco.languages.HoverProvider {
             });
             });
     }
     }
 }
 }
+
+export class CustomSignatureProvider extends BuiltinServiceProviderOverride implements monaco.languages.SignatureHelpProvider {
+    public signatureHelpTriggerCharacters = ["(", ","];
+
+    provideSignatureHelp(model: monaco.editor.IReadOnlyModel, position: monaco.Position) {
+        let resource = model.uri;
+
+        const message: WorkerProcessTypes.MonacoGetSignatureMessageData = {
+            command: WorkerProcessTypes.MonacoGetSignature,
+            uri: this.extension.filename,
+            source: model.getValue(),
+            positionOffset: model.getOffsetAt(position)
+        };
+
+        return this.extension.workerRequest(WorkerProcessTypes.MonacoGetSignatureResponse, message)
+            .then((e: WorkerProcessTypes.MonacoGetSignatureMessageDataResponse) => {
+                if (e.signatures) {
+                    console.log(e);
+                    let result: monaco.languages.SignatureHelp = {
+                        signatures: e.signatures,
+                        activeSignature: e.selectedItemIndex,
+                        activeParameter: e.argumentIndex
+                    };
+
+                    return result;
+                }
+            });
+    }
+}

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

@@ -304,6 +304,24 @@ export class TypescriptLanguageService {
         }
         }
     }
     }
 
 
+    /**
+     * Returns information about the current element in a function signature
+     * @param  {string} filename
+     * @param  {number} pos
+     */
+    getSignatureHelpItems(filename: string, pos: number) {
+        let results = this.languageService.getSignatureHelpItems(filename, pos);
+        if (results) {
+            return {
+                selectedItemIndex: results.selectedItemIndex,
+                argumentIndex: results.argumentIndex,
+                items: results.items
+            };
+        } else {
+            return null;
+        }
+    }
+
     /**
     /**
      * Compile the provided file to javascript with full type checking etc
      * Compile the provided file to javascript with full type checking etc
      * @param  {string}  a list of file names to compile
      * @param  {string}  a list of file names to compile

+ 50 - 65
Script/AtomicWebViewEditor/clientExtensions/languageExtensions/typescript/workerprocess/TypescriptLanguageServiceWebWorker.ts

@@ -182,12 +182,6 @@ export default class TypescriptLanguageServiceWebWorker {
                     case WorkerProcessTypes.Disconnect:
                     case WorkerProcessTypes.Disconnect:
                         this.handleCLOSE(port, e.data);
                         this.handleCLOSE(port, e.data);
                         break;
                         break;
-                    case WorkerProcessTypes.GetCompletions:
-                        this.handleGetCompletions(port, e.data);
-                        break;
-                    case WorkerProcessTypes.GetDocTooltip:
-                        this.handleGetDocTooltip(port, e.data);
-                        break;
                     case ClientExtensionEventNames.CodeSavedEvent:
                     case ClientExtensionEventNames.CodeSavedEvent:
                         this.handleSave(port, e.data);
                         this.handleSave(port, e.data);
                         break;
                         break;
@@ -214,10 +208,12 @@ export default class TypescriptLanguageServiceWebWorker {
                     case WorkerProcessTypes.MonacoResolveCompletionItem:
                     case WorkerProcessTypes.MonacoResolveCompletionItem:
                         this.monacoHandleResolveCompletionItem(port, e.data);
                         this.monacoHandleResolveCompletionItem(port, e.data);
                         break;
                         break;
-
                     case WorkerProcessTypes.MonacoGetQuickInfo:
                     case WorkerProcessTypes.MonacoGetQuickInfo:
                         this.monacoGetQuickInfo(port, e.data);
                         this.monacoGetQuickInfo(port, e.data);
                         break;
                         break;
+                    case WorkerProcessTypes.MonacoGetSignature:
+                        this.monacoGetSignature(port, e.data);
+                        break;
                 }
                 }
             } catch (e) {
             } catch (e) {
                 port.postMessage({ command: WorkerProcessTypes.Message, message: `Error in TypescriptLanguageServiceWebWorker: ${e}\n${e.stack}` });
                 port.postMessage({ command: WorkerProcessTypes.Message, message: `Error in TypescriptLanguageServiceWebWorker: ${e}\n${e.stack}` });
@@ -321,66 +317,10 @@ export default class TypescriptLanguageServiceWebWorker {
     }
     }
 
 
     /**
     /**
-     * Get completions
+     * Get any errors or warnings
      * @param  {MessagePort} port
      * @param  {MessagePort} port
-     * @param  {WorkerProcessCommands.GetCompletionsMessage} eventData
+     * @param  {WorkerProcessTypes.GetAnnotationsMessageData} eventData
      */
      */
-    handleGetCompletions(port: MessagePort, eventData: WorkerProcessTypes.GetCompletionsMessageData) {
-        // filename may not include the entire path, so let"s find it in the tsconfig
-        let filename = this.resolvePartialFilename(eventData.filename);
-        let sourceFile = this.languageService.updateProjectFile(filename, eventData.sourceText);
-
-        let newpos = this.languageService.getPositionOfLineAndCharacter(sourceFile, eventData.pos.row, eventData.pos.column);
-        let completions = this.languageService.getCompletions(filename, newpos);
-
-        let message: WorkerProcessTypes.GetCompletionsResponseMessageData = {
-            command: WorkerProcessTypes.CompletionResponse,
-            completions: []
-        };
-
-        if (completions) {
-            message.completions = completions.entries.map((completion: ts.CompletionEntry) => {
-                let value = completion.name;
-                let completionItem: WorkerProcessTypes.WordCompletion = {
-                    caption: completion.name,
-                    value: value,
-                    score: 100 - parseInt(completion.sortText, 0),
-                    meta: completion.kind,
-                    pos: newpos
-                };
-
-                //completionItem.docTooltip = this.getDocTooltip(eventData.filename, newpos, completionItem);
-                return completionItem;
-            });
-        }
-
-        port.postMessage(message);
-    }
-
-    /**
-     * Get the documentation popup information for the current completion item
-     * @param  {MessagePort} port
-     * @param  {WorkerProcessCommands.GetDocTooltipMessageData} eventData
-     * @return {[type]}
-     */
-    handleGetDocTooltip(port: MessagePort, eventData: WorkerProcessTypes.GetDocTooltipMessageData) {
-        let message: WorkerProcessTypes.GetDocTooltipResponseMessageData = {
-            command: WorkerProcessTypes.DocTooltipResponse
-        };
-        let filename = this.resolvePartialFilename(eventData.filename);
-        const details = this.languageService.getCompletionEntryDetails(filename, eventData.pos, eventData.completionItem.caption);
-        if (details) {
-            let docs = details.displayParts.map(part => part.text).join("");
-            if (details.documentation) {
-                docs += "<p>" + details.documentation.map(part => part.text).join("") + "</p>";
-            }
-
-            message.docHTML = docs;
-        }
-
-        port.postMessage(message);
-    }
-
     handleGetAnnotations(port: MessagePort, eventData: WorkerProcessTypes.GetAnnotationsMessageData) {
     handleGetAnnotations(port: MessagePort, eventData: WorkerProcessTypes.GetAnnotationsMessageData) {
         let filename = this.resolvePartialFilename(eventData.filename);
         let filename = this.resolvePartialFilename(eventData.filename);
         this.languageService.updateProjectFile(filename, eventData.code);
         this.languageService.updateProjectFile(filename, eventData.code);
@@ -540,6 +480,51 @@ export default class TypescriptLanguageServiceWebWorker {
         port.postMessage(message);
         port.postMessage(message);
     }
     }
 
 
+    monacoGetSignature(port: MessagePort, eventData: WorkerProcessTypes.MonacoGetSignatureMessageData) {
+        let filename = this.resolvePartialFilename(eventData.uri);
+        let sourceFile = this.languageService.updateProjectFile(filename, eventData.source);
+        let signatureInfo = this.languageService.getSignatureHelpItems(filename, eventData.positionOffset);
+
+        let message: WorkerProcessTypes.MonacoGetSignatureMessageDataResponse = {
+            command: WorkerProcessTypes.MonacoGetSignatureResponse,
+        };
+
+        if (signatureInfo) {
+            message.selectedItemIndex = signatureInfo.selectedItemIndex;
+            message.argumentIndex = signatureInfo.argumentIndex;
+            message.signatures = [];
+
+            signatureInfo.items.forEach(item => {
+                let signature: monaco.languages.SignatureInformation = {
+                    label: "",
+                    documentation: null,
+                    parameters: []
+                };
+
+                signature.label += ts.displayPartsToString(item.prefixDisplayParts);
+
+                item.parameters.forEach((p, i, a) => {
+                    let label = ts.displayPartsToString(p.displayParts);
+                    let parameter: monaco.languages.ParameterInformation = {
+                        label: label,
+                        documentation: ts.displayPartsToString(p.documentation)
+                    };
+
+                    signature.label += label;
+                    signature.parameters.push(parameter);
+                    if (i < a.length - 1) {
+                        signature.label += ts.displayPartsToString(item.separatorDisplayParts);
+                    }
+                });
+
+                signature.label += ts.displayPartsToString(item.suffixDisplayParts);
+                message.signatures.push(signature);
+            });
+        }
+
+        port.postMessage(message);
+    }
+
     /**
     /**
      * Called when a file has been deleted
      * Called when a file has been deleted
      * @param  {MessagePort} port
      * @param  {MessagePort} port

+ 14 - 36
Script/AtomicWebViewEditor/clientExtensions/languageExtensions/typescript/workerprocess/workerProcessTypes.ts

@@ -40,42 +40,6 @@ export interface SetPreferencesMessageData extends WorkerProcessMessageData {
     };
     };
 }
 }
 
 
-export const GetCompletions = "COMPLETIONS";
-export const CompletionResponse = "COMPLETION_RESPONSE";
-export interface WordCompletion {
-    caption: string;
-    meta: string;
-    score: number;
-    value: string;
-    pos: number;
-    snippet?: string;
-    docHTML?: string;
-    docText?: string;
-}
-
-export interface GetCompletionsMessageData extends WorkerProcessMessageData {
-    sourceText: string;
-    filename: string;
-    pos: { row: number, column: number };
-}
-
-export interface GetCompletionsResponseMessageData extends WorkerProcessMessageData {
-    completions: Array<WordCompletion>;
-}
-
-export const GetDocTooltip = "DOC_TOOLTIP";
-export const DocTooltipResponse = "DOC_TOOLTIP_RESPONSE";
-export interface GetDocTooltipMessageData extends WorkerProcessMessageData {
-    completionItem: WordCompletion;
-    filename: string;
-    pos: number;
-}
-
-export interface GetDocTooltipResponseMessageData extends WorkerProcessMessageData {
-    docText?: string;
-    docHTML?: string;
-}
-
 export const GetAnnotations = "ANNOTATIONS";
 export const GetAnnotations = "ANNOTATIONS";
 export const AnnotationsUpdated = "ANNOTATIONS_RESPONSE";
 export const AnnotationsUpdated = "ANNOTATIONS_RESPONSE";
 export interface GetAnnotationsMessageData extends SaveMessageData { };
 export interface GetAnnotationsMessageData extends SaveMessageData { };
@@ -148,3 +112,17 @@ export interface MonacoGetQuickInfoResponseMessageData extends WorkerProcessMess
         length: number
         length: number
     };
     };
 }
 }
+
+export const MonacoGetSignature = "SIGNATURE";
+export const MonacoGetSignatureResponse = "SIGNATURE_RESPONSE";
+export interface MonacoGetSignatureMessageData extends WorkerProcessMessageData {
+    source: string;
+    uri: string;
+    positionOffset: number;
+}
+
+export interface MonacoGetSignatureMessageDataResponse extends WorkerProcessMessageData {
+    selectedItemIndex?: number;
+    argumentIndex?: number;
+    signatures?;
+}