瀏覽代碼

Merge pull request #7616 from sailro/patch-1

Comment Monaco support in the Playground
David Catuhe 5 年之前
父節點
當前提交
e3c5a006b4
共有 2 個文件被更改,包括 51 次插入18 次删除
  1. 13 1
      Playground/js/definitionWorker.js
  2. 38 17
      Playground/js/monacoCreator.js

+ 13 - 1
Playground/js/definitionWorker.js

@@ -1,3 +1,14 @@
+// > This worker will analyze the syntaxtree and return an array of deprecated functions (but the goal is to do more in the future!)
+// We need to do this because:
+// - checking extended properties during completion is time consuming, so we need to prefilter potential candidates
+// - we don't want to maintain a static list of deprecated members or to instrument this work on the CI
+// - we have more plans involving syntaxtree analysis
+// > This worker was carefully crafted to work even if the processing is super fast or super long. 
+// In both cases the deprecation filter will start working after the worker is done.
+// We will also need this worker in the future to compute Intellicode scores for completion using dedicated attributes.
+
+// see monacoCreator.js/setupDefinitionWorker
+
 // monaco is using 'define' for module dependencies and service lookup.
 // hopefully typescript is self-contained
 var ts = null;
@@ -8,6 +19,7 @@ importScripts("../node_modules/monaco-editor/dev/vs/language/typescript/lib/type
 // store deprecated names
 var deprecatedCandidates = [];
 
+// optimize syntaxtree visitor, we don't care about non documented nodes
 function canHaveJsDoc(node) {
     const kind = node.kind;
     switch (kind) {
@@ -95,4 +107,4 @@ function processDefinition(code) {
 self.addEventListener('message', event => {
     const { code } = event.data;
     processDefinition(code);
-});
+});

+ 38 - 17
Playground/js/monacoCreator.js

@@ -1,5 +1,14 @@
 /**
  * This JS file is for Monaco management
+ * This file is quite technical, please make sure that you understand all parts before making changes.
+ * Please also make sure that the following is still working before submitting a PR:
+ * - autocompletion.
+ * - deprecated members marking.
+ * - compilation and proper error reporting for both JS and TS.
+ * - private/internal member filtering (we should not see members starting with an underscore).
+ * - dedicated adornments, like the one used for previewing colors for BABYLON.ColorX types.
+ * - diff support.
+ * - minimap support.
  */
 class MonacoCreator {
     constructor(parent) {
@@ -71,12 +80,17 @@ class MonacoCreator {
 
         this.setupDefinitionWorker(libContent);
 
+        // WARNING !!! We need the 'dev' version of Monaco, as we use monkey-patching to hook into the suggestion adapter
         require.config({ paths: { 'vs': '/node_modules/monaco-editor/dev/vs' } });
 
         require(['vs/editor/editor.main'], () => {
+            // Setup the Monaco compilation pipeline, so we can reuse it directly for our scrpting needs
             this.setupMonacoCompilationPipeline(libContent);
+            
+            // This is used for a vscode-like color preview for ColorX types
             this.setupMonacoColorProvider();
 
+            // As explained above, we need the 'dev' version of Monaco to access this adapter!
             require(['vs/language/typescript/languageFeatures'], module => {
                 this.hookMonacoCompletionProvider(module.SuggestAdapter);
             });
@@ -85,27 +99,21 @@ class MonacoCreator {
         });
     };
 
+    // > This worker will analyze the syntaxtree and return an array of deprecated functions (but the goal is to do more in the future!)
+    // We need to do this because:
+    // - checking extended properties during completion is time consuming, so we need to prefilter potential candidates
+    // - we don't want to maintain a static list of deprecated members or to instrument this work on the CI
+    // - we have more plans involving syntaxtree analysis
+    // > This worker was carefully crafted to work even if the processing is super fast or super long. 
+    // In both cases the deprecation filter will start working after the worker is done.
+    // We will also need this worker in the future to compute Intellicode scores for completion using dedicated attributes.
     setupDefinitionWorker(libContent) {
-
-        // This worker can be initialized differently.
-        // Its main job is to analyze the code and return an array of deprecated functions
         this.definitionWorker = new Worker('/js/definitionWorker.js');
         this.definitionWorker.addEventListener('message', ({ data }) => {
             this.deprecatedCandidates = data.result;
             this.analyzeCode();
         });
         this.definitionWorker.postMessage({ code: libContent });
-        // this.deprecatedCandidates = [
-        //     "FromFloatArray",
-        //     "FromFloatArrayToRef",
-        //     "getStrideSize",
-        //     "getStrideSize",
-        //     "getOffset",
-        //     "rgb",
-        //     "xy",
-        //     "xyz",
-        //     "fieldOfView"
-        //   ];
     }
 
     isDeprecatedEntry(details) {
@@ -119,8 +127,11 @@ class MonacoCreator {
             && tag.name == "deprecated";
     }
 
+    // This will make sure that all members marked with a deprecated jsdoc attribute will be marked as such in Monaco UI
+    // We use a prefiltered list of deprecated candidates, because the effective call to getCompletionEntryDetails is slow.
+    // @see setupDefinitionWorker
     async analyzeCode() {
-        // if the definition worker is very fast, this can be called out of context
+        // if the definition worker is very fast, this can be called out of context. @see setupDefinitionWorker
         if (!this.jsEditor)
             return;
 
@@ -154,6 +165,7 @@ class MonacoCreator {
                     continue;
 
                 // the following is time consuming on all suggestions, that's why we precompute deprecated candidate names in the definition worker to filter calls
+                // @see setupDefinitionWorker
                 const details = await languageService.getCompletionEntryDetails(uri.toString(), offset, wordInfo.word);
                 if (this.isDeprecatedEntry(details)) {
                     const deprecatedInfo = details.tags.find(this.isDeprecatedTag);
@@ -172,7 +184,10 @@ class MonacoCreator {
 
         monaco.editor.setModelMarkers(model, source, markers);
     }
-
+    
+    // This is our hook in the Monaco suggest adapter, we are called everytime a completion UI is displayed
+    // So we need to be super fast.
+    // We need the 'dev' version of Monaco, as we use monkey-patching to hook into this suggestion adapter
     hookMonacoCompletionProvider(provider) {
         const provideCompletionItems = provider.prototype.provideCompletionItems;
         const owner = this;
@@ -190,6 +205,7 @@ class MonacoCreator {
                 if (owner.deprecatedCandidates.includes(suggestion.label)) {
 
                     // the following is time consuming on all suggestions, that's why we precompute deprecated candidate names in the definition worker to filter calls
+                    // @see setupDefinitionWorker
                     const uri = suggestion.uri;
                     const worker = await this._worker(uri);
                     const model = monaco.editor.getModel(uri);
@@ -211,6 +227,7 @@ class MonacoCreator {
         }
     }
 
+    // Setup both JS and TS compilation pipelines to work with our scripts. 
     setupMonacoCompilationPipeline(libContent) {
         const typescript = monaco.languages.typescript;
 
@@ -240,6 +257,7 @@ class MonacoCreator {
         }
     }
 
+    // Provide an adornment for BABYLON.ColorX types: color preview
     setupMonacoColorProvider() {
         monaco.languages.registerColorProvider(this.monacoMode, {
             provideColorPresentations: (model, colorInfo) => {
@@ -317,6 +335,9 @@ class MonacoCreator {
         this.jsEditor = monaco.editor.create(document.getElementById('jsEditor'), editorOptions);
         this.jsEditor.setValue(oldCode);
 
+        // We cannot call 'analyzeCode' on every keystroke, that's time consuming
+        // So use a debounced version to prevent over processing.
+        // Be careful to keep the proper context for the effective call (this).
         const analyzeCodeDebounced = this.parent.utils.debounceAsync((async) => this.analyzeCode(), 500);
 
         this.jsEditor.onDidChangeModelContent(function () {
@@ -444,4 +465,4 @@ class MonacoCreator {
             return output + stub;
         }
     };
-};
+};