فهرست منبع

Merge pull request #1451 from AtomicGameEngine/TSH-ATOMIC-TSFIXES

TypeScript and Extension fixes
JoshEngebretson 8 سال پیش
والد
کامیت
715823142c

+ 8 - 2
Script/AtomicEditor/hostExtensions/ServiceLocator.ts

@@ -71,9 +71,15 @@ export class ServiceLocatorType implements Editor.HostExtensions.HostServiceLoca
      * @param  {string} eventType
      * @param  {any} data
      */
-    sendEvent(eventType: string, data: any) {
+    sendEvent<T extends Atomic.EventCallbackMetaData>(eventCallbackMetaData:T)
+    sendEvent(eventType: string, data: any)
+    sendEvent(eventTypeOrMetaData: any, data?: any) {
         if (this.eventDispatcher) {
-            this.eventDispatcher.sendEvent(eventType, data);
+            if  (data) {
+                this.eventDispatcher.sendEvent(eventTypeOrMetaData, data);
+            } else {
+                this.eventDispatcher.sendEvent(eventTypeOrMetaData);
+            }
         }
     }
 

+ 7 - 4
Script/AtomicEditor/hostExtensions/coreExtensions/ProjectBasedExtensionLoader.ts

@@ -25,7 +25,7 @@
 /**
  * Resource extension that supports the web view typescript extension
  */
-export default class ProjectBasedExtensionLoader implements Editor.HostExtensions.ProjectServicesEventListener {
+export default class ProjectBasedExtensionLoader extends Atomic.ScriptObject implements Editor.HostExtensions.ProjectServicesEventListener {
     name: string = "ProjectBasedExtensionLoader";
     description: string = "This service supports loading extensions that reside in the project under {ProjectRoot}/Editor and named '*.Service.js'.";
 
@@ -112,9 +112,12 @@ export default class ProjectBasedExtensionLoader implements Editor.HostExtension
                         extensionPath = extensionPath.substring(0, extensionPath.length - 3);
 
                         console.log(`Detected project extension at: ${extensionPath} `);
-                        // Note: duktape does not yet support unloading modules,
-                        // but will return the same object when passed a path the second time.
-                        let resourceServiceModule = require(ProjectBasedExtensionLoader.duktapeRequirePrefix + extensionPath);
+                        const moduleName = ProjectBasedExtensionLoader.duktapeRequirePrefix + extensionPath;
+
+                        // Make sure that we delete the module from the module cache first so if there are any
+                        // changes, they get reflected
+                        delete Duktape.modLoaded[moduleName];
+                        let resourceServiceModule = require(moduleName);
 
                         // Handle situation where the service is either exposed by a typescript default export
                         // or as the module.export (depends on if it is being written in typescript, javascript, es6, etc.)

+ 3 - 6
Script/AtomicEditor/hostExtensions/languageExtensions/CSharpLanguageExtension.ts

@@ -25,7 +25,7 @@ import EditorUI = require("ui/EditorUI");
 /**
 * Resource extension that supports the web view typescript extension
 */
-export default class CSharpLanguageExtension implements Editor.HostExtensions.ResourceServicesEventListener, Editor.HostExtensions.ProjectServicesEventListener {
+export default class CSharpLanguageExtension extends Atomic.ScriptObject implements Editor.HostExtensions.ResourceServicesEventListener, Editor.HostExtensions.ProjectServicesEventListener {
     name: string = "HostCSharpLanguageExtension";
     description: string = "This service supports the csharp language.";
 
@@ -40,9 +40,6 @@ export default class CSharpLanguageExtension implements Editor.HostExtensions.Re
     /** Reference to the compileOnSaveMenuItem */
     private compileOnSaveMenuItem: Atomic.UIMenuItem;
 
-    //** A script object so we can take part in event handling
-    private eventObject = new Atomic.ScriptObject();
-
     /**
     * Determines if the file name/path provided is something we care about
     * @param  {string} path
@@ -161,7 +158,7 @@ export default class CSharpLanguageExtension implements Editor.HostExtensions.Re
             this.isNETProject = true;
             this.configureNETProjectMenu();
 
-            this.eventObject.subscribeToEvent(ToolCore.NETBuildResultEvent((eventData:ToolCore.NETBuildResultEvent) => {
+            this.subscribeToEvent(ToolCore.NETBuildResultEvent((eventData:ToolCore.NETBuildResultEvent) => {
 
                 if (!eventData.success) {
 
@@ -193,7 +190,7 @@ export default class CSharpLanguageExtension implements Editor.HostExtensions.Re
         this.serviceRegistry.uiServices.removePluginMenuItemSource("AtomicNET");
         this.menuCreated = false;
         this.isNETProject = false;
-        this.eventObject.unsubscribeFromAllEvents();
+        this.unsubscribeFromAllEvents();
     }
 
     /*** UIService implementation ***/

+ 51 - 7
Script/AtomicEditor/hostExtensions/languageExtensions/TypescriptLanguageExtension.ts

@@ -43,7 +43,7 @@ const defaultCompilerOptions = {
 /**
  * Resource extension that supports the web view typescript extension
  */
-export default class TypescriptLanguageExtension implements Editor.HostExtensions.ResourceServicesEventListener, Editor.HostExtensions.ProjectServicesEventListener {
+export default class TypescriptLanguageExtension extends Atomic.ScriptObject implements Editor.HostExtensions.ResourceServicesEventListener, Editor.HostExtensions.ProjectServicesEventListener {
     name: string = "HostTypeScriptLanguageExtension";
     description: string = "This service supports the typescript webview extension.";
 
@@ -77,6 +77,7 @@ export default class TypescriptLanguageExtension implements Editor.HostExtension
     private buildTsConfig(): any {
         // only build out a tsconfig.atomic if we actually have typescript files in the project
         let projectFiles: Array<string> = [];
+        let hasJsFiles = false;
         const slashedProjectPath = Atomic.addTrailingSlash(ToolCore.toolSystem.project.projectPath);
 
         //scan all the files in the project for any typescript files and add them to the project
@@ -101,7 +102,12 @@ export default class TypescriptLanguageExtension implements Editor.HostExtension
         let compilerOptions = defaultCompilerOptions;
         Atomic.fileSystem.scanDir(ToolCore.toolSystem.project.resourcePath, "*.js", Atomic.SCAN_FILES, true).forEach(filename => {
             let fn = Atomic.addTrailingSlash(ToolCore.toolSystem.project.resourcePath) + filename;
-            projectFiles.push(Atomic.addTrailingSlash(ToolCore.toolSystem.project.resourcePath) + filename);
+            // if the .js file matches up to a .ts file already loaded, then skip it
+            let tsfn = filename.replace(/\.js$/, ".ts");
+            if (projectFiles.indexOf(tsfn) == -1) {
+                hasJsFiles = true;
+                projectFiles.push(fn);
+            }
         });
 
         // First we need to load in a copy of the lib.es6.d.ts that is necessary for the hosted typescript compiler
@@ -157,6 +163,9 @@ export default class TypescriptLanguageExtension implements Editor.HostExtension
         // set the base url
         compilerOptions["baseUrl"] = ToolCore.toolSystem.project.resourcePath;
 
+        // enable JS files in the TS Compiler if we have js files
+        compilerOptions.allowJs = hasJsFiles;
+
         let tsConfig = {
             compilerOptions: compilerOptions,
             files: projectFiles
@@ -231,7 +240,7 @@ export default class TypescriptLanguageExtension implements Editor.HostExtension
                 };
 
                 this.setTsConfigOnWebView(this.buildTsConfig());
-                this.serviceRegistry.sendEvent<Editor.EditorDeleteResourceNotificationEvent>(Editor.EditorDeleteResourceNotificationEventType, eventData);
+                this.sendEvent(Editor.EditorDeleteResourceNotificationEventData(eventData));
             }
         }
     }
@@ -260,7 +269,7 @@ export default class TypescriptLanguageExtension implements Editor.HostExtension
                 };
 
                 this.setTsConfigOnWebView(this.buildTsConfig());
-                this.serviceRegistry.sendEvent<Editor.EditorRenameResourceNotificationEvent>(Editor.EditorRenameResourceNotificationEventType, eventData);
+                this.sendEvent(Editor.EditorRenameResourceNotificationEventData(eventData));
             }
         }
     }
@@ -305,6 +314,7 @@ export default class TypescriptLanguageExtension implements Editor.HostExtension
         this.compileOnSaveMenuItem = null;
         this.menuCreated = false;
         this.isTypescriptProject = false;
+        this.unsubscribeFromAllEvents();
     }
 
     /*** UIService implementation ***/
@@ -399,6 +409,12 @@ export default class TypescriptLanguageExtension implements Editor.HostExtension
     doFullCompile() {
         const editor = this.serviceRegistry.uiServices.getCurrentResourceEditor();
         if (editor && editor.typeName == "JSResourceEditor" && this.isValidFiletype(editor.fullPath)) {
+            this.sendEvent(Editor.EditorModalEventData({
+              type: Editor.EDITOR_MODALINFO,
+              title: "Compiling TypeScript",
+              message: "Compiling TypeScript..."
+            }));
+
             const jsEditor = <Editor.JSResourceEditor>editor;
             jsEditor.webView.webClient.executeJavaScript(`TypeScript_DoFullCompile('${JSON.stringify(this.buildTsConfig())}');`);
         } else {
@@ -444,6 +460,18 @@ export default class TypescriptLanguageExtension implements Editor.HostExtension
         let links = {};
         let linkId = 0;
 
+        // choose different colors based upon if we are in a dark theme or light theme
+        let successColor = "#00ff00";
+        let errorColor = "#e3e02b";
+        let infoColor = "#888888";
+        const currentSkin = this.serviceRegistry.projectServices.getApplicationPreference("uiData", "skinPath", "");
+        if (currentSkin.indexOf("light") != -1) {
+            successColor = "#006600";
+            errorColor = "#7f5f04";
+            infoColor = "#333333";
+        }
+
+        let errors = false;
         let messageArray = results.annotations.filter(result => {
             // If we are compiling the lib.d.ts or some other built-in library and it was successful, then
             // we really don't need to display that result since it's just noise.  Only display it if it fails
@@ -455,13 +483,14 @@ export default class TypescriptLanguageExtension implements Editor.HostExtension
 
             // Clean up the path for display
             let file = result.file.replace(ToolCore.toolSystem.project.projectPath, "");
-            let message = `<color #888888>${file}: </color>`;
+            let message = `<color ${infoColor}>${file}: </color>`;
             if (result.type == "success") {
-                message += `<color #00ff00>${result.text}</color>`;
+                message += `<color ${successColor}>${result.text}</color>`;
             } else {
-                message += `<color #e3e02b>${result.text} at line ${result.row + 1} col ${result.column}</color> <widget TBSkinImage: skin: MagnifierBitmap, text:"..." id: link${linkId}>`;
+                message += `<color ${errorColor}>${result.text} at line ${result.row + 1} col ${result.column}</color> <widget TBSkinImage: skin: MagnifierBitmap, text:"..." id: link${linkId}>`;
                 links["link" + linkId] = result;
                 linkId++;
+                errors = true;
             }
             return message;
         }).join("\n");
@@ -470,6 +499,20 @@ export default class TypescriptLanguageExtension implements Editor.HostExtension
             messageArray = "Success";
         }
 
+        if (errors) {
+            this.sendEvent(Editor.EditorModalEventData({
+              type: Editor.EDITOR_MODALINFO,
+              title: "Compiling TypeScript",
+              message: "Errors detected while compiling TypeScript."
+            }));
+        } else {
+            this.sendEvent(Editor.EditorModalEventData({
+              type: Editor.EDITOR_MODALINFO,
+              title: "Compiling TypeScript",
+              message: "Successfully compiled TypeScript."
+            }));
+        }
+
         let message = [
             "Compiler Options: ",
             JSON.stringify(results.compilerOptions, null, 2),
@@ -486,6 +529,7 @@ export default class TypescriptLanguageExtension implements Editor.HostExtension
                 } else {
                     let diag = links[ev.target.id];
                     if (diag) {
+                        console.log(`Load editor: ${diag.file}:${diag.row + 1}`);
                         this.serviceRegistry.uiServices.loadResourceEditor(diag.file, diag.row + 1);
                     }
                 }

+ 23 - 8
Script/AtomicEditor/ui/frames/ResourceFrame.ts

@@ -88,7 +88,7 @@ class ResourceFrame extends ScriptWidget {
 
         if (this.editors[path]) {
 
-            this.navigateToResource(path);
+            this.navigateToResource(path, ev.lineNumber);
 
             return;
 
@@ -117,7 +117,10 @@ class ResourceFrame extends ScriptWidget {
 
         var editor = this.editors[fullpath];
 
-        if (this.currentResourceEditor == editor) return;
+        if (this.currentResourceEditor == editor) {
+            this.setCursorPositionInEditor(editor, lineNumber, tokenPos);
+            return;
+        }
 
         var root = this.tabcontainer.contentRoot;
 
@@ -135,18 +138,30 @@ class ResourceFrame extends ScriptWidget {
 
             editor.setFocus();
 
-            // this cast could be better
-            var ext = Atomic.getExtension(fullpath);
+            this.setCursorPositionInEditor(editor, lineNumber, tokenPos);
+        }
+
+    }
 
-            if (ext == ".js" && lineNumber != -1) {
+    /**
+     * 
+     * Set the cursor to the correct line number in the editor
+     * @param {Editor.ResourceEditor} editor
+     * @param {any} [lineNumber=-1]
+     * @param {any} [tokenPos=-1]
+     * 
+     * @memberOf ResourceFrame
+     */
+    setCursorPositionInEditor(editor: Editor.ResourceEditor, lineNumber = -1, tokenPos = -1) {
+        if (editor instanceof Editor.JSResourceEditor) {
+            if (lineNumber != -1) {
                 (<Editor.JSResourceEditor>editor).gotoLineNumber(lineNumber);
             }
-            else if (ext == ".js" && tokenPos != -1) {
+
+            if (tokenPos != -1) {
                 (<Editor.JSResourceEditor>editor).gotoTokenPos(tokenPos);
             }
-
         }
-
     }
 
     handleCloseResource(ev: Editor.EditorResourceCloseEvent) {

+ 1 - 1
Script/AtomicEditor/ui/modal/UIResourceOps.ts

@@ -264,7 +264,7 @@ export class CreateScript extends ModalWindow {
 
                 if (selectedTemplate) {
                     // Check to see if we have a file extension.  If we don't then use the one defined in the template
-                    if (outputFile.indexOf(".") == -1) {
+                    if (outputFile.lastIndexOf(`.${selectedTemplate.ext}`) != outputFile.length - selectedTemplate.ext.length) {
                         outputFile += selectedTemplate.ext;
                     }
 

+ 15 - 2
Script/AtomicWebViewEditor/clientExtensions/ClientExtensionServices.ts

@@ -35,10 +35,23 @@ interface EventSubscription {
 export class EventDispatcher implements Editor.Extensions.EventDispatcher {
     private subscriptions: EventSubscription[] = [];
 
-    sendEvent(eventType: string, data: any) {
+    sendEvent<T extends Atomic.EventCallbackMetaData>(eventCallbackMetaData:T)
+    sendEvent(eventType: string, data: any)
+    sendEvent(eventTypeOrWrapped: any, data?: any) {
+        let eventType: string;
+        let eventData: any;
+        if (typeof(eventTypeOrWrapped) == "string") {
+            eventType = eventTypeOrWrapped;
+            eventData = data;
+        } else {
+            const metaData = eventTypeOrWrapped as Atomic.EventCallbackMetaData;
+            eventType = metaData._eventType;
+            eventData = metaData._callbackData;
+        }
+
         this.subscriptions.forEach(sub => {
             if (sub.eventName == eventType) {
-                sub.callback(data);
+                sub.callback(eventData);
             }
         });
     }

+ 8 - 2
Script/AtomicWebViewEditor/clientExtensions/ServiceLocator.ts

@@ -53,9 +53,15 @@ export class ClientServiceLocatorType implements Editor.ClientExtensions.ClientS
      * @param  {string} eventType
      * @param  {any} data
      */
-    sendEvent(eventType: string, data: any) {
+    sendEvent<T extends Atomic.EventCallbackMetaData>(eventCallbackMetaData:T)
+    sendEvent(eventType: string, data: any)
+    sendEvent(eventTypeOrWrapped: any, data?: any) {
         if (this.eventDispatcher) {
-            this.eventDispatcher.sendEvent(eventType, data);
+            if (data) {
+                this.eventDispatcher.sendEvent(eventTypeOrWrapped, data);
+            } else {
+                this.eventDispatcher.sendEvent(eventTypeOrWrapped);
+            }
         }
     }
 

+ 1 - 0
Script/TypeScript/EditorWork.d.ts

@@ -64,6 +64,7 @@ declare module Editor.Extensions {
          */
         sendEvent(eventType: string, data: any);
         sendEvent<T extends Atomic.EventMetaData>(eventType:string, data?:T);
+        sendEvent<T extends Atomic.EventCallbackMetaData>(eventCallbackMetaData:T);
 
         /**
          * Subscribe to an event and provide a callback.  This can be used by services to subscribe to custom events

+ 7 - 0
Script/TypeScript/duktape.d.ts

@@ -11,6 +11,13 @@ declare var console: Console;
 declare function require(filename: string): any;
 
 declare interface DuktapeModule {
+    /**
+     * List of modules that have been loaded via the "require" statement
+     * 
+     * @type {string[]}
+     * @memberOf DuktapeModule
+     */
+    modLoaded: string[];
     modSearch(id: string, require, exports, module);
 }