diff --git a/lib/main/atom/atomUtils.js b/lib/main/atom/atomUtils.js index dd34161fb..accf716fa 100644 --- a/lib/main/atom/atomUtils.js +++ b/lib/main/atom/atomUtils.js @@ -1,7 +1,6 @@ var path = require('path'); var fs = require('fs'); var tsconfig = require('../tsconfig/tsconfig'); -var _atom = require('atom'); function getEditorPosition(editor) { var bufferPos = editor.getCursorBufferPosition(); return getEditorPositionForBufferPosition(editor, bufferPos); @@ -53,7 +52,12 @@ function getRangeForTextSpan(editor, ts) { var buffer = editor.buffer; var start = editor.buffer.positionForCharacterIndex(ts.start); var end = editor.buffer.positionForCharacterIndex(ts.start + ts.length); - var range = new _atom.Range(start, end); + var atom = require('atom'); + var range = new atom.Range(start, end); return range; } exports.getRangeForTextSpan = getRangeForTextSpan; +function getTypeScriptEditorsWithPaths() { + return atom.workspace.getEditors().filter(function (editor) { return !!editor.getPath(); }).filter(function (editor) { return (path.extname(editor.getPath()) === '.ts'); }); +} +exports.getTypeScriptEditorsWithPaths = getTypeScriptEditorsWithPaths; diff --git a/lib/main/atom/atomUtils.ts b/lib/main/atom/atomUtils.ts index cad28044c..f59a1fa36 100644 --- a/lib/main/atom/atomUtils.ts +++ b/lib/main/atom/atomUtils.ts @@ -1,12 +1,9 @@ ///ts:ref=globals /// ///ts:ref:generated -///ts:import=languageServiceHost -import languageServiceHost = require('../lang/languageServiceHost'); ///ts:import:generated import path = require('path'); import fs = require('fs'); import tsconfig = require('../tsconfig/tsconfig'); -import _atom = require('atom'); // Optimized version where we do not ask this of the languageServiceHost export function getEditorPosition(editor: AtomCore.IEditor): number { @@ -67,6 +64,14 @@ export function getRangeForTextSpan(editor: AtomCore.IEditor, ts: { start: numbe var buffer = editor.buffer; var start = editor.buffer.positionForCharacterIndex(ts.start); var end = editor.buffer.positionForCharacterIndex(ts.start + ts.length); - var range = new _atom.Range(start, end); + var atom = require('atom'); + var range = new atom.Range(start, end); return range; } + +/** only the editors that are persisted to disk. And are of type TypeScript */ +export function getTypeScriptEditorsWithPaths() { + return atom.workspace.getEditors() + .filter(editor=> !!editor.getPath()) + .filter(editor=> (path.extname(editor.getPath()) === '.ts')); +} diff --git a/lib/main/atomts.js b/lib/main/atomts.js index 52d274497..166c3f095 100644 --- a/lib/main/atomts.js +++ b/lib/main/atomts.js @@ -39,7 +39,7 @@ function activate(state) { atom.workspace.onDidChangeActivePaneItem(function (editor) { if (atomUtils.onDiskAndTs(editor)) { var filePath = editor.getPath(); - parent.updateText({ text: editor.getText(), filePath: filePath }).then(function () { return parent.errorsForFile({ filePath: filePath }); }).then(function (resp) { return errorView.setErrors(filePath, resp.errors); }); + parent.errorsForFile({ filePath: filePath }).then(function (resp) { return errorView.setErrors(filePath, resp.errors); }); } }); editorWatch = atom.workspace.observeTextEditors(function (editor) { diff --git a/lib/main/atomts.ts b/lib/main/atomts.ts index 19e42e35c..24794b555 100644 --- a/lib/main/atomts.ts +++ b/lib/main/atomts.ts @@ -96,12 +96,11 @@ export function activate(state: PackageState) { atom.workspace.onDidChangeActivePaneItem((editor: AtomCore.IEditor) => { if (atomUtils.onDiskAndTs(editor)) { var filePath = editor.getPath(); - // We have an update text here as we are highly aggressive about - // * loading file system changes and invalidating our project cache - // * crashes in the worker - // best to reload stuff on change active tab - parent.updateText({ text: editor.getText(), filePath: filePath }) - .then(() => parent.errorsForFile({ filePath: filePath })) + + // Refresh errors stuff on change active tab. + // Because the fix might be in the other file + // or the other file might have made this file have an error + parent.errorsForFile({ filePath: filePath }) .then((resp) => errorView.setErrors(filePath, resp.errors)); } }); diff --git a/lib/main/lang/projectService.js b/lib/main/lang/projectService.js index cac6b76a6..647533a16 100644 --- a/lib/main/lang/projectService.js +++ b/lib/main/lang/projectService.js @@ -7,15 +7,23 @@ var project = require('./project'); var Project = project.Project; var resolve = Promise.resolve.bind(Promise); var queryParent = require('../../worker/queryParent'); -exports.child; -if (exports.child) { - queryParent.echoNumWithModification = exports.child.sendToIpc(queryParent.echoNumWithModification); +var child; +function fixChild(childInjected) { + child = childInjected; + queryParent.echoNumWithModification = child.sendToIpc(queryParent.echoNumWithModification); + queryParent.getUpdatedTextForUnsavedEditors = child.sendToIpc(queryParent.getUpdatedTextForUnsavedEditors); } +exports.fixChild = fixChild; var projectByProjectPath = {}; var projectByFilePath = {}; function cacheAndCreateProject(projectFile) { var project = projectByProjectPath[projectFile.projectFileDirectory] = new Project(projectFile); projectFile.project.files.forEach(function (file) { return projectByFilePath[file] = project; }); + queryParent.getUpdatedTextForUnsavedEditors({}).then(function (resp) { + resp.editors.forEach(function (e) { + project.languageServiceHost.updateScript(e.filePath, e.text); + }); + }); return project; } function getOrCreateProjectFile(filePath) { diff --git a/lib/main/lang/projectService.ts b/lib/main/lang/projectService.ts index a97695aba..22beac484 100644 --- a/lib/main/lang/projectService.ts +++ b/lib/main/lang/projectService.ts @@ -26,9 +26,11 @@ import queryParent = require('../../worker/queryParent'); // pushed in by child.ts // If we are in a child context we patch the functions to execute via IPC. // Otherwise we would call them directly. -export var child: workerLib.Child; -if (child) { - queryParent.echoNumWithModification = child.sendToIpc(queryParent.echoNumWithModification) +var child: workerLib.Child; +export function fixChild(childInjected: typeof child) { + child = childInjected; + queryParent.echoNumWithModification = child.sendToIpc(queryParent.echoNumWithModification); + queryParent.getUpdatedTextForUnsavedEditors = child.sendToIpc(queryParent.getUpdatedTextForUnsavedEditors); } //////////////////////////////////////////////////////////////////////////////////////// @@ -39,12 +41,22 @@ var projectByProjectPath: { [projectDir: string]: Project } = {} /** the project file path or any source ts file path */ var projectByFilePath: { [filePath: string]: Project } = {} -/** Warning: we are loading the project from file system. This might not match what we have in the editor memory - This is the reason why we aggresively send text to the worker on *Tab Change* and other places +/** We are loading the project from file system. + This might not match what we have in the editor memory, so query those as well */ function cacheAndCreateProject(projectFile: tsconfig.TypeScriptProjectFileDetails) { var project = projectByProjectPath[projectFile.projectFileDirectory] = new Project(projectFile); projectFile.project.files.forEach((file) => projectByFilePath[file] = project); + + // query the parent for unsaved changes + // We do this lazily + queryParent.getUpdatedTextForUnsavedEditors({}) + .then(resp=> { + resp.editors.forEach(e=> { + project.languageServiceHost.updateScript(e.filePath, e.text); + }); + }); + return project; } diff --git a/lib/worker/child.js b/lib/worker/child.js index b23982ff9..096d51628 100644 --- a/lib/worker/child.js +++ b/lib/worker/child.js @@ -2,4 +2,4 @@ var workerLib = require('./lib/workerLib'); var child = new workerLib.Child(); var projectService = require('../main/lang/projectService'); child.registerAllFunctionsExportedFromAsResponders(projectService); -projectService.child = child; +projectService.fixChild(child); diff --git a/lib/worker/child.ts b/lib/worker/child.ts index 9f5cc0dea..ef4f60016 100644 --- a/lib/worker/child.ts +++ b/lib/worker/child.ts @@ -14,4 +14,4 @@ import projectService = require('../main/lang/projectService'); child.registerAllFunctionsExportedFromAsResponders(projectService); // push in child -projectService.child = child; +projectService.fixChild(child); diff --git a/lib/worker/queryParent.js b/lib/worker/queryParent.js index 69fbcc7c4..eb3972bf8 100644 --- a/lib/worker/queryParent.js +++ b/lib/worker/queryParent.js @@ -1,4 +1,15 @@ +var resolve = Promise.resolve.bind(Promise); +var atomUtils = require('../main/atom/atomUtils'); function echoNumWithModification(query) { return Promise.resolve({ num: query.num + 10 }); } exports.echoNumWithModification = echoNumWithModification; +function getUpdatedTextForUnsavedEditors(query) { + var editors = atomUtils.getTypeScriptEditorsWithPaths().filter(function (editor) { return editor.isModified(); }); + return resolve({ + editors: editors.map(function (e) { + return { filePath: e.getPath(), text: e.getText() }; + }) + }); +} +exports.getUpdatedTextForUnsavedEditors = getUpdatedTextForUnsavedEditors; diff --git a/lib/worker/queryParent.ts b/lib/worker/queryParent.ts index 34e65c157..4a248b1fc 100644 --- a/lib/worker/queryParent.ts +++ b/lib/worker/queryParent.ts @@ -1,5 +1,19 @@ /// Functions that the parent allows the child to query +var resolve: typeof Promise.resolve = Promise.resolve.bind(Promise); + +///ts:import=atomUtils +import atomUtils = require('../main/atom/atomUtils'); ///ts:import:generated + export function echoNumWithModification(query: { num: number }): Promise<{ num: number }> { return Promise.resolve({ num: query.num + 10 }); } + +export function getUpdatedTextForUnsavedEditors(query: {}): Promise<{ editors: { filePath: string; text: string }[] }> { + var editors = atomUtils.getTypeScriptEditorsWithPaths().filter(editor => editor.isModified()); + return resolve({ + editors: editors.map(e=> { + return { filePath: e.getPath(), text: e.getText() } + }) + }); +}