From 5a1132ec0b8679e476ff23eb04a0f136653537af Mon Sep 17 00:00:00 2001 From: Denis Malinochkin Date: Tue, 27 Sep 2016 13:02:38 +0300 Subject: [PATCH 001/163] Order properties by docs --- .../extensions/common/extensionsRegistry.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/vs/platform/extensions/common/extensionsRegistry.ts b/src/vs/platform/extensions/common/extensionsRegistry.ts index cdaf27c2c70..130386a658a 100644 --- a/src/vs/platform/extensions/common/extensionsRegistry.ts +++ b/src/vs/platform/extensions/common/extensionsRegistry.ts @@ -214,6 +214,10 @@ const schema: IJSONSchema = { // } // } // }, + publisher: { + description: nls.localize('vscode.extension.publisher', 'The publisher of the VS Code extension.'), + type: 'string' + }, displayName: { description: nls.localize('vscode.extension.displayName', 'The display name for the extension used in the VS Code gallery.'), type: 'string' @@ -241,9 +245,13 @@ const schema: IJSONSchema = { } } }, - publisher: { - description: nls.localize('vscode.extension.publisher', 'The publisher of the VS Code extension.'), - type: 'string' + contributes: { + description: nls.localize('vscode.extension.contributes', 'All contributions of the VS Code extension represented by this package.'), + type: 'object', + properties: { + // extensions will fill in + }, + default: {} }, activationEvents: { description: nls.localize('vscode.extension.activationEvents', 'Activation events for the VS Code extension.'), @@ -268,14 +276,6 @@ const schema: IJSONSchema = { type: 'string' } } - }, - contributes: { - description: nls.localize('vscode.extension.contributes', 'All contributions of the VS Code extension represented by this package.'), - type: 'object', - properties: { - // extensions will fill in - }, - default: {} } } }; From 0dcbee09aa9b7e45aa650f2a7c258e9c63431d84 Mon Sep 17 00:00:00 2001 From: Denis Malinochkin Date: Tue, 27 Sep 2016 13:02:57 +0300 Subject: [PATCH 002/163] Add `icon` property --- src/vs/platform/extensions/common/extensionsRegistry.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/platform/extensions/common/extensionsRegistry.ts b/src/vs/platform/extensions/common/extensionsRegistry.ts index 130386a658a..a9149b48f0c 100644 --- a/src/vs/platform/extensions/common/extensionsRegistry.ts +++ b/src/vs/platform/extensions/common/extensionsRegistry.ts @@ -276,6 +276,10 @@ const schema: IJSONSchema = { type: 'string' } } + }, + icon: { + type: 'string', + description: nls.localize('vscode.extension.icon', 'The path to a 128x128 pixel icon.') } } }; From dfde133e23b01be42582c2ef34fa8303811a34ea Mon Sep 17 00:00:00 2001 From: Denis Malinochkin Date: Tue, 27 Sep 2016 13:03:17 +0300 Subject: [PATCH 003/163] Add `badges` property --- .../extensions/common/extensionsRegistry.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/vs/platform/extensions/common/extensionsRegistry.ts b/src/vs/platform/extensions/common/extensionsRegistry.ts index a9149b48f0c..1e4f9b02d49 100644 --- a/src/vs/platform/extensions/common/extensionsRegistry.ts +++ b/src/vs/platform/extensions/common/extensionsRegistry.ts @@ -261,6 +261,28 @@ const schema: IJSONSchema = { defaultSnippets: [{ label: 'onLanguage', body: 'onLanguage:{{languageId}}'}, {label: 'onCommand', body: 'onCommand:{{commandId}}'}, {label: 'onDebug', body: 'onDebug:{{type}}'}, {label: 'workspaceContains', body: 'workspaceContains:{{fileName}}'}], } }, + badges: { + type: 'array', + description: nls.localize('vscode.extension.badges', 'Array of badges to display in the sidebar of the Marketplace\'s extension page.'), + items: { + type: 'object', + required: ['url', 'href', 'description'], + properties: { + url: { + type: 'string', + description: nls.localize('vscode.extension.badges.url', 'Badge image URL.') + }, + href: { + type: 'string', + description: nls.localize('vscode.extension.badges.href', 'Badge link.') + }, + description: { + type: 'string', + description: nls.localize('vscode.extension.badges.description', 'Badge description.') + } + } + } + }, extensionDependencies: { description: nls.localize('vscode.extension.extensionDependencies', 'Dependencies to other extensions. The identifier of an extension is always ${publisher}.${name}. For example: vscode.csharp.'), type: 'array', From 2c123f3c61b0b45dc25e11d366d5f5a43e4219dc Mon Sep 17 00:00:00 2001 From: Denis Malinochkin Date: Tue, 27 Sep 2016 13:03:40 +0300 Subject: [PATCH 004/163] Add `preview` property --- src/vs/platform/extensions/common/extensionsRegistry.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/platform/extensions/common/extensionsRegistry.ts b/src/vs/platform/extensions/common/extensionsRegistry.ts index 1e4f9b02d49..8cd2423b2e0 100644 --- a/src/vs/platform/extensions/common/extensionsRegistry.ts +++ b/src/vs/platform/extensions/common/extensionsRegistry.ts @@ -253,6 +253,10 @@ const schema: IJSONSchema = { }, default: {} }, + preview: { + type: 'boolean', + description: nls.localize('vscode.extension.preview', 'Sets the extension to be flagged as a Preview in the Marketplace.'), + }, activationEvents: { description: nls.localize('vscode.extension.activationEvents', 'Activation events for the VS Code extension.'), type: 'array', From 08507ca3e5b2ed6ada840723da64b7bef1730068 Mon Sep 17 00:00:00 2001 From: Denis Malinochkin Date: Tue, 27 Sep 2016 13:06:17 +0300 Subject: [PATCH 005/163] Add `uniqueItems` rule for simple arrays --- src/vs/platform/extensions/common/extensionsRegistry.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/platform/extensions/common/extensionsRegistry.ts b/src/vs/platform/extensions/common/extensionsRegistry.ts index 8cd2423b2e0..1f780050db4 100644 --- a/src/vs/platform/extensions/common/extensionsRegistry.ts +++ b/src/vs/platform/extensions/common/extensionsRegistry.ts @@ -225,6 +225,7 @@ const schema: IJSONSchema = { categories: { description: nls.localize('vscode.extension.categories', 'The categories used by the VS Code gallery to categorize the extension.'), type: 'array', + uniqueItems: true, items: { type: 'string', enum: ['Languages', 'Snippets', 'Linters', 'Themes', 'Debuggers', 'Productivity', 'Other'] @@ -290,6 +291,7 @@ const schema: IJSONSchema = { extensionDependencies: { description: nls.localize('vscode.extension.extensionDependencies', 'Dependencies to other extensions. The identifier of an extension is always ${publisher}.${name}. For example: vscode.csharp.'), type: 'array', + uniqueItems: true, items: { type: 'string' } From 2b564896915073ae1311fab8df190f62526c6733 Mon Sep 17 00:00:00 2001 From: kieferrm Date: Wed, 28 Sep 2016 18:27:17 -0700 Subject: [PATCH 006/163] scrolling issue #12562 --- src/vs/workbench/parts/html/browser/htmlPreviewPart.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/html/browser/htmlPreviewPart.ts b/src/vs/workbench/parts/html/browser/htmlPreviewPart.ts index ae80329ef48..93aef5db654 100644 --- a/src/vs/workbench/parts/html/browser/htmlPreviewPart.ts +++ b/src/vs/workbench/parts/html/browser/htmlPreviewPart.ts @@ -149,7 +149,8 @@ export class HtmlPreviewPart extends BaseEditor { } return super.setInput(input, options).then(() => { - return this._editorService.resolveEditorModel({ resource: (input).getResource() }).then(model => { + let resourceUri = (input).getResource(); + return this._editorService.resolveEditorModel({ resource: resourceUri }).then(model => { if (model instanceof BaseTextEditorModel) { this._model = model.textEditorModel; } @@ -157,6 +158,7 @@ export class HtmlPreviewPart extends BaseEditor { return TPromise.wrapError(localize('html.voidInput', "Invalid editor input.")); } this._modelChangeSubscription = this._model.onDidChangeContent(() => this.webview.contents = this._model.getLinesContent()); + this.webview.baseUrl = resourceUri.toString(true); this.webview.contents = this._model.getLinesContent(); }); }); From 7a8e03c676a72c9516d8c39b6c0c9fa836194c72 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 3 Oct 2016 16:46:39 +0200 Subject: [PATCH 007/163] responsive suggest icons fixes #12029 related to #12859 --- .../contrib/suggest/browser/Class_16x.svg | 1 + .../suggest/browser/Class_inverse_16x.svg | 1 + .../suggest/browser/ColorPalette_16x.svg | 1 + .../browser/ColorPalette_inverse_16x.svg | 1 + .../contrib/suggest/browser/Document_16x.svg | 1 + .../suggest/browser/Document_inverse_16x.svg | 1 + .../contrib/suggest/browser/EnumItem_16x.svg | 1 + .../suggest/browser/EnumItem_inverse_16x.svg | 1 + .../suggest/browser/Enumerator_16x.svg | 1 + .../browser/Enumerator_inverse_16x.svg | 1 + .../contrib/suggest/browser/Field_16x.svg | 1 + .../suggest/browser/Field_inverse_16x.svg | 1 + .../contrib/suggest/browser/Indexer_16x.svg | 1 + .../suggest/browser/Indexer_inverse_16x.svg | 1 + .../browser/IntelliSenseKeyword_16x.svg | 1 + .../IntelliSenseKeyword_inverse_16x.svg | 1 + .../contrib/suggest/browser/Interface_16x.svg | 1 + .../suggest/browser/Interface_inverse_16x.svg | 1 + .../suggest/browser/LineIndent_16x.svg | 1 + .../browser/LineIndent_inverse_16x.svg | 1 + .../contrib/suggest/browser/Method_16x.svg | 1 + .../suggest/browser/Method_inverse_16x.svg | 1 + .../contrib/suggest/browser/Misc_16x.svg | 1 + .../suggest/browser/Misc_inverse_16x.svg | 1 + .../contrib/suggest/browser/Namespace_16x.svg | 1 + .../suggest/browser/Namespace_inverse_16x.svg | 1 + .../contrib/suggest/browser/Property_16x.svg | 1 + .../suggest/browser/Property_inverse_16x.svg | 1 + .../contrib/suggest/browser/Ruler_16x.svg | 1 + .../suggest/browser/Ruler_inverse_16x.svg | 1 + .../contrib/suggest/browser/Snippet_16x.svg | 47 +++++ .../suggest/browser/Snippet_inverse_16x.svg | 43 +++++ .../contrib/suggest/browser/String_16x.svg | 1 + .../suggest/browser/String_inverse_16x.svg | 1 + .../contrib/suggest/browser/Toggle_16x.svg | 1 + .../suggest/browser/Toggle_inverse_16x.svg | 1 + .../contrib/suggest/browser/suggest.css | 170 ++++++------------ .../contrib/suggest/browser/suggestWidget.ts | 4 + .../contrib/suggest/browser/symbol-sprite.svg | 1 - 39 files changed, 185 insertions(+), 114 deletions(-) create mode 100755 src/vs/editor/contrib/suggest/browser/Class_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Class_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/ColorPalette_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/ColorPalette_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Document_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Document_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/EnumItem_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/EnumItem_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Enumerator_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Enumerator_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Field_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Field_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Indexer_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Indexer_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/IntelliSenseKeyword_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/IntelliSenseKeyword_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Interface_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Interface_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/LineIndent_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/LineIndent_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Method_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Method_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Misc_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Misc_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Namespace_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Namespace_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Property_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Property_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Ruler_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Ruler_inverse_16x.svg create mode 100644 src/vs/editor/contrib/suggest/browser/Snippet_16x.svg create mode 100644 src/vs/editor/contrib/suggest/browser/Snippet_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/String_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/String_inverse_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Toggle_16x.svg create mode 100755 src/vs/editor/contrib/suggest/browser/Toggle_inverse_16x.svg delete mode 100644 src/vs/editor/contrib/suggest/browser/symbol-sprite.svg diff --git a/src/vs/editor/contrib/suggest/browser/Class_16x.svg b/src/vs/editor/contrib/suggest/browser/Class_16x.svg new file mode 100755 index 00000000000..5ef1c6f80bc --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Class_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Class_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Class_inverse_16x.svg new file mode 100755 index 00000000000..c43aad29efd --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Class_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/ColorPalette_16x.svg b/src/vs/editor/contrib/suggest/browser/ColorPalette_16x.svg new file mode 100755 index 00000000000..2af5cc6faef --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/ColorPalette_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/ColorPalette_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/ColorPalette_inverse_16x.svg new file mode 100755 index 00000000000..7afb32b895e --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/ColorPalette_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Document_16x.svg b/src/vs/editor/contrib/suggest/browser/Document_16x.svg new file mode 100755 index 00000000000..13ded2953eb --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Document_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Document_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Document_inverse_16x.svg new file mode 100755 index 00000000000..949a376216a --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Document_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/EnumItem_16x.svg b/src/vs/editor/contrib/suggest/browser/EnumItem_16x.svg new file mode 100755 index 00000000000..aa901ec1934 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/EnumItem_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/EnumItem_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/EnumItem_inverse_16x.svg new file mode 100755 index 00000000000..791759092fc --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/EnumItem_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Enumerator_16x.svg b/src/vs/editor/contrib/suggest/browser/Enumerator_16x.svg new file mode 100755 index 00000000000..e4a9551fd5a --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Enumerator_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Enumerator_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Enumerator_inverse_16x.svg new file mode 100755 index 00000000000..d8e9f4f107a --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Enumerator_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Field_16x.svg b/src/vs/editor/contrib/suggest/browser/Field_16x.svg new file mode 100755 index 00000000000..c6cb5362b3b --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Field_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Field_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Field_inverse_16x.svg new file mode 100755 index 00000000000..5fc48ceff0f --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Field_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Indexer_16x.svg b/src/vs/editor/contrib/suggest/browser/Indexer_16x.svg new file mode 100755 index 00000000000..028f55771cc --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Indexer_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Indexer_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Indexer_inverse_16x.svg new file mode 100755 index 00000000000..37a29ad4a88 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Indexer_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/IntelliSenseKeyword_16x.svg b/src/vs/editor/contrib/suggest/browser/IntelliSenseKeyword_16x.svg new file mode 100755 index 00000000000..4a69c4a038b --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/IntelliSenseKeyword_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/IntelliSenseKeyword_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/IntelliSenseKeyword_inverse_16x.svg new file mode 100755 index 00000000000..decbf2c403e --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/IntelliSenseKeyword_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Interface_16x.svg b/src/vs/editor/contrib/suggest/browser/Interface_16x.svg new file mode 100755 index 00000000000..958a792742a --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Interface_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Interface_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Interface_inverse_16x.svg new file mode 100755 index 00000000000..f7c2934a55c --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Interface_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/LineIndent_16x.svg b/src/vs/editor/contrib/suggest/browser/LineIndent_16x.svg new file mode 100755 index 00000000000..6c15351f14f --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/LineIndent_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/LineIndent_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/LineIndent_inverse_16x.svg new file mode 100755 index 00000000000..c1d45b45ebf --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/LineIndent_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Method_16x.svg b/src/vs/editor/contrib/suggest/browser/Method_16x.svg new file mode 100755 index 00000000000..2be9daa5f5d --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Method_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Method_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Method_inverse_16x.svg new file mode 100755 index 00000000000..d3c2c571d98 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Method_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Misc_16x.svg b/src/vs/editor/contrib/suggest/browser/Misc_16x.svg new file mode 100755 index 00000000000..13ff00b2347 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Misc_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Misc_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Misc_inverse_16x.svg new file mode 100755 index 00000000000..50a038657b2 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Misc_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Namespace_16x.svg b/src/vs/editor/contrib/suggest/browser/Namespace_16x.svg new file mode 100755 index 00000000000..dab07dd5ad9 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Namespace_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Namespace_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Namespace_inverse_16x.svg new file mode 100755 index 00000000000..9b9a44c52d2 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Namespace_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Property_16x.svg b/src/vs/editor/contrib/suggest/browser/Property_16x.svg new file mode 100755 index 00000000000..fb1c74cf773 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Property_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Property_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Property_inverse_16x.svg new file mode 100755 index 00000000000..f90781897a7 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Property_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Ruler_16x.svg b/src/vs/editor/contrib/suggest/browser/Ruler_16x.svg new file mode 100755 index 00000000000..2e8e88fef0d --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Ruler_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Ruler_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Ruler_inverse_16x.svg new file mode 100755 index 00000000000..373ab812f92 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Ruler_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Snippet_16x.svg b/src/vs/editor/contrib/suggest/browser/Snippet_16x.svg new file mode 100644 index 00000000000..8bf3b9f67d6 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Snippet_16x.svg @@ -0,0 +1,47 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/vs/editor/contrib/suggest/browser/Snippet_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Snippet_inverse_16x.svg new file mode 100644 index 00000000000..501ff9c6177 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Snippet_inverse_16x.svg @@ -0,0 +1,43 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/vs/editor/contrib/suggest/browser/String_16x.svg b/src/vs/editor/contrib/suggest/browser/String_16x.svg new file mode 100755 index 00000000000..35e744ce90d --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/String_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/String_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/String_inverse_16x.svg new file mode 100755 index 00000000000..1ac0cf99ac8 --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/String_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Toggle_16x.svg b/src/vs/editor/contrib/suggest/browser/Toggle_16x.svg new file mode 100755 index 00000000000..7a1d3f1335e --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Toggle_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/Toggle_inverse_16x.svg b/src/vs/editor/contrib/suggest/browser/Toggle_inverse_16x.svg new file mode 100755 index 00000000000..fbc83f8879f --- /dev/null +++ b/src/vs/editor/contrib/suggest/browser/Toggle_inverse_16x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/suggest.css b/src/vs/editor/contrib/suggest/browser/suggest.css index ceb91b4db3c..b1a643799ed 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.css +++ b/src/vs/editor/contrib/suggest/browser/suggest.css @@ -33,16 +33,20 @@ } .monaco-editor .suggest-widget .monaco-list .monaco-list-row { + display: flex; -mox-box-sizing: border-box; box-sizing: border-box; - padding: 0 10px 0 22px; + padding-right: 10px; background-repeat: no-repeat; background-position: 2px 2px; white-space: nowrap; } .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .text { + flex: 1; height: 100%; + overflow: hidden; + padding-left: 2px; } .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .text > .main { @@ -115,35 +119,33 @@ } .monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon { - position: absolute; display: block; - left: 1px; - top: 2px; - background-image: url('symbol-sprite.svg'); - background-repeat: no-repeat; height: 16px; width: 16px; + background-repeat: no-repeat; + background-size: 80%; + background-position: center; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon { background-position: -361px -3px; } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon { background-image: url('Misc_16x.svg'); } .monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.method, .monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.function, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.constructor { background-position: 1px -3px; } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.constructor { background-image: url('Method_16x.svg'); } .monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.field, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.variable { background-position: -19px -2px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.class { background-position: -41px -3px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.interface { background-position: -62px -2px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.module { background-position: -79px -4px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.property { background-position: -100px -3px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.unit { background-position: -120px -4px; } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.variable { background-image: url('Field_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.class { background-image: url('Class_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.interface { background-image: url('Interface_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.module { background-image: url('Namespace_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.property { background-image: url('Property_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.unit { background-image: url('Ruler_16x.svg'); } .monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.value, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.enum { background-position: -140px -3px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.keyword { background-position: -162px -2px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.snippet { background-position: -181px -4px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.text { background-position: -201px -2px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.color { background-position: -221px -4px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.file { background-position: -260px -2px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.reference { background-position: -281px -4px; } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.enum { background-image: url('EnumItem_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.keyword { background-image: url('IntelliSenseKeyword_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.text { background-image: url('String_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.color { background-image: url('ColorPalette_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.file { background-image: url('Document_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.reference { background-image: url('Enumerator_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.snippet { background-image: url('Snippet_16x.svg'); } .monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.customcolor { background-image: none; @@ -236,28 +238,25 @@ color: #4E94CE; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon { background-position: -361px -23px; } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon { background-image: url('Misc_inverse_16x.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.method, .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.function, -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.constructor { background-position: 2px -23px; } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.constructor { background-image: url('Method_inverse_16x.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.field, -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.variable { background-position: -18px -23px; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.class { background-position: -41px -23px; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.interface { background-position: -61px -24px; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.module { background-position: -79px -24px; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.property { background-position: -100px -23px; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.unit { background-position: -120px -24px; } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.variable { background-image: url('Field_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.class { background-image: url('Class_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.interface { background-image: url('Interface_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.module { background-image: url('Namespace_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.property { background-image: url('Property_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.unit { background-image: url('Ruler_inverse_16x.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.value, -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.enum { background-position: -140px -23px; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.keyword { background-position: -161px -22px; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.snippet { background-position: -181px -23px; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.text { background-position: -201px -22px; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.color { background-position: -221px -24px; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.file { background-position: -260px -22px; } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.reference { background-position: -281px -24px; } - - - +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.enum { background-image: url('EnumItem_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.keyword { background-image: url('IntelliSenseKeyword_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.text { background-image: url('String_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.color { background-image: url('ColorPalette_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.file { background-image: url('Document_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.reference { background-image: url('Enumerator_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .icon.snippet { background-image: url('Snippet_inverse_16x.svg'); } /* High Contrast Theming */ .monaco-editor.hc-black .suggest-widget { @@ -279,77 +278,22 @@ color: #4E94CE; } -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon { - background: none; - overflow: hidden; -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon:before { - height: 16px; - width: 16px; - display: inline-block; - content: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyIDIpIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0xIDB2OC44bC0xIDEuNlYxMmg4di0xaDRWMEgxeiIgaWQ9IlNoYXBlIiBmaWxsPSIjMkQyRDMwIi8+PHBhdGggZD0iTTEgMTFsMy01IDMgNUgxem01LjA4Mi0zLjY3QzYuMzg4IDYgNy41NzcgNSA5IDVjLjc3IDAgMS40NjguMyAyIC43OFYxSDJ2Ni4yTDQgNGwyLjA4MiAzLjMzeiIgZmlsbD0iI0M1QzVDNSIvPjxjaXJjbGUgZmlsbD0iI0M1QzVDNSIgY3g9IjguOTM4IiBjeT0iOCIgcj0iMi4wNjMiLz48L2c+PC9zdmc+"); -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.method:before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.function:before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.constructor:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI0IxODBENyIgZD0iTTUuNSAzbC00LjUgMi44NTd2NC4yODVsNC41IDIuODU4IDQuNS0yLjg1N3YtNC4yODZsLTQuNS0yLjg1N3ptLS41IDguNDk4bC0zLTEuOTA1di0yLjgxNmwzIDEuOTA1djIuODE2em0tMi4zNTgtNS40OThsMi44NTgtMS44MTUgMi44NTggMS44MTUtMi44NTggMS44MTUtMi44NTgtMS44MTV6bTYuMzU4IDMuNTkzbC0zIDEuOTA1di0yLjgxNWwzLTEuOTA1djIuODE1eiIvPjwvc3ZnPg=="); - margin-left: 2px; -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.field:before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.variable:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iIzc1QkVGRiIgZD0iTTEgNnY0bDQgMiA2LTN2LTRsLTQtMi02IDN6bTQgMWwtMi0xIDQtMiAyIDEtNCAyeiIvPjwvc3ZnPg=="); - margin-left: 2px; -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.class:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBvbHlnb24gZmlsbD0iI0U4QUI1MyIgcG9pbnRzPSIxMS45OTgsMTEuMDAyIDksMTEgOSw3IDExLDcgMTAsOCAxMiwxMCAxNSw3IDEzLDUgMTIsNiA3LDYgOSw0IDYsMSAxLDYgNCw5IDYsNyA4LDcgOCwxMiAxMSwxMiAxMCwxMyAxMiwxNSAxNSwxMiAxMywxMCIvPjwvc3ZnPg=="); -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.interface:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iIzc1QkVGRiIgZD0iTTExLjUgNGMtMS43NTkgMC0zLjIwNCAxLjMwOC0zLjQ0OSAzaC0zLjEyMmMtLjIyMy0uODYxLS45OTgtMS41LTEuOTI5LTEuNS0xLjEwNCAwLTIgLjg5NS0yIDIgMCAxLjEwNC44OTYgMiAyIDIgLjkzMSAwIDEuNzA2LS42MzkgMS45MjktMS41aDMuMTIyYy4yNDUgMS42OTEgMS42OSAzIDMuNDQ5IDMgMS45MyAwIDMuNS0xLjU3IDMuNS0zLjUgMC0xLjkzMS0xLjU3LTMuNS0zLjUtMy41em0wIDVjLS44MjcgMC0xLjUtLjY3NC0xLjUtMS41IDAtLjgyOC42NzMtMS41IDEuNS0xLjVzMS41LjY3MiAxLjUgMS41YzAgLjgyNi0uNjczIDEuNS0xLjUgMS41eiIvPjwvc3ZnPg=="); -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.module:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI0M1QzVDNSIgZD0iTTkgMTF2LTFjMC0uODM0LjQ5Ni0xLjczOCAxLTItLjUwNC0uMjctMS0xLjE2OC0xLTJ2LTFjMC0uODQtLjU4NC0xLTEtMXYtMWMyLjA4MyAwIDIgMS4xNjYgMiAydjFjMCAuOTY5LjcwMy45OCAxIDF2MmMtLjMyMi4wMi0xIC4wNTMtMSAxdjFjMCAuODM0LjA4MyAyLTIgMnYtMWMuODMzIDAgMS0xIDEtMXptLTYgMHYtMWMwLS44MzQtLjQ5Ni0xLjczOC0xLTIgLjUwNC0uMjcgMS0xLjE2OCAxLTJ2LTFjMC0uODQuNTg0LTEgMS0xdi0xYy0yLjA4MyAwLTIgMS4xNjYtMiAydjFjMCAuOTY5LS43MDMuOTgtMSAxdjJjLjMyMi4wMiAxIC4wNTMgMSAxdjFjMCAuODM0LS4wODMgMiAyIDJ2LTFjLS44MzMgMC0xLTEtMS0xeiIvPjwvc3ZnPg=="); - margin-left: 2px; -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.property:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI0M1QzVDNSIgZD0iTTEyLjA5IDQuMzU5bC0yLjY0MSAyLjY0MS0yLTIgMi42NDEtMi42NDFjLS41MDItLjIyNi0xLjA1NS0uMzU5LTEuNjQxLS4zNTktMi4yMDkgMC00IDEuNzkxLTQgNCAwIC41ODYuMTMzIDEuMTM5LjM1OSAxLjY0bC0zLjM1OSAzLjM2cy0xIDEgMCAyaDJsMy4zNTktMy4zNmMuNTAzLjIyNiAxLjA1NS4zNiAxLjY0MS4zNiAyLjIwOSAwIDQtMS43OTEgNC00IDAtLjU4Ni0uMTMzLTEuMTM5LS4zNTktMS42NDF6Ii8+PC9zdmc+"); - margin-left: 1px; -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.value:before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.enum:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PGcgZmlsbD0iIzc1QkVGRiI+PHBhdGggZD0iTTEyIDNoLTRsLTEgMXYyaDV2MWgtMnYxaDJsMS0xdi0zbC0xLTF6bTAgMmgtNHYtMWg0djF6TTMgMTJoNnYtNWgtNnY1em0xLTNoNHYxaC00di0xeiIvPjwvZz48L3N2Zz4="); -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.snippet:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI0M1QzVDNSIgZD0iTTEyIDExdi03aC03djdoLTF2LThoOXY4aC0xem0tNyAyaC0xdi0xaDF2MXptMi0xaC0xdjFoMXYtMXptMiAwaC0xdjFoMXYtMXptMiAxaC0xdi0xaDF2MXptMi0xaC0xdjFoMXYtMXoiLz48L3N2Zz4="); -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.keyword:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI0M1QzVDNSIgZD0iTTEzIDVoLTR2LTFoNHYxem0wIDNoLTJ2MWgydi0xem0tNCAwaC02djFoNnYtMXptLTIgM2gtNHYxaDR2LTF6bTYgMGgtNHYxaDR2LTF6bS01LTh2M2gtNXYtM2g1em0tMSAxaC0zdjFoM3YtMXoiLz48L3N2Zz4="); -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.unit:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHJlY3QgeD0iNCIgeT0iNiIgZmlsbD0iI0M1QzVDNSIgd2lkdGg9IjkiIGhlaWdodD0iNCIvPjxnIGZpbGw9IiMyQjI4MkUiPjxyZWN0IHg9IjUiIHk9IjgiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSI3IiB5PSI4IiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iOSIgeT0iOCIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjExIiB5PSI4IiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iNSIgeT0iNyIgd2lkdGg9IjMiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjkiIHk9IjciIHdpZHRoPSIzIiBoZWlnaHQ9IjEiLz48L2c+PC9zdmc+"); -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.text { - padding-left: 0; -} -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.text:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI0M1QzVDNSIgZD0iTTEgMnYxMmgxNHYtMTJoLTE0em0xMyAxMWgtMTJ2LTEwaDEydjEwem0tNi03di0xaC0xdjVoM3YtNGgtMnptMSAzaC0xdi0yaDF2MnptMy0ydjJoMXYxaC0ydi00aDJ2MWgtMXptLTYtMXY0aC0zdi0yaDF2MWgxdi0xaC0xdi0xaC0xdi0xaDN6Ii8+PC9zdmc+"); -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.color:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI0M1QzVDNSIgZD0iTTEwLjY0OCA4LjUwOHMtMS45MTEuNDU4LS40NzgtLjkxNmMxLjIxNy0xLjE2NyAzLjM0NC0yLjc0NyAxLjkxLTQuMTItMS40MzMtMS4zNzUtOS4wNzkuNDU2LTkuMDc5IDUuMDM2IDAgNC41ODEgNS43MzUgNS4wMzggOC4xMjQgNC4xMjIgMi4zODktLjkxNSAyLjg2Ni00LjU3OC0uNDc3LTQuMTIyem0tNS4yNzIgMS45MDJjLS41NzQgMC0xLjA0MS0uNDY3LTEuMDQxLTEuMDQxIDAtLjU3NS40NjctMS4wNDIgMS4wNDEtMS4wNDJzMS4wNDEuNDY2IDEuMDQxIDEuMDQyYzAgLjU3NC0uNDY3IDEuMDQxLTEuMDQxIDEuMDQxem0xLjA0MS0zYy0uNTc0IDAtMS4wNDEtLjQ2Ni0xLjA0MS0xLjA0MXMuNDY3LTEuMDQxIDEuMDQxLTEuMDQxIDEuMDQxLjQ2NiAxLjA0MSAxLjA0MWMwIC41NzQtLjQ2NyAxLjA0MS0xLjA0MSAxLjA0MXptMS45NDUtMi4yNWMwLS41NzUuNDY3LTEuMDQxIDEuMDQxLTEuMDQxLjU3NCAwIDEuMDQxLjQ2NiAxLjA0MSAxLjA0MXMtLjQ2NyAxLjA0MS0xLjA0MSAxLjA0MWMtLjU3NCAwLTEuMDQxLS40NjYtMS4wNDEtMS4wNDF6Ii8+PC9zdmc+"); -} - -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.reference:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PGcgZmlsbD0iI0U4QUI1MyI+PHBhdGggZD0iTTYgN2gtNGwtMSAxdjNsMSAxaDRsMS0xdi0zbC0xLTF6bTAgNGgtNHYtMWg0djF6bTAtMmgtNHYtMWg0djF6TTEwIDNoLTRsLTEgMXYyaDV2MWgtMi41ODZsLjU4Ni41ODZ2LjQxNGgybDEtMXYtM2wtMS0xem0wIDJoLTR2LTFoNHYxeiIvPjwvZz48L3N2Zz4="); -} \ No newline at end of file +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon { background-image: url('Misc_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.method, +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.function, +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.constructor { background-image: url('Method_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.field, +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.variable { background-image: url('Field_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.class { background-image: url('Class_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.interface { background-image: url('Interface_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.module { background-image: url('Namespace_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.property { background-image: url('Property_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.unit { background-image: url('Ruler_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.value, +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.enum { background-image: url('EnumItem_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.keyword { background-image: url('IntelliSenseKeyword_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.text { background-image: url('String_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.color { background-image: url('ColorPalette_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.file { background-image: url('Document_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.reference { background-image: url('Enumerator_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .icon.snippet { background-image: url('Snippet_inverse_16x.svg'); } \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index 7ae3ec84f2b..5485225ff18 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -83,8 +83,12 @@ class Renderer implements IRenderer { const configureFont = () => { const fontInfo = this.editor.getConfiguration().fontInfo; + data.root.style.fontSize = `${ fontInfo.fontSize }px`; main.style.fontFamily = fontInfo.fontFamily; + main.style.lineHeight = `${ fontInfo.lineHeight }px`; + data.icon.style.height = `${ fontInfo.lineHeight }px`; + data.icon.style.width = `${ fontInfo.lineHeight }px`; }; configureFont(); diff --git a/src/vs/editor/contrib/suggest/browser/symbol-sprite.svg b/src/vs/editor/contrib/suggest/browser/symbol-sprite.svg deleted file mode 100644 index b3ba27c70d2..00000000000 --- a/src/vs/editor/contrib/suggest/browser/symbol-sprite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 487696f8d6651345ab0e3da4f221d5441fd94daf Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 4 Oct 2016 09:48:05 +0200 Subject: [PATCH 008/163] fixes #13105 --- .../electron-browser/releaseNotesEditor.ts | 87 +++---------------- .../electron-browser/releaseNotesInput.ts | 6 +- 2 files changed, 15 insertions(+), 78 deletions(-) diff --git a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts index 4f324536962..21f41aadea2 100644 --- a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts +++ b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts @@ -7,11 +7,9 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { marked } from 'vs/base/common/marked/marked'; -import { always } from 'vs/base/common/async'; -import URI from 'vs/base/common/uri'; -import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Builder } from 'vs/base/browser/builder'; -import { append, $, addClass, removeClass } from 'vs/base/browser/dom'; +import { append, $ } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/workbench/services/themes/common/themeService'; @@ -20,13 +18,10 @@ import { EditorOptions } from 'vs/workbench/common/editor'; import WebView from 'vs/workbench/parts/html/browser/webview'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { asText } from 'vs/base/node/request'; -import { Keybinding } from 'vs/base/common/keybinding'; import { IRequestService } from 'vs/platform/request/common/request'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import product from 'vs/platform/product'; import { IModeService } from 'vs/editor/common/services/modeService'; -import {tokenizeToString} from 'vs/editor/common/modes/textToHtmlTokenizer'; +import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer'; function renderBody(body: string): string { return ` @@ -67,25 +62,12 @@ export class ReleaseNotesEditor extends BaseEditor { } setInput(input: ReleaseNotesInput, options: EditorOptions): TPromise { - const version = input.version; + const { text } = input; this.content.innerHTML = ''; - const match = /^(\d+\.\d)\./.exec(version); - - if (!match) { - return TPromise.as(null); - } - - const versionLabel = match[1].replace(/\./g, '_'); - const baseUrl = 'https://code.visualstudio.com/raw'; - const url = `${ baseUrl }/v${ versionLabel }.md`; - - this.loadContents(() => this.requestService.request({ url }) - .then(asText) - .then(text => this.patchKeybindings(text)) - .then(text => { - // we first need to load the modes... + return super.setInput(input, options) + .then(() => { const result = []; const renderer = new marked.Renderer(); renderer.code = (code, lang) => { @@ -95,14 +77,12 @@ export class ReleaseNotesEditor extends BaseEditor { }; marked(text, { renderer }); - return TPromise.join(result).then(() => text); - }) - .then(text => { - // then we can render + return TPromise.join(result); + }).then(() => { const renderer = new marked.Renderer(); renderer.code = (code, lang) => { const modeId = this.modeService.getModeIdForLanguageName(lang); - return `${ tokenizeToString(code, modeId) }`; + return `${tokenizeToString(code, modeId)}`; }; return marked(text, { renderer }); @@ -114,59 +94,14 @@ export class ReleaseNotesEditor extends BaseEditor { document.querySelector('.monaco-editor-background') ); - webview.baseUrl = `${ baseUrl }/`; + webview.baseUrl = `https://code.visualstudio.com/raw/`; webview.style(this.themeService.getColorTheme()); webview.contents = [body]; webview.onDidClickLink(link => this.openerService.open(link), null, this.contentDisposables); this.themeService.onDidColorThemeChange(themeId => webview.style(themeId), null, this.contentDisposables); this.contentDisposables.push(webview); - }) - .then(null, () => { - const uri = URI.parse(product.releaseNotesUrl); - this.openerService.open(uri); - this.editorService.closeEditor(this.position, this.input); - })); - - return super.setInput(input, options); - } - - private loadContents(loadingTask: ()=>TPromise): void { - this.contentDisposables = dispose(this.contentDisposables); - - this.content.innerHTML = ''; - addClass(this.content, 'loading'); - - let promise = loadingTask(); - promise = always(promise, () => removeClass(this.content, 'loading')); - - this.contentDisposables.push(toDisposable(() => promise.cancel())); - } - - private patchKeybindings(text: string): string { - return text.replace(/kb\(([a-z.\d\-]+)\)/gi, (match, kb) => { - const keybinding = this.keybindingService.lookupKeybindings(kb)[0]; - - if (!keybinding) { - return match; - } - - return this.keybindingService.getLabelFor(keybinding); - }).replace(/kbstyle\(([^\)]+)\)/gi, (match, kb) => { - const code = Keybinding.fromUserSettingsLabel(kb); - - if (!code) { - return match; - } - - const keybinding = new Keybinding(code); - - if (!keybinding) { - return match; - } - - return this.keybindingService.getLabelFor(keybinding); - }); + }); } layout(): void { diff --git a/src/vs/workbench/parts/update/electron-browser/releaseNotesInput.ts b/src/vs/workbench/parts/update/electron-browser/releaseNotesInput.ts index 80a39e5c853..b447d81231f 100644 --- a/src/vs/workbench/parts/update/electron-browser/releaseNotesInput.ts +++ b/src/vs/workbench/parts/update/electron-browser/releaseNotesInput.ts @@ -12,9 +12,11 @@ import { EditorInput } from 'vs/workbench/common/editor'; export class ReleaseNotesInput extends EditorInput { static get ID() { return 'workbench.releaseNotes.input'; } - get version(): string { return this._version; } - constructor(private _version: string) { + get version(): string { return this._version; } + get text(): string { return this._text; } + + constructor(private _version: string, private _text: string) { super(); } From 3c63ca22c6ff8482b7ac28de1682105c617be4a3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 4 Oct 2016 10:03:29 +0200 Subject: [PATCH 009/163] use timeout > 10ms, #13148 --- .../test/node/api/extHostDocumentSaveParticipant.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/test/node/api/extHostDocumentSaveParticipant.test.ts b/src/vs/workbench/test/node/api/extHostDocumentSaveParticipant.test.ts index d8ddd22601e..eaa69d4fca9 100644 --- a/src/vs/workbench/test/node/api/extHostDocumentSaveParticipant.test.ts +++ b/src/vs/workbench/test/node/api/extHostDocumentSaveParticipant.test.ts @@ -157,17 +157,17 @@ suite('ExtHostDocumentSaveParticipant', () => { }); test('event delivery, overall timeout', () => { - const participant = new ExtHostDocumentSaveParticipant(documents, workspace, { timeout: 10, errors: 5 }); + const participant = new ExtHostDocumentSaveParticipant(documents, workspace, { timeout: 20, errors: 5 }); let callCount = 0; let sub1 = participant.onWillSaveTextDocumentEvent(function (event) { callCount += 1; - event.waitUntil(TPromise.timeout(7)); + event.waitUntil(TPromise.timeout(17)); }); let sub2 = participant.onWillSaveTextDocumentEvent(function (event) { callCount += 1; - event.waitUntil(TPromise.timeout(7)); + event.waitUntil(TPromise.timeout(17)); }); let sub3 = participant.onWillSaveTextDocumentEvent(function (event) { From e7a496b881c1cb39a0a6e6fe420a1f1d59e56102 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 4 Oct 2016 10:11:24 +0200 Subject: [PATCH 010/163] use Object.create over {}, fixes #12890 --- src/vs/editor/common/services/editorSimpleWorker.ts | 2 +- src/vs/editor/test/common/model/compatMirrorModel.test.ts | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/common/services/editorSimpleWorker.ts b/src/vs/editor/common/services/editorSimpleWorker.ts index 642fabd7dc0..b4e8ec5e988 100644 --- a/src/vs/editor/common/services/editorSimpleWorker.ts +++ b/src/vs/editor/common/services/editorSimpleWorker.ts @@ -124,7 +124,7 @@ export class MirrorModel extends MirrorModel2 implements ICommonModel { public getAllUniqueWords(wordDefinition:RegExp, skipWordOnce?:string) : string[] { var foundSkipWord = false; - var uniqueWords = {}; + var uniqueWords = Object.create(null); return this._getAllWords(wordDefinition).filter((word) => { if (skipWordOnce && !foundSkipWord && skipWordOnce === word) { foundSkipWord = true; diff --git a/src/vs/editor/test/common/model/compatMirrorModel.test.ts b/src/vs/editor/test/common/model/compatMirrorModel.test.ts index 8ec13ce4bcc..dc336c86862 100644 --- a/src/vs/editor/test/common/model/compatMirrorModel.test.ts +++ b/src/vs/editor/test/common/model/compatMirrorModel.test.ts @@ -138,6 +138,13 @@ suite('Editor Model - MirrorModel', () => { assert.equal(uniqueWords.length, 2); assert.equal(uniqueWords[0], 'foo'); assert.equal(uniqueWords[1], 'bar'); + + model = new SimpleMirrorModel(null, [ 'toString', 'hasOwnProperty', 'foo' ], '\n', 1); + uniqueWords = model.getAllUniqueWords(DEFAULT_WORD_REGEXP); + assert.equal(uniqueWords.length, 3); + assert.equal(uniqueWords[0], 'toString'); + assert.equal(uniqueWords[1], 'hasOwnProperty'); + assert.equal(uniqueWords[2], 'foo'); }); test('word at/until pos', () => { From 4dd54771fdee96691a2a00bfb92a91ca10b1d7a3 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 4 Oct 2016 10:15:58 +0200 Subject: [PATCH 011/163] fixes #13174 --- .../extensions/electron-browser/extensions.contribution.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index fbff0a295cd..14c83b3584c 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -20,7 +20,7 @@ import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/co import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { VIEWLET_ID, IExtensionsWorkbenchService } from './extensions'; import { ExtensionsWorkbenchService } from './extensionsWorkbenchService'; -import { OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowInstalledExtensionsAction, UpdateAllAction, OpenExtensionsFolderAction, ConfigureWorkspaceRecommendedExtensionsAction } from './extensionsActions'; +import { OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExtensionsAction, ShowRecommendedExtensionsAction, ShowWorkspaceRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowInstalledExtensionsAction, UpdateAllAction, OpenExtensionsFolderAction, ConfigureWorkspaceRecommendedExtensionsAction, InstallVSIXAction } from './extensionsActions'; import { ExtensionsInput } from './extensionsInput'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { ExtensionEditor } from './extensionEditor'; @@ -119,6 +119,9 @@ actionRegistry.registerWorkbenchAction(openExtensionsFolderActionDescriptor, 'Ex const openExtensionsFileActionDescriptor = new SyncActionDescriptor(ConfigureWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceRecommendedExtensionsAction.ID, ConfigureWorkspaceRecommendedExtensionsAction.LABEL); actionRegistry.registerWorkbenchAction(openExtensionsFileActionDescriptor, 'Extensions: Open Extensions File', ExtensionsLabel); +const installVSIXActionDescriptor = new SyncActionDescriptor(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL); +actionRegistry.registerWorkbenchAction(installVSIXActionDescriptor, 'Extensions: Install from VSIX...', ExtensionsLabel); + Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ id: 'extensions', From ecaea72ef90f00095659a82dcf4c3d59357ddb39 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 4 Oct 2016 10:28:43 +0200 Subject: [PATCH 012/163] run formatter, #13057 --- .../browser/goToDeclaration.ts | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts index 151ac0a9880..205ee4a5e2d 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts +++ b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts @@ -7,30 +7,30 @@ import 'vs/css!./goToDeclaration'; import * as nls from 'vs/nls'; -import {Throttler} from 'vs/base/common/async'; -import {onUnexpectedError} from 'vs/base/common/errors'; -import {MarkedString, textToMarkedString} from 'vs/base/common/htmlContent'; -import {KeyCode, KeyMod, KeyChord} from 'vs/base/common/keyCodes'; +import { Throttler } from 'vs/base/common/async'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { MarkedString, textToMarkedString } from 'vs/base/common/htmlContent'; +import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; import * as platform from 'vs/base/common/platform'; import Severity from 'vs/base/common/severity'; import * as strings from 'vs/base/common/strings'; -import {TPromise} from 'vs/base/common/winjs.base'; +import { TPromise } from 'vs/base/common/winjs.base'; import * as browser from 'vs/base/browser/browser'; -import {IKeyboardEvent} from 'vs/base/browser/keyboardEvent'; -import {IEditorService} from 'vs/platform/editor/common/editor'; -import {IMessageService} from 'vs/platform/message/common/message'; -import {Range} from 'vs/editor/common/core/range'; +import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { IEditorService } from 'vs/platform/editor/common/editor'; +import { IMessageService } from 'vs/platform/message/common/message'; +import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import {editorAction, IActionOptions, ServicesAccessor, EditorAction} from 'vs/editor/common/editorCommonExtensions'; -import {Location, DefinitionProviderRegistry} from 'vs/editor/common/modes'; -import {ICodeEditor, IEditorMouseEvent, IMouseTarget} from 'vs/editor/browser/editorBrowser'; -import {editorContribution} from 'vs/editor/browser/editorBrowserExtensions'; -import {getDeclarationsAtPosition} from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration'; -import {ReferencesController} from 'vs/editor/contrib/referenceSearch/browser/referencesController'; -import {ReferencesModel} from 'vs/editor/contrib/referenceSearch/browser/referencesModel'; -import {IDisposable, dispose} from 'vs/base/common/lifecycle'; -import {PeekContext} from 'vs/editor/contrib/zoneWidget/browser/peekViewWidget'; -import {ContextKeyExpr} from 'vs/platform/contextkey/common/contextkey'; +import { editorAction, IActionOptions, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; +import { Location, DefinitionProviderRegistry } from 'vs/editor/common/modes'; +import { ICodeEditor, IEditorMouseEvent, IMouseTarget } from 'vs/editor/browser/editorBrowser'; +import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; +import { getDeclarationsAtPosition } from 'vs/editor/contrib/goToDeclaration/common/goToDeclaration'; +import { ReferencesController } from 'vs/editor/contrib/referenceSearch/browser/referencesController'; +import { ReferencesModel } from 'vs/editor/contrib/referenceSearch/browser/referencesModel'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { PeekContext } from 'vs/editor/contrib/zoneWidget/browser/peekViewWidget'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import ModeContextKeys = editorCommon.ModeContextKeys; import EditorContextKeys = editorCommon.EditorContextKeys; @@ -50,12 +50,12 @@ export class DefinitionAction extends EditorAction { private _configuration: DefinitionActionConfig; - constructor(configuration: DefinitionActionConfig, opts:IActionOptions) { + constructor(configuration: DefinitionActionConfig, opts: IActionOptions) { super(opts); this._configuration = configuration; } - public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): TPromise { + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): TPromise { const messageService = accessor.get(IMessageService); const editorService = accessor.get(IEditorService); @@ -102,7 +102,7 @@ export class DefinitionAction extends EditorAction { }); } - private _onResult(editorService:IEditorService, editor:editorCommon.ICommonCodeEditor, model: ReferencesModel) { + private _onResult(editorService: IEditorService, editor: editorCommon.ICommonCodeEditor, model: ReferencesModel) { if (this._configuration.openInPeek) { this._openInPeek(editorService, editor, model); } else { @@ -115,7 +115,7 @@ export class DefinitionAction extends EditorAction { } } - private _openReference(editorService:IEditorService, reference: Location, sideBySide: boolean): TPromise{ + private _openReference(editorService: IEditorService, reference: Location, sideBySide: boolean): TPromise { let {uri, range} = reference; return editorService.openEditor({ resource: uri, @@ -124,11 +124,11 @@ export class DefinitionAction extends EditorAction { revealIfVisible: !sideBySide } }, sideBySide).then(editor => { - return editor.getControl(); + return editor.getControl(); }); } - private _openInPeek(editorService:IEditorService, target: editorCommon.ICommonCodeEditor, model: ReferencesModel) { + private _openInPeek(editorService: IEditorService, target: editorCommon.ICommonCodeEditor, model: ReferencesModel) { let controller = ReferencesController.get(target); if (controller) { controller.toggleWidget(target.getSelection(), TPromise.as(model), { @@ -392,7 +392,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC } } - let newDecorations : editorCommon.IModelDeltaDecoration = { + let newDecorations: editorCommon.IModelDeltaDecoration = { range: range, options: { inlineClassName: 'goto-definition-link', From fc263aa2b632863b9be554dc5f7c8857c4750a78 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 4 Oct 2016 10:39:36 +0200 Subject: [PATCH 013/163] use modeId of target, not source, fixes #13057 --- .../browser/goToDeclaration.ts | 49 +++++++------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts index 205ee4a5e2d..2c33ea87f67 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts +++ b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts @@ -9,7 +9,7 @@ import 'vs/css!./goToDeclaration'; import * as nls from 'vs/nls'; import { Throttler } from 'vs/base/common/async'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { MarkedString, textToMarkedString } from 'vs/base/common/htmlContent'; +import { MarkedString } from 'vs/base/common/htmlContent'; import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; import * as platform from 'vs/base/common/platform'; import Severity from 'vs/base/common/severity'; @@ -18,6 +18,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as browser from 'vs/base/browser/browser'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IEditorService } from 'vs/platform/editor/common/editor'; +import { IModeService } from 'vs/editor/common/services/modeService'; import { IMessageService } from 'vs/platform/message/common/message'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -232,7 +233,8 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC constructor( editor: ICodeEditor, - @IEditorService private editorService: IEditorService + @IEditorService private editorService: IEditorService, + @IModeService private modeService: IModeService ) { this.toUnhook = []; this.decorations = []; @@ -310,21 +312,18 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC startColumn: word.startColumn, endLineNumber: position.lineNumber, endColumn: word.endColumn - }, nls.localize('multipleResults', "Click to show the {0} definitions found.", results.length), false); + }, nls.localize('multipleResults', "Click to show {0} definitions.", results.length)); } // Single result else { let result = results[0]; this.editorService.resolveEditorModel({ resource: result.uri }).then(model => { - let source: string; + let hoverMessage: MarkedString; if (model && model.textEditorModel) { - - let from = Math.max(1, result.range.startLineNumber), - to: number, - editorModel: editorCommon.IModel; - - editorModel = model.textEditorModel; + const editorModel = model.textEditorModel; + let from = Math.max(1, result.range.startLineNumber); + let to: number; // if we have a range, take that into consideration for the "to" position, otherwise fallback to MAX_SOURCE_PREVIEW_LINES if (!Range.isEmpty(result.range)) { @@ -333,7 +332,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC to = Math.min(from + GotoDefinitionWithMouseEditorContribution.MAX_SOURCE_PREVIEW_LINES, editorModel.getLineCount()); } - source = editorModel.getValueInRange({ + let source = editorModel.getValueInRange({ startLineNumber: from, startColumn: 1, endLineNumber: to, @@ -361,6 +360,12 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC if (to < editorModel.getLineCount()) { source += '\n\u2026'; } + + const language = this.modeService.getModeIdByFilenameOrFirstLine(editorModel.uri.fsPath); + hoverMessage = { + language, + value: source + }; } this.addDecoration({ @@ -368,31 +373,15 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC startColumn: word.startColumn, endLineNumber: position.lineNumber, endColumn: word.endColumn - }, source, true); + }, hoverMessage); }); } }).done(undefined, onUnexpectedError); } - private addDecoration(range: editorCommon.IRange, text: string, isCode: boolean): void { - let model = this.editor.getModel(); - if (!model) { - return; - } + private addDecoration(range: editorCommon.IRange, hoverMessage: MarkedString): void { - let hoverMessage: MarkedString = void 0; - if (text && text.trim().length > 0) { - if (isCode) { - hoverMessage = { - language: model.getMode().getId(), - value: text - }; - } else { - hoverMessage = textToMarkedString(text); - } - } - - let newDecorations: editorCommon.IModelDeltaDecoration = { + const newDecorations: editorCommon.IModelDeltaDecoration = { range: range, options: { inlineClassName: 'goto-definition-link', From 9339926361af15a49333e6800befa7d8e8867fab Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 4 Oct 2016 10:01:53 +0200 Subject: [PATCH 014/163] Find in Folder: Null check guard --- src/vs/workbench/parts/search/browser/searchViewlet.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/search/browser/searchViewlet.ts b/src/vs/workbench/parts/search/browser/searchViewlet.ts index ee2048bddec..63e14845a74 100644 --- a/src/vs/workbench/parts/search/browser/searchViewlet.ts +++ b/src/vs/workbench/parts/search/browser/searchViewlet.ts @@ -670,7 +670,12 @@ export class SearchViewlet extends Viewlet { } public searchInFolder(resource: URI): void { - if (this.contextService.getWorkspace().resource.toString() === resource.toString()) { + const workspace = this.contextService.getWorkspace(); + if (!workspace) { + return; + } + + if (workspace.resource.toString() === resource.toString()) { this.inputPatternIncludes.setValue(''); this.searchWidget.focus(); return; From d01bc20b79ef1fefad9f3a98e1b107323287d48b Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 4 Oct 2016 11:04:07 +0200 Subject: [PATCH 015/163] fix #13196 --- .../search/browser/search.contribution.ts | 1 + .../parts/search/browser/searchActions.ts | 14 ++++++++++++ .../parts/search/browser/searchWidget.ts | 22 +++++++++---------- .../parts/search/common/constants.ts | 2 ++ 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/parts/search/browser/search.contribution.ts b/src/vs/workbench/parts/search/browser/search.contribution.ts index 1a9d178171a..603887028f8 100644 --- a/src/vs/workbench/parts/search/browser/search.contribution.ts +++ b/src/vs/workbench/parts/search/browser/search.contribution.ts @@ -181,6 +181,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusPre registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleCaseSensitiveAction, Constants.ToggleCaseSensitiveActionId, '', ToggleCaseSensitiveKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleWholeWordAction, Constants.ToggleWholeWordActionId, '', ToggleWholeWordKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleRegexAction, Constants.ToggleRegexActionId, '', ToggleRegexKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.CloseReplaceAction, Constants.CloseReplaceWidgetActionId, '', { primary: KeyCode.Escape }, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.ReplaceInputBoxFocussedKey)), ''); // Configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index d8106725267..a84377313be 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -170,6 +170,20 @@ export class ReplaceInFilesAction extends Action { } } +export class CloseReplaceAction extends Action { + + constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) { + super(id, label); + } + + public run(): TPromise { + let searchAndReplaceWidget = (this.viewletService.getActiveViewlet()).searchAndReplaceWidget; + searchAndReplaceWidget.toggleReplace(false); + searchAndReplaceWidget.focus(); + return TPromise.as(null); + } +} + export class FindInFolderAction extends Action { private resource: URI; diff --git a/src/vs/workbench/parts/search/browser/searchWidget.ts b/src/vs/workbench/parts/search/browser/searchWidget.ts index 3b66bedd7b6..5e6ec175aaa 100644 --- a/src/vs/workbench/parts/search/browser/searchWidget.ts +++ b/src/vs/workbench/parts/search/browser/searchWidget.ts @@ -76,6 +76,7 @@ export class SearchWidget extends Widget { public domNode: HTMLElement; public searchInput: FindInput; private searchInputBoxFocussed: IContextKey; + private replaceInputBoxFocussed: IContextKey; private replaceInput: InputBox; public searchInputFocusTracker: dom.IFocusTracker; @@ -113,6 +114,7 @@ export class SearchWidget extends Widget { this.searchHistory = new HistoryNavigator(); this.replaceActive = Constants.ReplaceActiveKey.bindTo(this.keyBindingService); this.searchInputBoxFocussed = Constants.SearchInputBoxFocussedKey.bindTo(this.keyBindingService); + this.replaceInputBoxFocussed = Constants.ReplaceInputBoxFocussedKey.bindTo(this.keyBindingService); this.render(container, options); } @@ -218,7 +220,7 @@ export class SearchWidget extends Widget { this.searchHistory.add(this.searchInput.getValue()); })); - this.searchInputFocusTracker = dom.trackFocus(this.searchInput.inputBox.inputElement); + this.searchInputFocusTracker = this._register(dom.trackFocus(this.searchInput.inputBox.inputElement)); this._register(this.searchInputFocusTracker.addFocusListener(() => { this.searchInputBoxFocussed.set(true); })); @@ -244,7 +246,13 @@ export class SearchWidget extends Widget { this.replaceActionBar = this._register(new ActionBar(this.replaceContainer)); this.replaceActionBar.push([this.replaceAllAction], { icon: true, label: false }); - this.replaceInputFocusTracker = dom.trackFocus(this.replaceInput.inputElement); + this.replaceInputFocusTracker = this._register(dom.trackFocus(this.replaceInput.inputElement)); + this._register(this.replaceInputFocusTracker.addFocusListener(() => { + this.replaceInputBoxFocussed.set(true); + })); + this._register(this.replaceInputFocusTracker.addBlurListener(() => { + this.replaceInputBoxFocussed.set(false); + })); } triggerReplaceAll(): TPromise { @@ -321,10 +329,6 @@ export class SearchWidget extends Widget { case KeyCode.Enter: this.submitSearch(); return; - case KeyCode.Escape: - this.onToggleReplaceButton(); - this.searchInput.focus(); - return; default: return; } @@ -340,12 +344,6 @@ export class SearchWidget extends Widget { this.setReplaceAllActionState(false); this.replaceAllAction.searchWidget= null; this.replaceActionBar = null; - if (this.searchInputFocusTracker) { - this.searchInputFocusTracker.dispose(); - } - if (this.replaceInputFocusTracker) { - this.replaceInputFocusTracker.dispose(); - } super.dispose(); } } diff --git a/src/vs/workbench/parts/search/common/constants.ts b/src/vs/workbench/parts/search/common/constants.ts index 678d59c02dd..26a5f3bf3bb 100644 --- a/src/vs/workbench/parts/search/common/constants.ts +++ b/src/vs/workbench/parts/search/common/constants.ts @@ -10,9 +10,11 @@ export const VIEWLET_ID = 'workbench.view.search'; export const ToggleCaseSensitiveActionId = 'toggleSearchCaseSensitive'; export const ToggleWholeWordActionId = 'toggleSearchWholeWord'; export const ToggleRegexActionId = 'toggleSearchRegex'; +export const CloseReplaceWidgetActionId = 'closeReplaceInFilesWidget'; export const SearchViewletVisibleKey = new RawContextKey('searchViewletVisible', true); export const InputBoxFocussedKey = new RawContextKey('inputBoxFocus', false); export const SearchInputBoxFocussedKey = new RawContextKey('searchInputBoxFocus', false); +export const ReplaceInputBoxFocussedKey = new RawContextKey('replaceInputBoxFocus', false); export const ReplaceActiveKey= new RawContextKey('replaceActive', false); \ No newline at end of file From 1fdc366e15829497e37a3cc93b2c06424cd91d4a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 4 Oct 2016 11:12:13 +0200 Subject: [PATCH 016/163] smoother title control update when closing --- .../workbench/browser/parts/editor/sideBySideEditorControl.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts index 29021184ec0..84963de008a 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts @@ -223,8 +223,9 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti POSITIONS.forEach(position => { const titleAreaControl = this.getTitleAreaControl(position); const context = this.stacks.groupAt(position); + const hasContext = titleAreaControl.hasContext(); titleAreaControl.setContext(context); - if (!context && titleAreaControl.hasContext()) { + if (!context && hasContext) { titleAreaControl.refresh(); // clear out the control if the context is no longer present and there was a context } }); From 9e91f0ad9dbeb30ddd0ec07101a89343a736fcb3 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 4 Oct 2016 11:32:43 +0200 Subject: [PATCH 017/163] fall back to current language, fixes #11331 --- .../hover/browser/modesContentHover.ts | 63 ++++++++++--------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/src/vs/editor/contrib/hover/browser/modesContentHover.ts b/src/vs/editor/contrib/hover/browser/modesContentHover.ts index f118c3fc3c4..4789f0080d0 100644 --- a/src/vs/editor/contrib/hover/browser/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/browser/modesContentHover.ts @@ -7,22 +7,22 @@ import 'vs/css!vs/base/browser/ui/progressbar/progressbar'; import * as nls from 'vs/nls'; import URI from 'vs/base/common/uri'; -import {onUnexpectedError} from 'vs/base/common/errors'; -import {$} from 'vs/base/browser/dom'; -import {TPromise} from 'vs/base/common/winjs.base'; -import {renderMarkedString} from 'vs/base/browser/htmlContentRenderer'; -import {IOpenerService, NullOpenerService} from 'vs/platform/opener/common/opener'; -import {IModeService} from 'vs/editor/common/services/modeService'; -import {Range} from 'vs/editor/common/core/range'; -import {Position} from 'vs/editor/common/core/position'; -import {IRange} from 'vs/editor/common/editorCommon'; -import {HoverProviderRegistry, Hover} from 'vs/editor/common/modes'; -import {tokenizeToString} from 'vs/editor/common/modes/textToHtmlTokenizer'; -import {ICodeEditor} from 'vs/editor/browser/editorBrowser'; -import {getHover} from '../common/hover'; -import {HoverOperation, IHoverComputer} from './hoverOperation'; -import {ContentHoverWidget} from './hoverWidgets'; -import {textToMarkedString, MarkedString} from 'vs/base/common/htmlContent'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { $ } from 'vs/base/browser/dom'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { renderMarkedString } from 'vs/base/browser/htmlContentRenderer'; +import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { Range } from 'vs/editor/common/core/range'; +import { Position } from 'vs/editor/common/core/position'; +import { IRange } from 'vs/editor/common/editorCommon'; +import { HoverProviderRegistry, Hover } from 'vs/editor/common/modes'; +import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { getHover } from '../common/hover'; +import { HoverOperation, IHoverComputer } from './hoverOperation'; +import { ContentHoverWidget } from './hoverWidgets'; +import { textToMarkedString, MarkedString } from 'vs/base/common/htmlContent'; class ModesContentComputer implements IHoverComputer { @@ -58,7 +58,7 @@ class ModesContentComputer implements IHoverComputer { } public computeSync(): Hover[] { - var result:Hover[] = []; + var result: Hover[] = []; var lineNumber = this._range.startLineNumber; if (lineNumber > this._editor.getModel().getLineCount()) { @@ -67,7 +67,7 @@ class ModesContentComputer implements IHoverComputer { } var hasHoverContent = (contents: MarkedString | MarkedString[]) => { - return contents && (!Array.isArray(contents) || ( contents).length > 0); + return contents && (!Array.isArray(contents) || (contents).length > 0); }; var lineDecorations = this._editor.getLineDecorations(lineNumber); @@ -77,15 +77,15 @@ class ModesContentComputer implements IHoverComputer { var endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn; if (startColumn <= this._range.startColumn && this._range.endColumn <= endColumn && hasHoverContent(d.options.hoverMessage)) { - var obj:Hover = { + var obj: Hover = { contents: [], range: new Range(this._range.startLineNumber, startColumn, this._range.startLineNumber, endColumn) }; if (d.options.hoverMessage) { if (Array.isArray(d.options.hoverMessage)) { - obj.contents = obj.contents.concat( d.options.hoverMessage); + obj.contents = obj.contents.concat(d.options.hoverMessage); } else { - obj.contents.push( d.options.hoverMessage); + obj.contents.push(d.options.hoverMessage); } } result.push(obj); @@ -126,7 +126,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { private _lastRange: Range; private _computer: ModesContentComputer; private _hoverOperation: HoverOperation; - private _highlightDecorations:string[]; + private _highlightDecorations: string[]; private _isChangingDecorations: boolean; private _openerService: IOpenerService; private _modeService: IModeService; @@ -143,9 +143,9 @@ export class ModesContentHoverWidget extends ContentHoverWidget { this._hoverOperation = new HoverOperation( this._computer, - (result:Hover[]) => this._withResult(result, true), + (result: Hover[]) => this._withResult(result, true), null, - (result:any) => this._withResult(result, false) + (result: any) => this._withResult(result, false) ); } @@ -215,12 +215,12 @@ export class ModesContentHoverWidget extends ContentHoverWidget { this._isChangingDecorations = false; } - public _withResult(result: Hover[], complete:boolean): void { + public _withResult(result: Hover[], complete: boolean): void { this._messages = result; if (this._lastRange && this._messages.length > 0) { this._renderMessages(this._lastRange, this._messages); - } else if(complete) { + } else if (complete) { this.hide(); } } @@ -248,10 +248,15 @@ export class ModesContentHoverWidget extends ContentHoverWidget { this._openerService.open(URI.parse(content)).then(void 0, onUnexpectedError); }, codeBlockRenderer: (languageAlias, value): string | TPromise => { - // In markdown, it is possible that we stumble upon language aliases (e.g. js instead of javascript) - const modeId = this._modeService.getModeIdForLanguageName(languageAlias); + // In markdown, + // it is possible that we stumble upon language aliases (e.g.js instead of javascript) + // it is possible no alias is given in which case we fall back to the current editor lang + const modeId = languageAlias + ? this._modeService.getModeIdForLanguageName(languageAlias) + : this._editor.getModel().getModeId(); + return this._modeService.getOrCreateMode(modeId).then(_ => { - return `
${ tokenizeToString(value, modeId) }
`; + return `
${tokenizeToString(value, modeId)}
`; }); } }); From f6f188cea819e8b51a17a531d0bd5ce29a043ac3 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 4 Oct 2016 11:36:57 +0200 Subject: [PATCH 018/163] allow to contribute to the tab context menu --- .../platform/actions/browser/menusExtensionPoint.ts | 1 + src/vs/platform/actions/common/actions.ts | 3 ++- .../workbench/browser/parts/editor/titleControl.ts | 13 +++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 3eb906cc83d..25be267fc03 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -30,6 +30,7 @@ namespace schema { case 'editor/title': return MenuId.EditorTitle; case 'editor/context': return MenuId.EditorContext; case 'explorer/context': return MenuId.ExplorerContext; + case 'editor/tab': return MenuId.EditorTab; } } diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 250504ec6eb..3de63bfcab8 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -39,7 +39,8 @@ export interface IMenuItem { export enum MenuId { EditorTitle = 1, EditorContext = 2, - ExplorerContext = 3 + ExplorerContext = 3, + EditorTab = 4 } export const IMenuService = createDecorator('menuService'); diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 436e2b5b14d..eda18501325 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -417,6 +417,12 @@ export abstract class TitleControl implements ITitleAreaControl { } protected onContextMenu(identifier: IEditorIdentifier, e: Event, node: HTMLElement): void { + + // Update the resource context + const currentContext = this.resourceContext.get(); + this.resourceContext.set(identifier.editor && getResource(identifier.editor)); + + // Find target anchor let anchor: HTMLElement | { x: number, y: number } = node; if (e instanceof MouseEvent) { const event = new StandardMouseEvent(e); @@ -434,6 +440,9 @@ export abstract class TitleControl implements ITitleAreaControl { } return null; + }, + onHide: (cancel) => { + this.resourceContext.set(currentContext); // restore previous context } }); } @@ -462,6 +471,10 @@ export abstract class TitleControl implements ITitleAreaControl { actions.push(new Separator(), this.pinEditorAction); } + const titleBarMenu = this.menuService.createMenu(MenuId.EditorTab, this.contextKeyService); + fillInActions(titleBarMenu, actions); + titleBarMenu.dispose(); // not needed anymore + return actions; } From e499b26fb0fd701973e932e409ddecc68c3e83c8 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 4 Oct 2016 11:38:36 +0200 Subject: [PATCH 019/163] fix #12933 --- .../workbench/parts/tasks/electron-browser/task.contribution.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index dc5319eb7cb..05d43600e1f 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -440,6 +440,7 @@ class StatusBarItem implements IStatusbarItem { Dom.addClass(label, 'task-statusbar-item-label'); element.appendChild(label); + element.title = nls.localize('problems', "Problems"); Dom.addClass(error, 'task-statusbar-item-label-error'); error.innerHTML = '0'; From 512ce31500eac26a6f661fc883c926abfc33a788 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 4 Oct 2016 09:59:11 +0200 Subject: [PATCH 020/163] zoneWidget: introduce frameWidth option --- .../contrib/zoneWidget/browser/zoneWidget.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts index d7a0e78d845..2101a009c80 100644 --- a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts @@ -18,19 +18,20 @@ export interface IOptions { showFrame?: boolean; showArrow?: boolean; frameColor?: string; + frameWidth?: number; className?: string; isAccessible?: boolean; isResizeable?: boolean; } -var defaultOptions: IOptions = { +const defaultOptions: IOptions = { showArrow: true, showFrame: true, frameColor: '', className: '' }; -var WIDGET_ID = 'vs.editor.contrib.zoneWidget'; +const WIDGET_ID = 'vs.editor.contrib.zoneWidget'; export class ViewZoneDelegate implements IViewZone { @@ -112,7 +113,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { } this._disposables.add(this.editor.onDidLayoutChange((info: EditorLayoutInfo) => { - var width = this._getWidth(info); + const width = this._getWidth(info); this.domNode.style.width = width + 'px'; this._onWidth(width); })); @@ -263,10 +264,11 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { if (this.options.showFrame) { + const width = this.options.frameWidth ? this.options.frameWidth : frameThickness; this.container.style.borderTopColor = this.options.frameColor; this.container.style.borderBottomColor = this.options.frameColor; - this.container.style.borderTopWidth = frameThickness + 'px'; - this.container.style.borderBottomWidth = frameThickness + 'px'; + this.container.style.borderTopWidth = width + 'px'; + this.container.style.borderBottomWidth = width + 'px'; } let containerHeight = heightInLines * lineHeight - this._decoratingElementsHeight(); @@ -280,7 +282,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { this.editor.setSelection(where); // Reveal the line above or below the zone widget, to get the zone widget in the viewport - var revealLineNumber = Math.min(this.editor.getModel().getLineCount(), Math.max(1, where.endLineNumber + 1)); + const revealLineNumber = Math.min(this.editor.getModel().getLineCount(), Math.max(1, where.endLineNumber + 1)); this.editor.revealLine(revealLineNumber); } @@ -352,4 +354,3 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { return this.editor.getLayoutInfo().width; } } - From 0e3e5bd8ff8cce783aebadbdbaa3440686e2e853 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 4 Oct 2016 10:08:11 +0200 Subject: [PATCH 021/163] debug: add hit condition to breakpoint model --- .../debug/browser/debugEditorModelManager.ts | 37 ++++++++++--------- src/vs/workbench/parts/debug/common/debug.ts | 3 ++ .../parts/debug/common/debugModel.ts | 12 +++--- .../debug/electron-browser/debugService.ts | 6 +-- .../debug/electron-browser/debugViewer.ts | 4 +- 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts index 3d9510afb95..c6237974b7a 100644 --- a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts +++ b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts @@ -200,11 +200,12 @@ export class DebugEditorModelManager implements IWorkbenchContribution { const data: IRawBreakpoint[] = []; - const enabledAndConditions: { [key: number]: { enabled: boolean, condition: string } } = {}; + const lineToBreakpointDataMap: { [key: number]: { enabled: boolean, condition: string, hitCondition: string } } = {}; this.debugService.getModel().getBreakpoints().filter(bp => bp.source.uri.toString() === modelUrlStr).forEach(bp => { - enabledAndConditions[bp.lineNumber] = { + lineToBreakpointDataMap[bp.lineNumber] = { enabled: bp.enabled, - condition: bp.condition + condition: bp.condition, + hitCondition: bp.hitCondition }; }); @@ -217,8 +218,9 @@ export class DebugEditorModelManager implements IWorkbenchContribution { data.push({ uri: modelUrl, lineNumber: decorationRange.startLineNumber, - enabled: enabledAndConditions[modelData.breakpointLines[i]].enabled, - condition: enabledAndConditions[modelData.breakpointLines[i]].condition + enabled: lineToBreakpointDataMap[modelData.breakpointLines[i]].enabled, + condition: lineToBreakpointDataMap[modelData.breakpointLines[i]].condition, + hitCondition: lineToBreakpointDataMap[modelData.breakpointLines[i]].hitCondition }); } } @@ -280,7 +282,7 @@ export class DebugEditorModelManager implements IWorkbenchContribution { let result = (!breakpoint.enabled || !activated) ? DebugEditorModelManager.BREAKPOINT_DISABLED_DECORATION : debugActive && modelData && modelData.dirty && !breakpoint.verified ? DebugEditorModelManager.BREAKPOINT_DIRTY_DECORATION : debugActive && !breakpoint.verified ? DebugEditorModelManager.BREAKPOINT_UNVERIFIED_DECORATION : - !breakpoint.condition ? DebugEditorModelManager.BREAKPOINT_DECORATION : null; + !breakpoint.condition && !breakpoint.hitCondition ? DebugEditorModelManager.BREAKPOINT_DECORATION : null; if (result && breakpoint.message) { result = objects.clone(result); @@ -291,19 +293,20 @@ export class DebugEditorModelManager implements IWorkbenchContribution { return result; } - if (!session || session.configuration.capabilities.supportsConditionalBreakpoints) { - const mode = modelData ? modelData.model.getMode() : null; - const modeId = mode ? mode.getId() : ''; - const glyphMarginHoverMessage = `\`\`\`${modeId}\n${ breakpoint.condition }\`\`\``; - - return { - glyphMarginClassName: 'debug-breakpoint-conditional-glyph', - glyphMarginHoverMessage, - stickiness: editorcommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges - }; + if (session && !session.configuration.capabilities.supportsConditionalBreakpoints) { + return DebugEditorModelManager.BREAKPOINT_UNSUPPORTED_DECORATION; } + + const mode = modelData ? modelData.model.getMode() : null; + const modeId = mode ? mode.getId() : ''; + const condition = breakpoint.condition ? breakpoint.condition : breakpoint.hitCondition; + const glyphMarginHoverMessage = `\`\`\`${modeId}\n${ condition }\`\`\``; - return DebugEditorModelManager.BREAKPOINT_UNSUPPORTED_DECORATION; + return { + glyphMarginClassName: 'debug-breakpoint-conditional-glyph', + glyphMarginHoverMessage, + stickiness: editorcommon.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges + }; } // editor decorations diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 4e87d10c03a..4e2719cd7d8 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -130,6 +130,7 @@ export interface IRawBreakpoint { lineNumber: number; enabled?: boolean; condition?: string; + hitCondition?: string; } export interface IBreakpoint extends IEnablement { @@ -137,6 +138,7 @@ export interface IBreakpoint extends IEnablement { lineNumber: number; desiredLineNumber: number; condition: string; + hitCondition: string; verified: boolean; idFromAdapter: number; message: string; @@ -146,6 +148,7 @@ export interface IFunctionBreakpoint extends IEnablement { name: string; verified: boolean; idFromAdapter: number; + hitCondition: string; } export interface IExceptionBreakpoint extends IEnablement { diff --git a/src/vs/workbench/parts/debug/common/debugModel.ts b/src/vs/workbench/parts/debug/common/debugModel.ts index b4cac7501a4..9f55504dd9d 100644 --- a/src/vs/workbench/parts/debug/common/debugModel.ts +++ b/src/vs/workbench/parts/debug/common/debugModel.ts @@ -410,7 +410,8 @@ export class Breakpoint implements debug.IBreakpoint { public source: Source, public desiredLineNumber: number, public enabled: boolean, - public condition: string + public condition: string, + public hitCondition: string ) { if (enabled === undefined) { this.enabled = true; @@ -431,7 +432,7 @@ export class FunctionBreakpoint implements debug.IFunctionBreakpoint { public verified: boolean; public idFromAdapter: number; - constructor(public name: string, public enabled: boolean) { + constructor(public name: string, public enabled: boolean, public hitCondition: string) { this.verified = false; this.id = uuid.generateUuid(); } @@ -563,7 +564,7 @@ export class Model implements debug.IModel { public addBreakpoints(rawData: debug.IRawBreakpoint[]): void { this.breakpoints = this.breakpoints.concat(rawData.map(rawBp => - new Breakpoint(new Source(Source.toRawSource(rawBp.uri, this)), rawBp.lineNumber, rawBp.enabled, rawBp.condition))); + new Breakpoint(new Source(Source.toRawSource(rawBp.uri, this)), rawBp.lineNumber, rawBp.enabled, rawBp.condition, rawBp.hitCondition))); this.breakpointsActivated = true; this._onDidChangeBreakpoints.fire(); } @@ -612,17 +613,18 @@ export class Model implements debug.IModel { } public addFunctionBreakpoint(functionName: string): void { - this.functionBreakpoints.push(new FunctionBreakpoint(functionName, true)); + this.functionBreakpoints.push(new FunctionBreakpoint(functionName, true, null)); this._onDidChangeBreakpoints.fire(); } - public updateFunctionBreakpoints(data: { [id: string]: { name?: string, verified?: boolean; id?: number } }): void { + public updateFunctionBreakpoints(data: { [id: string]: { name?: string, verified?: boolean; id?: number; hitCondition?: string } }): void { this.functionBreakpoints.forEach(fbp => { const fbpData = data[fbp.getId()]; if (fbpData) { fbp.name = fbpData.name || fbp.name; fbp.verified = fbpData.verified; fbp.idFromAdapter = fbpData.id; + fbp.hitCondition = fbpData.hitCondition; } }); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index d1d67e57b1a..ae9288f4147 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -359,7 +359,7 @@ export class DebugService implements debug.IDebugService { try { result = JSON.parse(this.storageService.get(DEBUG_BREAKPOINTS_KEY, StorageScope.WORKSPACE, '[]')).map((breakpoint: any) => { return new model.Breakpoint(new Source(breakpoint.source.raw ? breakpoint.source.raw : { path: uri.parse(breakpoint.source.uri).fsPath, name: breakpoint.source.name }), - breakpoint.desiredLineNumber || breakpoint.lineNumber, breakpoint.enabled, breakpoint.condition); + breakpoint.desiredLineNumber || breakpoint.lineNumber, breakpoint.enabled, breakpoint.condition, breakpoint.hitCondition); }); } catch (e) { } @@ -370,7 +370,7 @@ export class DebugService implements debug.IDebugService { let result: debug.IFunctionBreakpoint[]; try { result = JSON.parse(this.storageService.get(DEBUG_FUNCTION_BREAKPOINTS_KEY, StorageScope.WORKSPACE, '[]')).map((fb: any) => { - return new model.FunctionBreakpoint(fb.name, fb.enabled); + return new model.FunctionBreakpoint(fb.name, fb.enabled, fb.hitCondition); }); } catch (e) { } @@ -1045,7 +1045,7 @@ export class DebugService implements debug.IDebugService { return this.session.setBreakpoints({ source: rawSource, lines: breakpointsToSend.map(bp => bp.desiredLineNumber), - breakpoints: breakpointsToSend.map(bp => ({ line: bp.desiredLineNumber, condition: bp.condition })), + breakpoints: breakpointsToSend.map(bp => ({ line: bp.desiredLineNumber, condition: bp.condition, hitCondition: bp.hitCondition })), sourceModified }).then(response => { if (!response || !response.body) { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index 6f43336463f..34ba1a8f8bc 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -1190,8 +1190,8 @@ export class BreakpointsRenderer implements tree.IRenderer { if (breakpoint.message) { data.breakpoint.title = breakpoint.message; } - } else if (breakpoint.condition) { - data.breakpoint.title = breakpoint.condition; + } else if (breakpoint.condition || breakpoint.hitCondition) { + data.breakpoint.title = breakpoint.condition ? breakpoint.condition : breakpoint.hitCondition; } } From 82b87c760d8cc79bdd93d4e7259310124882fe4d Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 4 Oct 2016 10:51:11 +0200 Subject: [PATCH 022/163] SelectBox --- src/vs/base/browser/ui/actionbar/actionbar.ts | 64 +++-------- .../base/browser/ui/selectBox/selectBox.css | 26 +++++ src/vs/base/browser/ui/selectBox/selectBox.ts | 103 ++++++++++++++++++ .../electron-browser/media/workbench.css | 23 +--- 4 files changed, 145 insertions(+), 71 deletions(-) create mode 100644 src/vs/base/browser/ui/selectBox/selectBox.css create mode 100644 src/vs/base/browser/ui/selectBox/selectBox.ts diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 8c6d9466041..806341ed3f6 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -10,6 +10,7 @@ import nls = require('vs/nls'); import lifecycle = require('vs/base/common/lifecycle'); import {Promise} from 'vs/base/common/winjs.base'; import {Builder, $} from 'vs/base/browser/builder'; +import {SelectBox} from 'vs/base/browser/ui/selectBox/selectBox'; import platform = require('vs/base/common/platform'); import {IAction, IActionRunner, Action, IActionChangeEvent, ActionRunner} from 'vs/base/common/actions'; import DOM = require('vs/base/browser/dom'); @@ -661,39 +662,25 @@ export class ActionBar extends EventEmitter implements IActionRunner { } export class SelectActionItem extends BaseActionItem { - private select: HTMLSelectElement; - private options: string[]; - private selected: number; + private selectBox: SelectBox; protected toDispose: lifecycle.IDisposable[]; constructor(ctx: any, action: IAction, options: string[], selected: number) { super(ctx, action); - - this.select = document.createElement('select'); - this.select.className = 'action-bar-select'; - - this.options = options; - this.selected = selected; + this.selectBox = new SelectBox(options, selected); this.toDispose = []; - + this.toDispose.push(this.selectBox); this.registerListeners(); } public setOptions(options: string[], selected: number): void { - this.options = options; - if (selected >= 0) { - this.selected = selected; - } else if (this.selected < 0 || this.selected > this.options.length) { - this.selected = 0; - } - - this.doSetOptions(); + this.selectBox.setOptions(options, selected); } private registerListeners(): void { - this.toDispose.push(DOM.addStandardDisposableListener(this.select, 'change', (e) => { - this.actionRunner.run(this._action, this.getActionContext(e.target.value)).done(); + this.toDispose.push(this.selectBox.onDidSelect(selected => { + this.actionRunner.run(this._action, this.getActionContext(selected)).done(); })); } @@ -702,50 +689,27 @@ export class SelectActionItem extends BaseActionItem { } public focus(): void { - if (this.select) { - this.select.focus(); + if (this.selectBox) { + this.selectBox.focus(); } } public set enabled(value: boolean) { - this.select.disabled = !value; + this.selectBox.enabled = value; } public blur(): void { - if (this.select) { - this.select.blur(); + if (this.selectBox) { + this.selectBox.blur(); } } public render(container: HTMLElement): void { - DOM.addClass(container, 'select-container'); - container.appendChild(this.select); - this.doSetOptions(); + this.selectBox.render(container); } protected getSelected(): string { - return this.options && this.selected >= 0 && this.selected < this.options.length ? this.options[this.selected] : null; - } - - private doSetOptions(): void { - this.select.options.length = 0; - - this.options.forEach((option) => { - this.select.add(this.createOption(option)); - }); - - if (this.selected >= 0) { - this.select.selectedIndex = this.selected; - this.select.title = this.options[this.selected]; - } - } - - private createOption(value: string): HTMLOptionElement { - let option = document.createElement('option'); - option.value = value; - option.text = value; - - return option; + return this.selectBox.getSelected(); } public dispose(): void { diff --git a/src/vs/base/browser/ui/selectBox/selectBox.css b/src/vs/base/browser/ui/selectBox/selectBox.css new file mode 100644 index 00000000000..d54fc5b05bf --- /dev/null +++ b/src/vs/base/browser/ui/selectBox/selectBox.css @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-workbench .select-box { + width: 100%; + height: 20px; +} + +.vs .monaco-workbench .select-box { + background-color: white; + border-color: #CECECE; +} + +.vs-dark .monaco-workbench .select-box { + background-color: #3C3C3C; + border-color: #3C3C3C; + color: rgb(204, 204, 204); +} + +.hc-black .monaco-workbench .select-box { + background-color: #3C3C3C; + border-color: #3C3C3C; + color: white; +} diff --git a/src/vs/base/browser/ui/selectBox/selectBox.ts b/src/vs/base/browser/ui/selectBox/selectBox.ts new file mode 100644 index 00000000000..bd08f4c1693 --- /dev/null +++ b/src/vs/base/browser/ui/selectBox/selectBox.ts @@ -0,0 +1,103 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./selectBox'; + +import {IDisposable, dispose} from 'vs/base/common/lifecycle'; +import Event, {Emitter} from 'vs/base/common/event'; +import {Widget} from 'vs/base/browser/ui/widget'; +import * as dom from 'vs/base/browser/dom'; + +export class SelectBox extends Widget { + + private select: HTMLSelectElement; + private options: string[]; + private selected: number; + private _onDidSelect: Emitter; + private toDispose: IDisposable[]; + + constructor(options: string[], selected: number) { + super(); + + this.select = document.createElement('select'); + this.select.className = 'select-box'; + + this.options = options; + this.selected = selected; + this.toDispose = []; + this._onDidSelect = new Emitter(); + + this.toDispose.push(dom.addStandardDisposableListener(this.select, 'change', (e) => { + this._onDidSelect.fire(e.target.value); + })); + } + + public get onDidSelect(): Event { + return this._onDidSelect.event; + } + + public setOptions(options: string[], selected: number): void { + this.options = options; + if (selected >= 0) { + this.selected = selected; + } else if (this.selected < 0 || this.selected > this.options.length) { + this.selected = 0; + } + + this.doSetOptions(); + } + + public focus(): void { + if (this.select) { + this.select.focus(); + } + } + + public set enabled(value: boolean) { + this.select.disabled = !value; + } + + public blur(): void { + if (this.select) { + this.select.blur(); + } + } + + public render(container: HTMLElement): void { + dom.addClass(container, 'select-container'); + container.appendChild(this.select); + this.doSetOptions(); + } + + public getSelected(): string { + return this.options && this.selected >= 0 && this.selected < this.options.length ? this.options[this.selected] : null; + } + + private doSetOptions(): void { + this.select.options.length = 0; + + this.options.forEach((option) => { + this.select.add(this.createOption(option)); + }); + + if (this.selected >= 0) { + this.select.selectedIndex = this.selected; + this.select.title = this.options[this.selected]; + } + } + + private createOption(value: string): HTMLOptionElement { + let option = document.createElement('option'); + option.value = value; + option.text = value; + + return option; + } + + public dispose(): void { + this.toDispose = dispose(this.toDispose); + super.dispose(); + } +} \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/media/workbench.css b/src/vs/workbench/electron-browser/media/workbench.css index 101ff0af2ab..805433dba10 100644 --- a/src/vs/workbench/electron-browser/media/workbench.css +++ b/src/vs/workbench/electron-browser/media/workbench.css @@ -29,13 +29,11 @@ box-sizing: border-box; } -.monaco-workbench .action-bar-select { - width: 100%; - height: 20px; +.monaco-workbench .monaco-action-bar .select-box { margin-top: 8px; /* Center the select box */ } -.monaco-workbench.windows .action-bar-select { +.monaco-workbench.windows .monaco-action-bar .select-box { margin-top: 7px; /* Center the select box */ } @@ -76,11 +74,6 @@ background-color: #E1E1E1; } -.vs .monaco-workbench .action-bar-select { - background-color: white; - border-color: #CECECE; -} - /* ---------- Dark Theme ---------- */ .vs-dark .monaco-workbench { @@ -111,12 +104,6 @@ .vs-dark .monaco-workbench .stacked-view .action-label { color: inherit; } .vs-dark .monaco-workbench .stacked-view .action-label:hover { color: #3399FF; } -.vs-dark .monaco-workbench .action-bar-select { - background-color: #3C3C3C; - border-color: #3C3C3C; - color: rgb(204, 204, 204); -} - /* ---------- HC Theme ---------- */ .hc-black .monaco-workbench { color: #FFF; background-color: #000; } @@ -136,9 +123,3 @@ .hc-black .monaco-workbench .monaco-action-bar .action-item.disabled .action-label.disabled { opacity: .4; } - -.hc-black .monaco-workbench .action-bar-select { - background-color: #3C3C3C; - border-color: #3C3C3C; - color: white; -} \ No newline at end of file From 134a1ec223e8d017a864690dfed40e76f2236de1 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 4 Oct 2016 11:39:35 +0200 Subject: [PATCH 023/163] breakpoint widget: support hit condition editing --- .../parts/debug/browser/breakpointWidget.ts | 36 +++++++++++++++---- .../debug/browser/media/breakpointWidget.css | 20 +++++++++-- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/breakpointWidget.ts b/src/vs/workbench/parts/debug/browser/breakpointWidget.ts index dc13999eeea..35354848338 100644 --- a/src/vs/workbench/parts/debug/browser/breakpointWidget.ts +++ b/src/vs/workbench/parts/debug/browser/breakpointWidget.ts @@ -9,6 +9,7 @@ import async = require('vs/base/common/async'); import errors = require('vs/base/common/errors'); import {KeyCode, KeyMod} from 'vs/base/common/keyCodes'; import platform = require('vs/base/common/platform'); +import {SelectBox} from 'vs/base/browser/ui/selectBox/selectBox'; import lifecycle = require('vs/base/common/lifecycle'); import dom = require('vs/base/browser/dom'); import {InputBox} from 'vs/base/browser/ui/inputbox/inputBox'; @@ -33,15 +34,25 @@ export class BreakpointWidget extends ZoneWidget { private inputBox: InputBox; private toDispose: lifecycle.IDisposable[]; private breakpointWidgetVisible: IContextKey; + private expressionPlaceholder: string; + private expressionAriaLabel: string; + private hitCountPlaceholder: string; + private hitCountAriaLabel: string; + private hitCountContext: boolean; constructor(editor: editorbrowser.ICodeEditor, private lineNumber: number, @IContextViewService private contextViewService: IContextViewService, @debug.IDebugService private debugService: debug.IDebugService, @IContextKeyService contextKeyService: IContextKeyService ) { - super(editor, { showFrame: true, showArrow: false }); + super(editor, { showFrame: true, showArrow: false, frameColor: '#007ACC', frameWidth: 1 }); this.toDispose = []; + this.expressionPlaceholder = nls.localize('breakpointWidgetExpressionPlaceholder', "Breakpoint on line {0} will only stop if this expression is true.", this.lineNumber); + this.expressionAriaLabel = nls.localize('breakpointWidgetAriaLabel', "Type the breakpoint condition for line {0}. The program will only stop here if this condition is true. Press Enter to accept or Escape to cancel.", this.lineNumber); + this.hitCountPlaceholder = nls.localize('breakpointWidgetHitCountPlaceholder', "Breakpoint on line {0} will only stop if the hit count condition is true.", this.lineNumber); + this.hitCountAriaLabel = nls.localize('breakpointWidgetHitCountAriaLabel', "Type the breakpoint hit count condition for line {0}. The program will only stop here if the hit count is met. Press Enter to accept or Escape to cancel.", this.lineNumber); + this.create(); this.breakpointWidgetVisible = CONTEXT_BREAKPOINT_WIDGET_VISIBLE.bindTo(contextKeyService); this.breakpointWidgetVisible.set(true); @@ -63,10 +74,19 @@ export class BreakpointWidget extends ZoneWidget { const uri = this.editor.getModel().uri; const breakpoint = this.debugService.getModel().getBreakpoints().filter(bp => bp.lineNumber === this.lineNumber && bp.source.uri.toString() === uri.toString()).pop(); + const selectBox = new SelectBox([nls.localize('expression', "Expression"), nls.localize('hitCount', "Hit Count")], 0); + selectBox.render(dom.append(container, $('.breakpoint-select-container'))); + selectBox.onDidSelect(e => { + this.hitCountContext = e === 'Hit Count'; + this.inputBox.setAriaLabel(this.hitCountContext ? this.hitCountAriaLabel : this.expressionAriaLabel); + this.inputBox.setPlaceHolder(this.hitCountContext ? this.hitCountPlaceholder : this.expressionPlaceholder); + this.inputBox.value = (this.hitCountContext && breakpoint && breakpoint.hitCondition) ? breakpoint.hitCondition : breakpoint && breakpoint.condition ? breakpoint.condition : ''; + }); + const inputBoxContainer = dom.append(container, $('.inputBoxContainer')); this.inputBox = new InputBox(inputBoxContainer, this.contextViewService, { - placeholder: nls.localize('breakpointWidgetPlaceholder', "Breakpoint on line {0} will only stop if this condition is true.", this.lineNumber), - ariaLabel: nls.localize('breakpointWidgetAriaLabel', "Type the breakpoint condition for line {0}. The program will only stop here if this condition is true. Press Enter to accept or Escape to cancel.") + placeholder: this.expressionPlaceholder, + ariaLabel: this.expressionAriaLabel }); this.toDispose.push(this.inputBox); @@ -80,12 +100,16 @@ export class BreakpointWidget extends ZoneWidget { if (!disposed) { disposed = true; if (success) { - const raw = { + const raw: debug.IRawBreakpoint = { uri, lineNumber: this.lineNumber, - enabled: true, - condition: this.inputBox.value + enabled: true }; + if (this.hitCountContext) { + raw.hitCondition = this.inputBox.value; + } else { + raw.condition = this.inputBox.value; + } // if there is already a breakpoint on this location - remove it. const oldBreakpoint = this.debugService.getModel().getBreakpoints() diff --git a/src/vs/workbench/parts/debug/browser/media/breakpointWidget.css b/src/vs/workbench/parts/debug/browser/media/breakpointWidget.css index 65c0f1f320e..0fb6516a856 100644 --- a/src/vs/workbench/parts/debug/browser/media/breakpointWidget.css +++ b/src/vs/workbench/parts/debug/browser/media/breakpointWidget.css @@ -4,9 +4,25 @@ *--------------------------------------------------------------------------------------------*/ .monaco-editor .zone-widget .zone-widget-container.breakpoint-widget { - border-top-color: #E89208; - border-bottom-color: #E89208; height: 30px !important; + display: flex; + background-color: var(--input-bgcolor); +} + +.monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .breakpoint-select-container { + display: flex; + justify-content: center; + flex-direction: column; + padding: 0 10px; +} + +.monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .breakpoint-select-container .select-box { + margin-top: 0px; + border-color: rgba(128, 128, 128, 0.35); +} + +.monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .inputBoxContainer { + flex: 1; } .monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .monaco-inputbox { From 4dd18c1c7fc6abbed74ac55c52bd729242186ff9 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 4 Oct 2016 12:00:44 +0200 Subject: [PATCH 024/163] do not unset mode from picker --- src/vs/workbench/browser/parts/editor/editorStatus.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index bf4c3ed2389..381aa926f23 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -760,6 +760,14 @@ export class ChangeModeAction extends Action { return this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickLanguage', "Select Language Mode") }).then(language => { if (language) { + + // User decided to permanently configure associations, return right after + if (language === configureModeAssociations) { + this.configureFileAssociation(fileinput.getResource()); + return; + } + + // Change mode for active editor activeEditor = this.editorService.getActiveEditor(); if (activeEditor instanceof BaseTextEditor) { const editorWidget = activeEditor.getControl(); @@ -780,8 +788,6 @@ export class ChangeModeAction extends Action { let mode: TPromise; if (language === autoDetectMode) { mode = this.modeService.getOrCreateModeByFilenameOrFirstLine(getUntitledOrFileResource(activeEditor.input, true).fsPath, textModel.getLineContent(1)); - } else if (language === configureModeAssociations) { - this.configureFileAssociation(fileinput.getResource()); } else { mode = this.modeService.getOrCreateModeByLanguageName(language.label); } From d90b865f65f003df3cc781d62d0987fad451c4b8 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 4 Oct 2016 10:52:12 +0200 Subject: [PATCH 025/163] fix huge intellisense icons --- src/vs/editor/contrib/suggest/browser/suggest.css | 12 ++++++------ .../editor/contrib/suggest/browser/suggestWidget.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggest.css b/src/vs/editor/contrib/suggest/browser/suggest.css index b1a643799ed..dced1e7bad4 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.css +++ b/src/vs/editor/contrib/suggest/browser/suggest.css @@ -18,7 +18,7 @@ transition: left .05s ease-in-out; } -.monaco-editor.mac .suggest-widget .text { +.monaco-editor.mac .suggest-widget .contents { line-height: 1.3em; } @@ -42,14 +42,14 @@ white-space: nowrap; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .text { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents { flex: 1; height: 100%; overflow: hidden; padding-left: 2px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .text > .main { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main { display: flex; overflow: hidden; text-overflow: ellipsis; @@ -92,7 +92,7 @@ color: #186B9E; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .text > .main > .type-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .type-label { display: none; margin-left: 0.8em; flex: 1; @@ -102,11 +102,11 @@ opacity: 0.7; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .text > .main > .type-label > .monaco-tokenized-source { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .type-label > .monaco-tokenized-source { display: inline; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .text > .main > .type-label { +.monaco-editor .suggest-widget .monaco-list .monaco-list-row.focused > .contents > .main > .type-label { display: inline; } diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index 5485225ff18..056c6812021 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -70,7 +70,7 @@ class Renderer implements IRenderer { data.icon = append(container, $('.icon')); data.colorspan = append(data.icon, $('span.colorspan')); - const text = append(container, $('.text')); + const text = append(container, $('.contents')); const main = append(text, $('.main')); data.highlightedLabel = new HighlightedLabel(main); data.disposables.push(data.highlightedLabel); From c77820351cb80cca1201a44c54e8ebb050fbc370 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 4 Oct 2016 10:53:55 +0200 Subject: [PATCH 026/163] fixes #12847 --- src/vs/editor/contrib/suggest/browser/suggest.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/editor/contrib/suggest/browser/suggest.css b/src/vs/editor/contrib/suggest/browser/suggest.css index dced1e7bad4..24890d9dee5 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.css +++ b/src/vs/editor/contrib/suggest/browser/suggest.css @@ -164,6 +164,7 @@ box-sizing: border-box; display: flex; flex-direction: column; + cursor: default; } .monaco-editor .suggest-widget .details > .header { From fcf008f4a28e1e424f530cc556a4e91328371352 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 4 Oct 2016 10:54:56 +0200 Subject: [PATCH 027/163] remove mac overwrite --- src/vs/editor/contrib/suggest/browser/suggest.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggest.css b/src/vs/editor/contrib/suggest/browser/suggest.css index 24890d9dee5..74ba1aed106 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.css +++ b/src/vs/editor/contrib/suggest/browser/suggest.css @@ -18,10 +18,6 @@ transition: left .05s ease-in-out; } -.monaco-editor.mac .suggest-widget .contents { - line-height: 1.3em; -} - .monaco-editor .suggest-widget > .message { padding-left: 22px; opacity: 0.7; From 6c0b455f9df2daa5bd46bfd4dd835cc748c39752 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 4 Oct 2016 11:21:45 +0200 Subject: [PATCH 028/163] fixes #12859 --- src/vs/editor/contrib/suggest/browser/suggest.css | 13 +++++++------ .../editor/contrib/suggest/browser/suggestWidget.ts | 12 +++++++++--- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggest.css b/src/vs/editor/contrib/suggest/browser/suggest.css index 74ba1aed106..acbf3bdf3dd 100644 --- a/src/vs/editor/contrib/suggest/browser/suggest.css +++ b/src/vs/editor/contrib/suggest/browser/suggest.css @@ -64,14 +64,17 @@ opacity: 0.85; } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .docs > .docs-text.no-docs { + opacity: 0.5; + font-style: italic; +} + .monaco-editor .suggest-widget .monaco-list .monaco-list-row .docs > .docs-details { opacity: 0.6; - width: 14px; - height: 14px; background-image: url('./info.svg'); - background-size: 14px; background-position: center center; background-repeat: no-repeat; + background-size: 70%; } .monaco-editor .suggest-widget .details > .header > .go-back, @@ -177,10 +180,8 @@ .monaco-editor .suggest-widget .details > .header > .go-back { cursor: pointer; opacity: 0.6; - width: 14px; - height: 14px; background-image: url('./back.svg'); - background-size: 14px; + background-size: 70%; background-position: center center; background-repeat: no-repeat; } diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index 056c6812021..c60fd75c168 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -83,12 +83,15 @@ class Renderer implements IRenderer { const configureFont = () => { const fontInfo = this.editor.getConfiguration().fontInfo; + const lineHeight = `${ fontInfo.lineHeight }px`; data.root.style.fontSize = `${ fontInfo.fontSize }px`; main.style.fontFamily = fontInfo.fontFamily; - main.style.lineHeight = `${ fontInfo.lineHeight }px`; - data.icon.style.height = `${ fontInfo.lineHeight }px`; - data.icon.style.width = `${ fontInfo.lineHeight }px`; + main.style.lineHeight = lineHeight; + data.icon.style.height = lineHeight; + data.icon.style.width = lineHeight; + data.documentationDetails.style.height = lineHeight; + data.documentationDetails.style.width = lineHeight; }; configureFont(); @@ -261,10 +264,13 @@ class SuggestionDetails { private configureFont() { const fontInfo = this.editor.getConfiguration().fontInfo; const fontSize = `${ fontInfo.fontSize }px`; + const lineHeight = `${ fontInfo.lineHeight }px`; this.el.style.fontSize = fontSize; this.title.style.fontFamily = fontInfo.fontFamily; this.type.style.fontFamily = fontInfo.fontFamily; + this.back.style.height = lineHeight; + this.back.style.width = lineHeight; } dispose(): void { From 60211895c769abe55303a3dccec889d20c0f1a69 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 4 Oct 2016 12:10:33 +0200 Subject: [PATCH 029/163] fixes #2465 --- .../common/config/commonEditorConfig.ts | 14 ++++++ src/vs/editor/common/config/defaultConfig.ts | 2 + src/vs/editor/common/editorCommon.ts | 18 +++++++ .../contrib/suggest/browser/suggestWidget.ts | 47 +++++++++++-------- src/vs/monaco.d.ts | 12 +++++ 5 files changed, 73 insertions(+), 20 deletions(-) diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index efcc0815166..b51b3200971 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -312,6 +312,8 @@ class InternalEditorOptionsHelper { snippetSuggestions: opts.snippetSuggestions, tabCompletion: opts.tabCompletion, wordBasedSuggestions: opts.wordBasedSuggestions, + suggestFontSize: opts.suggestFontSize, + suggestLineHeight: opts.suggestLineHeight, selectionHighlight: toBoolean(opts.selectionHighlight), codeLens: opts.referenceInfos && opts.codeLens, folding: toBoolean(opts.folding), @@ -765,6 +767,18 @@ let editorConfiguration:IConfigurationNode = { 'default': DefaultConfig.editor.wordBasedSuggestions, 'description': nls.localize('wordBasedSuggestions', "Enable word based suggestions.") }, + 'editor.suggestFontSize' : { + 'type': 'integer', + 'default': 0, + 'minimum': 0, + 'description': nls.localize('suggestFontSize', "Font size for the suggest widget") + }, + 'editor.suggestLineHeight' : { + 'type': 'integer', + 'default': 0, + 'minimum': 0, + 'description': nls.localize('suggestLineHeight', "Line height for the suggest widget") + }, 'editor.tabCompletion': { 'type': 'boolean', 'default': DefaultConfig.editor.tabCompletion, diff --git a/src/vs/editor/common/config/defaultConfig.ts b/src/vs/editor/common/config/defaultConfig.ts index 5d9d2cefa14..01548d9f34c 100644 --- a/src/vs/editor/common/config/defaultConfig.ts +++ b/src/vs/editor/common/config/defaultConfig.ts @@ -87,6 +87,8 @@ class ConfigClass implements IConfiguration { snippetSuggestions: 'bottom', tabCompletion: false, wordBasedSuggestions: true, + suggestFontSize: 0, + suggestLineHeight: 0, selectionHighlight: true, codeLens: true, referenceInfos: true, diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index f64c674ec54..e892b495887 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -410,6 +410,16 @@ export interface IEditorOptions { * Enable word based suggestions. Defaults to 'true' */ wordBasedSuggestions?: boolean; + /** + * The font size for the suggest widget. + * Defaults to the editor font size. + */ + suggestFontSize?: number; + /** + * The line height for the suggest widget. + * Defaults to the editor line height. + */ + suggestLineHeight?: number; /** * Enable selection highlight. * Defaults to true. @@ -854,6 +864,8 @@ export class EditorContribOptions { snippetSuggestions: 'top' | 'bottom' | 'inline' | 'none'; tabCompletion: boolean; wordBasedSuggestions: boolean; + suggestFontSize: number; + suggestLineHeight: number; selectionHighlight:boolean; codeLens: boolean; folding: boolean; @@ -875,6 +887,8 @@ export class EditorContribOptions { snippetSuggestions: 'top' | 'bottom' | 'inline' | 'none'; tabCompletion: boolean; wordBasedSuggestions: boolean; + suggestFontSize: number; + suggestLineHeight: number; selectionHighlight:boolean; codeLens: boolean; folding: boolean; @@ -892,6 +906,8 @@ export class EditorContribOptions { this.snippetSuggestions = source.snippetSuggestions; this.tabCompletion = source.tabCompletion; this.wordBasedSuggestions = source.wordBasedSuggestions; + this.suggestFontSize = source.suggestFontSize; + this.suggestLineHeight = source.suggestLineHeight; this.selectionHighlight = Boolean(source.selectionHighlight); this.codeLens = Boolean(source.codeLens); this.folding = Boolean(source.folding); @@ -915,6 +931,8 @@ export class EditorContribOptions { && this.snippetSuggestions === other.snippetSuggestions && this.tabCompletion === other.tabCompletion && this.wordBasedSuggestions === other.wordBasedSuggestions + && this.suggestFontSize === other.suggestFontSize + && this.suggestLineHeight === other.suggestLineHeight && this.selectionHighlight === other.selectionHighlight && this.codeLens === other.codeLens && this.folding === other.folding diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index c60fd75c168..588f7aaf3a8 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -82,22 +82,26 @@ class Renderer implements IRenderer { data.documentationDetails.title = nls.localize('readMore', "Read More...{0}", this.triggerKeybindingLabel); const configureFont = () => { - const fontInfo = this.editor.getConfiguration().fontInfo; - const lineHeight = `${ fontInfo.lineHeight }px`; + const configuration = this.editor.getConfiguration(); + const fontFamily = configuration.fontInfo.fontFamily; + const fontSize = configuration.contribInfo.suggestFontSize || configuration.fontInfo.fontSize; + const lineHeight = configuration.contribInfo.suggestLineHeight || configuration.fontInfo.lineHeight; + const fontSizePx = `${ fontSize }px`; + const lineHeightPx = `${ lineHeight }px`; - data.root.style.fontSize = `${ fontInfo.fontSize }px`; - main.style.fontFamily = fontInfo.fontFamily; - main.style.lineHeight = lineHeight; - data.icon.style.height = lineHeight; - data.icon.style.width = lineHeight; - data.documentationDetails.style.height = lineHeight; - data.documentationDetails.style.width = lineHeight; + data.root.style.fontSize = fontSizePx; + main.style.fontFamily = fontFamily; + main.style.lineHeight = lineHeightPx; + data.icon.style.height = lineHeightPx; + data.icon.style.width = lineHeightPx; + data.documentationDetails.style.height = lineHeightPx; + data.documentationDetails.style.width = lineHeightPx; }; configureFont(); chain(this.editor.onDidChangeConfiguration.bind(this.editor)) - .filter(e => e.fontInfo) + .filter(e => e.fontInfo || e.contribInfo) .on(configureFont, null, data.disposables); return data; @@ -262,15 +266,18 @@ class SuggestionDetails { } private configureFont() { - const fontInfo = this.editor.getConfiguration().fontInfo; - const fontSize = `${ fontInfo.fontSize }px`; - const lineHeight = `${ fontInfo.lineHeight }px`; + const configuration = this.editor.getConfiguration(); + const fontFamily = configuration.fontInfo.fontFamily; + const fontSize = configuration.contribInfo.suggestFontSize || configuration.fontInfo.fontSize; + const lineHeight = configuration.contribInfo.suggestLineHeight || configuration.fontInfo.lineHeight; + const fontSizePx = `${ fontSize }px`; + const lineHeightPx = `${ lineHeight }px`; - this.el.style.fontSize = fontSize; - this.title.style.fontFamily = fontInfo.fontFamily; - this.type.style.fontFamily = fontInfo.fontFamily; - this.back.style.height = lineHeight; - this.back.style.width = lineHeight; + this.el.style.fontSize = fontSizePx; + this.title.style.fontFamily = fontFamily; + this.type.style.fontFamily = fontFamily; + this.back.style.height = lineHeightPx; + this.back.style.width = lineHeightPx; } dispose(): void { @@ -754,8 +761,8 @@ export class SuggestWidget implements IContentWidget, IDelegate } private get unfocusedHeight(): number { - const fontInfo = this.editor.getConfiguration().fontInfo; - return fontInfo.lineHeight; + const configuration = this.editor.getConfiguration(); + return configuration.contribInfo.suggestLineHeight || configuration.fontInfo.lineHeight; } // IDelegate diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 755ddd32afd..a53abe82de2 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -1273,6 +1273,16 @@ declare module monaco.editor { * Enable word based suggestions. Defaults to 'true' */ wordBasedSuggestions?: boolean; + /** + * The font size for the suggest widget. + * Defaults to the editor font size. + */ + suggestFontSize?: number; + /** + * The line height for the suggest widget. + * Defaults to the editor line height. + */ + suggestLineHeight?: number; /** * Enable selection highlight. * Defaults to true. @@ -1453,6 +1463,8 @@ declare module monaco.editor { snippetSuggestions: 'top' | 'bottom' | 'inline' | 'none'; tabCompletion: boolean; wordBasedSuggestions: boolean; + suggestFontSize: number; + suggestLineHeight: number; selectionHighlight: boolean; codeLens: boolean; folding: boolean; From 7e1a77429de4f98b15a20b5486601e6299eeb4ae Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 4 Oct 2016 12:12:39 +0200 Subject: [PATCH 030/163] let => const --- .../browser/parts/editor/baseEditor.ts | 50 +++++++++---------- .../browser/parts/editor/binaryDiffEditor.ts | 22 ++++---- .../browser/parts/editor/binaryEditor.ts | 8 +-- .../parts/editor/editor.contribution.ts | 6 +-- .../browser/parts/editor/editorPicker.ts | 4 +- .../browser/parts/editor/stringEditor.ts | 30 +++++------ .../browser/parts/editor/textDiffEditor.ts | 44 ++++++++-------- 7 files changed, 82 insertions(+), 82 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/baseEditor.ts b/src/vs/workbench/browser/parts/editor/baseEditor.ts index 4dbbf9578dc..9918792ef8b 100644 --- a/src/vs/workbench/browser/parts/editor/baseEditor.ts +++ b/src/vs/workbench/browser/parts/editor/baseEditor.ts @@ -86,7 +86,7 @@ export abstract class BaseEditor extends Panel implements IEditor { public create(parent: Builder): void; // create is sync for editors public create(parent: Builder): TPromise; public create(parent: Builder): TPromise { - let res = super.create(parent); + const res = super.create(parent); // Create Editor this.createEditor(parent); @@ -105,7 +105,7 @@ export abstract class BaseEditor extends Panel implements IEditor { public setVisible(visible: boolean, position?: Position): void; // setVisible is sync for editors public setVisible(visible: boolean, position?: Position): TPromise; public setVisible(visible: boolean, position: Position = null): TPromise { - let promise = super.setVisible(visible); + const promise = super.setVisible(visible); // Propagate to Editor this.setEditorVisible(visible, position); @@ -185,7 +185,7 @@ class EditorRegistry implements IEditorRegistry { this.instantiationService = service; for (let key in this.editorInputFactoryConstructors) { - let element = this.editorInputFactoryConstructors[key]; + const element = this.editorInputFactoryConstructors[key]; this.createEditorInputFactory(key, element); } @@ -193,7 +193,7 @@ class EditorRegistry implements IEditorRegistry { } private createEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0): void { - let instance = this.instantiationService.createInstance(ctor); + const instance = this.instantiationService.createInstance(ctor); this.editorInputFactoryInstances[editorInputId] = instance; } @@ -215,14 +215,14 @@ class EditorRegistry implements IEditorRegistry { } public getEditor(input: EditorInput): EditorDescriptor { - let findEditorDescriptors = (input: EditorInput, byInstanceOf?: boolean): EditorDescriptor[]=> { - let matchingDescriptors: EditorDescriptor[] = []; + const findEditorDescriptors = (input: EditorInput, byInstanceOf?: boolean): EditorDescriptor[]=> { + const matchingDescriptors: EditorDescriptor[] = []; for (let i = 0; i < this.editors.length; i++) { - let editor = this.editors[i]; - let inputDescriptors = []>editor[INPUT_DESCRIPTORS_PROPERTY]; + const editor = this.editors[i]; + const inputDescriptors = []>editor[INPUT_DESCRIPTORS_PROPERTY]; for (let j = 0; j < inputDescriptors.length; j++) { - let inputClass = inputDescriptors[j].ctor; + const inputClass = inputDescriptors[j].ctor; // Direct check on constructor type (ignores prototype chain) if (!byInstanceOf && (input).constructor === inputClass) { @@ -250,11 +250,11 @@ class EditorRegistry implements IEditorRegistry { return matchingDescriptors; }; - let descriptors = findEditorDescriptors(input); + const descriptors = findEditorDescriptors(input); if (descriptors && descriptors.length > 0) { // Ask the input for its preferred Editor - let preferredEditorId = input.getPreferredEditorId(descriptors.map(d => d.getId())); + const preferredEditorId = input.getPreferredEditorId(descriptors.map(d => d.getId())); if (preferredEditorId) { return this.getEditorById(preferredEditorId); } @@ -268,7 +268,7 @@ class EditorRegistry implements IEditorRegistry { public getEditorById(editorId: string): EditorDescriptor { for (let i = 0; i < this.editors.length; i++) { - let editor = this.editors[i]; + const editor = this.editors[i]; if (editor.getId() === editorId) { return editor; } @@ -286,10 +286,10 @@ class EditorRegistry implements IEditorRegistry { } public getEditorInputs(): any[] { - let inputClasses: any[] = []; + const inputClasses: any[] = []; for (let i = 0; i < this.editors.length; i++) { - let editor = this.editors[i]; - let editorInputDescriptors = []>editor[INPUT_DESCRIPTORS_PROPERTY]; + const editor = this.editors[i]; + const editorInputDescriptors = []>editor[INPUT_DESCRIPTORS_PROPERTY]; inputClasses.push(...editorInputDescriptors.map(descriptor=> descriptor.ctor)); } @@ -346,7 +346,7 @@ export class EditorInputActionContributor extends ActionBarContributor { } private createPositionArray(): any[] { - let array: any[] = []; + const array: any[] = []; for (let i = 0; i < POSITIONS.length; i++) { array[i] = {}; @@ -371,7 +371,7 @@ export class EditorInputActionContributor extends ActionBarContributor { private doClearInputsFromCache(cache: { [id: string]: IEditorInputAction[] }): void { for (let key in cache) { if (cache.hasOwnProperty(key)) { - let cachedActions = cache[key]; + const cachedActions = cache[key]; cachedActions.forEach((action) => { action.input = null; action.position = null; @@ -412,9 +412,9 @@ export class EditorInputActionContributor extends ActionBarContributor { this.clearInputsFromCache(context.position, true /* primary actions */); // First consult cache - let editorInput = context.input; - let editorPosition = context.position; - let cachedActions = this.mapEditorInputActionContextToPrimaryActions[context.position][this.toId(context)]; + const editorInput = context.input; + const editorPosition = context.position; + const cachedActions = this.mapEditorInputActionContextToPrimaryActions[context.position][this.toId(context)]; if (cachedActions) { // Update the input field and position in all actions to indicate this change and return @@ -427,7 +427,7 @@ export class EditorInputActionContributor extends ActionBarContributor { } // Otherwise collect and keep in cache - let actions = this.getActionsForEditorInput(context); + const actions = this.getActionsForEditorInput(context); actions.forEach((action) => { action.input = editorInput; action.position = editorPosition; @@ -470,9 +470,9 @@ export class EditorInputActionContributor extends ActionBarContributor { this.clearInputsFromCache(context.position, false /* secondary actions */); // First consult cache - let editorInput = context.input; - let editorPosition = context.position; - let cachedActions = this.mapEditorInputActionContextToSecondaryActions[context.position][this.toId(context)]; + const editorInput = context.input; + const editorPosition = context.position; + const cachedActions = this.mapEditorInputActionContextToSecondaryActions[context.position][this.toId(context)]; if (cachedActions) { // Update the input field and position in all actions to indicate this change and return @@ -485,7 +485,7 @@ export class EditorInputActionContributor extends ActionBarContributor { } // Otherwise collect and keep in cache - let actions = this.getSecondaryActionsForEditorInput(context); + const actions = this.getSecondaryActionsForEditorInput(context); actions.forEach((action) => { action.input = editorInput; action.position = editorPosition; diff --git a/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts b/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts index 79fb82d8288..e406a24e3b3 100644 --- a/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts @@ -64,7 +64,7 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas public createEditor(parent: Builder): void { // Left Container for Binary - let leftBinaryContainerElement = document.createElement('div'); + const leftBinaryContainerElement = document.createElement('div'); leftBinaryContainerElement.className = 'binary-container'; this.leftBinaryContainer = $(leftBinaryContainerElement); this.leftBinaryContainer.tabindex(0); // enable focus support from the editor part (do not remove) @@ -82,7 +82,7 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas this.sash.addListener2('reset', () => this.onSashReset()); // Right Container for Binary - let rightBinaryContainerElement = document.createElement('div'); + const rightBinaryContainerElement = document.createElement('div'); rightBinaryContainerElement.className = 'binary-container'; this.rightBinaryContainer = $(rightBinaryContainerElement); this.rightBinaryContainer.tabindex(0); // enable focus support from the editor part (do not remove) @@ -94,11 +94,11 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas } public setInput(input: EditorInput, options: EditorOptions): TPromise { - let oldInput = this.getInput(); + const oldInput = this.getInput(); super.setInput(input, options); // Detect options - let forceOpen = options && options.forceOpen; + const forceOpen = options && options.forceOpen; // Same Input if (!forceOpen && input.matches(oldInput)) { @@ -119,11 +119,11 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas } // Render original - let original = resolvedModel.originalModel; + const original = resolvedModel.originalModel; this.renderInput(original.getName(), original.getResource(), original.getSize(), original.getETag(), true); // Render modified - let modified = resolvedModel.modifiedModel; + const modified = resolvedModel.modifiedModel; this.renderInput(modified.getName(), modified.getResource(), modified.getSize(), modified.getETag(), false); }); } @@ -138,8 +138,8 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas } // Pass to ResourceViewer - let container = isOriginal ? this.leftBinaryContainer : this.rightBinaryContainer; - let scrollbar = isOriginal ? this.leftScrollbar : this.rightScrollbar; + const container = isOriginal ? this.leftBinaryContainer : this.rightBinaryContainer; + const scrollbar = isOriginal ? this.leftScrollbar : this.rightScrollbar; ResourceViewer.show({ name, resource, size, etag }, container, scrollbar, (meta) => this.handleMetadataChanged(meta, isOriginal)); } @@ -172,14 +172,14 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas } public layout(dimension: Dimension): void { - let oldDimension = this.dimension; + const oldDimension = this.dimension; this.dimension = dimension; // Calculate left hand container width based on sash move or fallback to 50% by default if (!this.leftContainerWidth || !oldDimension) { this.leftContainerWidth = this.dimension.width / 2; } else { - let sashRatio = this.leftContainerWidth / oldDimension.width; + const sashRatio = this.leftContainerWidth / oldDimension.width; this.leftContainerWidth = this.dimension.width * sashRatio; } @@ -208,7 +208,7 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas private onSashDrag(e: ISashEvent): void { // Update Widths and keep in bounds of MIN_CONTAINER_WIDTH for both sides - let newLeftContainerWidth = this.startLeftContainerWidth + e.currentX - e.startX; + const newLeftContainerWidth = this.startLeftContainerWidth + e.currentX - e.startX; this.leftContainerWidth = Math.max(BinaryResourceDiffEditor.MIN_CONTAINER_WIDTH, newLeftContainerWidth); if (this.dimension.width - this.leftContainerWidth < BinaryResourceDiffEditor.MIN_CONTAINER_WIDTH) { this.leftContainerWidth = this.dimension.width - BinaryResourceDiffEditor.MIN_CONTAINER_WIDTH; diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index dc60e1108dd..42c50fcd567 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -49,7 +49,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { public createEditor(parent: Builder): void { // Container for Binary - let binaryContainerElement = document.createElement('div'); + const binaryContainerElement = document.createElement('div'); binaryContainerElement.className = 'binary-container'; this.binaryContainer = $(binaryContainerElement); this.binaryContainer.tabindex(0); // enable focus support from the editor part (do not remove) @@ -60,11 +60,11 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { } public setInput(input: EditorInput, options: EditorOptions): TPromise { - let oldInput = this.getInput(); + const oldInput = this.getInput(); super.setInput(input, options); // Detect options - let forceOpen = options && options.forceOpen; + const forceOpen = options && options.forceOpen; // Same Input if (!forceOpen && input.matches(oldInput)) { @@ -85,7 +85,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { } // Render Input - let model = resolvedModel; + const model = resolvedModel; ResourceViewer.show({ name: model.getName(), resource: model.getResource(), size: model.getSize(), etag: model.getETag() }, this.binaryContainer, this.scrollbar, (meta) => this.handleMetadataChanged(meta)); return TPromise.as(null); diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 536fe9573fe..0e7a4f6409e 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -95,15 +95,15 @@ export class QuickOpenActionContributor extends ActionBarContributor { } public hasActions(context: any): boolean { - let entry = this.getEntry(context); + const entry = this.getEntry(context); return !!entry; } public getActions(context: any): IAction[] { - let actions: Action[] = []; + const actions: Action[] = []; - let entry = this.getEntry(context); + const entry = this.getEntry(context); if (entry) { if (!this.openToSideActionInstance) { this.openToSideActionInstance = this.instantiationService.createInstance(OpenToSideAction); diff --git a/src/vs/workbench/browser/parts/editor/editorPicker.ts b/src/vs/workbench/browser/parts/editor/editorPicker.ts index 2f65018a3db..81a96b9627f 100644 --- a/src/vs/workbench/browser/parts/editor/editorPicker.ts +++ b/src/vs/workbench/browser/parts/editor/editorPicker.ts @@ -120,8 +120,8 @@ export abstract class BaseEditorPicker extends QuickOpenHandler { return true; } - let resource = e.getResource(); - let targetToMatch = resource ? labels.getPathLabel(e.getResource(), this.contextService) : e.getLabel(); + const resource = e.getResource(); + const targetToMatch = resource ? labels.getPathLabel(e.getResource(), this.contextService) : e.getLabel(); if (!scorer.matches(targetToMatch, normalizedSearchValueLowercase)) { return false; } diff --git a/src/vs/workbench/browser/parts/editor/stringEditor.ts b/src/vs/workbench/browser/parts/editor/stringEditor.ts index d996aef7eed..948fa455160 100644 --- a/src/vs/workbench/browser/parts/editor/stringEditor.ts +++ b/src/vs/workbench/browser/parts/editor/stringEditor.ts @@ -69,17 +69,17 @@ export class StringEditor extends BaseTextEditor { } public setInput(input: EditorInput, options: EditorOptions): TPromise { - let oldInput = this.getInput(); + const oldInput = this.getInput(); super.setInput(input, options); // Detect options - let forceOpen = options && options.forceOpen; + const forceOpen = options && options.forceOpen; // Same Input if (!forceOpen && input.matches(oldInput)) { // TextOptions (avoiding instanceof here for a reason, do not change!) - let textOptions = options; + const textOptions = options; if (textOptions && types.isFunction(textOptions.apply)) { textOptions.apply(this.getControl()); } @@ -106,20 +106,20 @@ export class StringEditor extends BaseTextEditor { } // Set Editor Model - let textEditor = this.getControl(); - let textEditorModel = (resolvedModel).textEditorModel; + const textEditor = this.getControl(); + const textEditorModel = (resolvedModel).textEditorModel; textEditor.setModel(textEditorModel); // Apply Options from TextOptions let optionsGotApplied = false; - let textOptions = options; + const textOptions = options; if (textOptions && types.isFunction(textOptions.apply)) { optionsGotApplied = textOptions.apply(textEditor); } // Otherwise restore View State if (!optionsGotApplied && input instanceof UntitledEditorInput) { - let viewState = this.mapResourceToEditorViewState[input.getResource().toString()]; + const viewState = this.mapResourceToEditorViewState[input.getResource().toString()]; if (viewState) { textEditor.restoreViewState(viewState); } @@ -131,16 +131,16 @@ export class StringEditor extends BaseTextEditor { } protected getCodeEditorOptions(): IEditorOptions { - let options = super.getCodeEditorOptions(); + const options = super.getCodeEditorOptions(); - let input = this.getInput(); - let isUntitled = input instanceof UntitledEditorInput; - let isReadonly = !isUntitled; // all string editors are readonly except for the untitled one + const input = this.getInput(); + const isUntitled = input instanceof UntitledEditorInput; + const isReadonly = !isUntitled; // all string editors are readonly except for the untitled one options.readOnly = isReadonly; let ariaLabel: string; - let inputName = input && input.getName(); + const inputName = input && input.getName(); if (isReadonly) { ariaLabel = inputName ? nls.localize('readonlyEditorWithInputAriaLabel', "{0}. Readonly text editor.", inputName) : nls.localize('readonlyEditorAriaLabel', "Readonly text editor."); } else { @@ -157,12 +157,12 @@ export class StringEditor extends BaseTextEditor { * If smart reveal is true will only reveal the last line if the line before last is visible #3351 */ public revealLastLine(smartReveal = false): void { - let codeEditor = this.getControl(); - let model = codeEditor.getModel(); + const codeEditor = this.getControl(); + const model = codeEditor.getModel(); const lineBeforeLastRevealed = codeEditor.getScrollTop() + codeEditor.getLayoutInfo().height >= codeEditor.getScrollHeight(); if (model && (!smartReveal || lineBeforeLastRevealed)) { - let lastLine = model.getLineCount(); + const lastLine = model.getLineCount(); codeEditor.revealLine(lastLine); } } diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 219940bf448..8e219979834 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -84,11 +84,11 @@ export class TextDiffEditor extends BaseTextEditor { this.previousDiffAction = new NavigateAction(this, false); // Support navigation within the diff editor by overriding the editor service within - let delegatingEditorService = this.instantiationService.createInstance(DelegatingWorkbenchEditorService, (input: EditorInput, options?: EditorOptions, arg3?: any) => { + const delegatingEditorService = this.instantiationService.createInstance(DelegatingWorkbenchEditorService, (input: EditorInput, options?: EditorOptions, arg3?: any) => { // Check if arg4 is a position argument that differs from this editors position if (types.isUndefinedOrNull(arg3) || arg3 === false || arg3 === this.position) { - let activeDiffInput = this.getInput(); + const activeDiffInput = this.getInput(); if (input && options && activeDiffInput) { // Input matches modified side of the diff editor: perform the action on modified side @@ -98,7 +98,7 @@ export class TextDiffEditor extends BaseTextEditor { // Input matches original side of the diff editor: perform the action on original side else if (input.matches(activeDiffInput.originalInput)) { - let originalEditor = this.getControl().getOriginalEditor(); + const originalEditor = this.getControl().getOriginalEditor(); if (options instanceof TextEditorOptions) { (options).apply(originalEditor); @@ -112,23 +112,23 @@ export class TextDiffEditor extends BaseTextEditor { }); // Create a special child of instantiator that will delegate all calls to openEditor() to the same diff editor if the input matches with the modified one - let diffEditorInstantiator = this.instantiationService.createChild(new ServiceCollection([IWorkbenchEditorService, delegatingEditorService])); + const diffEditorInstantiator = this.instantiationService.createChild(new ServiceCollection([IWorkbenchEditorService, delegatingEditorService])); return diffEditorInstantiator.createInstance(DiffEditorWidget, parent.getHTMLElement(), this.getCodeEditorOptions()); } public setInput(input: EditorInput, options: EditorOptions): TPromise { - let oldInput = this.getInput(); + const oldInput = this.getInput(); super.setInput(input, options); // Detect options - let forceOpen = options && options.forceOpen; + const forceOpen = options && options.forceOpen; // Same Input if (!forceOpen && input.matches(oldInput)) { // TextOptions (avoiding instanceof here for a reason, do not change!) - let textOptions = options; + const textOptions = options; if (textOptions && types.isFunction(textOptions.apply)) { textOptions.apply(this.getControl()); } @@ -155,13 +155,13 @@ export class TextDiffEditor extends BaseTextEditor { } // Editor - let diffEditor = this.getControl(); + const diffEditor = this.getControl(); diffEditor.setModel((resolvedModel).textDiffEditorModel); // Respect text diff editor options let autoRevealFirstChange = true; if (options instanceof TextDiffEditorOptions) { - let textDiffOptions = (options); + const textDiffOptions = (options); autoRevealFirstChange = !types.isUndefinedOrNull(textDiffOptions.autoRevealFirstChange) ? textDiffOptions.autoRevealFirstChange : autoRevealFirstChange; } @@ -195,10 +195,10 @@ export class TextDiffEditor extends BaseTextEditor { private openAsBinary(input: EditorInput, options: EditorOptions): boolean { if (input instanceof DiffEditorInput) { - let originalInput = input.originalInput; - let modifiedInput = input.modifiedInput; + const originalInput = input.originalInput; + const modifiedInput = input.modifiedInput; - let binaryDiffInput = new DiffEditorInput(input.getName(), input.getDescription(), originalInput, modifiedInput, true); + const binaryDiffInput = new DiffEditorInput(input.getName(), input.getDescription(), originalInput, modifiedInput, true); this.editorService.openEditor(binaryDiffInput, options, this.position).done(null, onUnexpectedError); @@ -209,17 +209,17 @@ export class TextDiffEditor extends BaseTextEditor { } protected getCodeEditorOptions(): IEditorOptions { - let options: IDiffEditorOptions = super.getCodeEditorOptions(); + const options: IDiffEditorOptions = super.getCodeEditorOptions(); - let input = this.input; + const input = this.input; if (input instanceof DiffEditorInput) { - let modifiedInput = input.modifiedInput; - let readOnly = modifiedInput instanceof StringEditorInput || modifiedInput instanceof ResourceEditorInput; + const modifiedInput = input.modifiedInput; + const readOnly = modifiedInput instanceof StringEditorInput || modifiedInput instanceof ResourceEditorInput; options.readOnly = readOnly; let ariaLabel: string; - let inputName = input && input.getName(); + const inputName = input && input.getName(); if (readOnly) { ariaLabel = inputName ? nls.localize('readonlyEditorWithInputAriaLabel', "{0}. Readonly text compare editor.", inputName) : nls.localize('readonlyEditorAriaLabel', "Readonly text compare editor."); } else { @@ -236,7 +236,7 @@ export class TextDiffEditor extends BaseTextEditor { private isFileBinaryError(error: Error): boolean; private isFileBinaryError(error: any): boolean { if (types.isArray(error)) { - let errors = error; + const errors = error; return errors.some((e) => this.isFileBinaryError(e)); } @@ -275,16 +275,16 @@ export class TextDiffEditor extends BaseTextEditor { } public getSecondaryActions(): IAction[] { - let actions = super.getSecondaryActions(); + const actions = super.getSecondaryActions(); const control = this.getControl(); let inlineModeActive = control && !control.renderSideBySide; - let inlineLabel = nls.localize('inlineDiffLabel', "Switch to Inline View"); - let sideBySideLabel = nls.localize('sideBySideDiffLabel', "Switch to Side by Side View"); + const inlineLabel = nls.localize('inlineDiffLabel', "Switch to Inline View"); + const sideBySideLabel = nls.localize('sideBySideDiffLabel', "Switch to Side by Side View"); // Action to toggle editor mode from inline to side by side - let toggleEditorModeAction = new Action('toggle.diff.editorMode', inlineModeActive ? sideBySideLabel : inlineLabel, null, true, () => { + const toggleEditorModeAction = new Action('toggle.diff.editorMode', inlineModeActive ? sideBySideLabel : inlineLabel, null, true, () => { this.getControl().updateOptions({ renderSideBySide: inlineModeActive }); From 0af52604e57d02412e41b452c5faaf0467477367 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 4 Oct 2016 12:21:35 +0200 Subject: [PATCH 031/163] distro related to #11722 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2169f9baa15..b1a20925add 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "code-oss-dev", "version": "1.6.0", "electronVersion": "1.3.7", - "distro": "7542725e6f4b1bb0cfe791f513e8819600edaefd", + "distro": "b1e023235579beebbb3cc127676cc91cc7f3e823", "author": { "name": "Microsoft Corporation" }, From d1023ee91894e9c6a2c73c7b92ff68da3f8fdc7d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 4 Oct 2016 12:37:41 +0200 Subject: [PATCH 032/163] debt: no more mime in editor service --- src/vs/platform/editor/common/editor.ts | 5 ----- .../files/browser/editors/textFileEditor.ts | 3 +-- .../parts/files/browser/fileActions.ts | 20 ++----------------- .../parts/files/browser/views/explorerView.ts | 2 +- .../files/browser/views/explorerViewer.ts | 2 +- .../files/common/editors/fileEditorTracker.ts | 7 +++---- .../git/browser/gitActions.contribution.ts | 1 - .../workbench/parts/git/browser/gitActions.ts | 2 -- .../services/editor/browser/editorService.ts | 8 ++++---- .../workbench/test/browser/services.test.ts | 5 ++--- 10 files changed, 14 insertions(+), 41 deletions(-) diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index 897923795c7..9b7cc2e9f5e 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -52,11 +52,6 @@ export interface IResourceInput { */ resource: URI; - /** - * The mime type of the text input if known. - */ - mime?: string; - /** * The encoding of the text input if known. */ diff --git a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts index 8700eb3f7b2..e3f87ff280a 100644 --- a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts @@ -8,7 +8,7 @@ import {TPromise} from 'vs/base/common/winjs.base'; import nls = require('vs/nls'); import errors = require('vs/base/common/errors'); import {toErrorMessage} from 'vs/base/common/errorMessage'; -import {MIME_BINARY, MIME_TEXT} from 'vs/base/common/mime'; +import {MIME_BINARY} from 'vs/base/common/mime'; import types = require('vs/base/common/types'); import paths = require('vs/base/common/paths'); import {IEditorViewState} from 'vs/editor/common/editorCommon'; @@ -182,7 +182,6 @@ export class TextFileEditor extends BaseTextEditor { // Open return this.editorService.openEditor({ resource: input.getResource(), - mime: MIME_TEXT, options: { pinned: true // new file gets pinned by default } diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 9858e2a8111..d6bc9be0b65 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -10,7 +10,7 @@ import {TPromise} from 'vs/base/common/winjs.base'; import nls = require('vs/nls'); import {isWindows, isLinux, isMacintosh} from 'vs/base/common/platform'; import {sequence, ITask} from 'vs/base/common/async'; -import {MIME_TEXT, isUnspecific, isBinaryMime, guessMimeTypes} from 'vs/base/common/mime'; +import {isBinaryMime, guessMimeTypes} from 'vs/base/common/mime'; import paths = require('vs/base/common/paths'); import URI from 'vs/base/common/uri'; import errors = require('vs/base/common/errors'); @@ -1422,14 +1422,6 @@ export abstract class BaseSaveFileAction extends BaseActionWithErrorReporting { // Save As (or Save untitled with associated path) if (this.isSaveAs() || source.scheme === 'untitled') { - let mimeOfSource: string; - if (source.scheme === 'untitled') { - const selectedMime = this.untitledEditorService.get(source).getMime(); - if (!isUnspecific(selectedMime)) { - mimeOfSource = [selectedMime, MIME_TEXT].join(', '); - } - } - let encodingOfSource: string; if (source.scheme === 'untitled') { encodingOfSource = this.untitledEditorService.get(source).getEncoding(); @@ -1471,7 +1463,6 @@ export abstract class BaseSaveFileAction extends BaseActionWithErrorReporting { const replaceWith: IResourceInput = { resource: target, - mime: mimeOfSource, encoding: encodingOfSource, options: { pinned: true, @@ -1563,14 +1554,13 @@ export abstract class BaseSaveAllAction extends BaseActionWithErrorReporting { const stacks = this.editorGroupService.getStacksModel(); // Store some properties per untitled file to restore later after save is completed - const mapUntitledToProperties: { [resource: string]: { mime: string; encoding: string; indexInGroups: number[]; activeInGroups: boolean[] } } = Object.create(null); + const mapUntitledToProperties: { [resource: string]: { encoding: string; indexInGroups: number[]; activeInGroups: boolean[] } } = Object.create(null); this.textFileService.getDirty() .filter(r => r.scheme === 'untitled') // All untitled resources .map(r => this.untitledEditorService.get(r)) // Mapped to their inputs .filter(input => !!input) // If possible :) .forEach(input => { mapUntitledToProperties[input.getResource().toString()] = { - mime: input.getMime(), encoding: input.getEncoding(), indexInGroups: stacks.groups.map(g => g.indexOf(input)), activeInGroups: stacks.groups.map(g => g.isActive(input)) @@ -1593,18 +1583,12 @@ export abstract class BaseSaveAllAction extends BaseActionWithErrorReporting { return; } - let mimeOfSource: string; - if (!isUnspecific(untitledProps.mime)) { - mimeOfSource = [untitledProps.mime, MIME_TEXT].join(', '); - } - // For each position where the untitled file was opened untitledProps.indexInGroups.forEach((indexInGroup, index) => { if (indexInGroup >= 0) { untitledToReopen.push({ input: { resource: result.target, - mime: mimeOfSource, encoding: untitledProps.encoding, options: { pinned: true, diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index 87b3ceea993..fcc828278dd 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -282,7 +282,7 @@ export class ExplorerView extends CollapsibleViewletView { private openFocusedElement(preserveFocus?: boolean): void { const stat: FileStat = this.explorerViewer.getFocus(); if (stat && !stat.isDirectory) { - this.editorService.openEditor({ resource: stat.resource, mime: stat.mime, options: { preserveFocus, revealIfVisible: true } }).done(null, errors.onUnexpectedError); + this.editorService.openEditor({ resource: stat.resource, options: { preserveFocus, revealIfVisible: true } }).done(null, errors.onUnexpectedError); } } diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index cace354b43c..a36e842e6e4 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -611,7 +611,7 @@ export class FileController extends DefaultController { if (stat && !stat.isDirectory) { this.telemetryService.publicLog('workbenchActionExecuted', { id: 'workbench.files.openFile', from: 'explorer' }); - this.editorService.openEditor({ resource: stat.resource, mime: stat.mime, options: { preserveFocus, pinned } }, sideBySide).done(null, errors.onUnexpectedError); + this.editorService.openEditor({ resource: stat.resource, options: { preserveFocus, pinned } }, sideBySide).done(null, errors.onUnexpectedError); } } diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts index 0feaf117748..df9c192b1cb 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts @@ -6,7 +6,6 @@ import {IWorkbenchContribution} from 'vs/workbench/common/contributions'; import errors = require('vs/base/common/errors'); -import {MIME_UNKNOWN} from 'vs/base/common/mime'; import URI from 'vs/base/common/uri'; import paths = require('vs/base/common/paths'); import {DiffEditorInput} from 'vs/workbench/common/editor/diffEditorInput'; @@ -71,11 +70,11 @@ export class FileEditorTracker implements IWorkbenchContribution { const before = e.getBefore(); const after = e.getAfter(); - this.handleMovedFileInOpenedEditors(before ? before.resource : null, after ? after.resource : null, after ? after.mime : null); + this.handleMovedFileInOpenedEditors(before ? before.resource : null, after ? after.resource : null); } } - private handleMovedFileInOpenedEditors(oldResource: URI, newResource: URI, mimeHint?: string): void { + private handleMovedFileInOpenedEditors(oldResource: URI, newResource: URI): void { const stacks = this.editorGroupService.getStacksModel(); stacks.groups.forEach(group => { group.getEditors().forEach(input => { @@ -93,7 +92,7 @@ export class FileEditorTracker implements IWorkbenchContribution { } // Reopen - this.editorService.openEditor({ resource: reopenFileResource, mime: mimeHint || MIME_UNKNOWN, options: { preserveFocus: true, pinned: group.isPinned(input), index: group.indexOf(input), inactive: !group.isActive(input) } }, stacks.positionOfGroup(group)).done(null, errors.onUnexpectedError); + this.editorService.openEditor({ resource: reopenFileResource, options: { preserveFocus: true, pinned: group.isPinned(input), index: group.indexOf(input), inactive: !group.isActive(input) } }, stacks.positionOfGroup(group)).done(null, errors.onUnexpectedError); } } }); diff --git a/src/vs/workbench/parts/git/browser/gitActions.contribution.ts b/src/vs/workbench/parts/git/browser/gitActions.contribution.ts index cf0b5e3470f..a38afaf371c 100644 --- a/src/vs/workbench/parts/git/browser/gitActions.contribution.ts +++ b/src/vs/workbench/parts/git/browser/gitActions.contribution.ts @@ -189,7 +189,6 @@ class OpenInEditorAction extends baseeditor.EditorInputAction { return this.fileService.resolveFile(resource).then(stat => { return this.editorService.openEditor({ resource: stat.resource, - mime: stat.mime, options: { forceOpen: true } diff --git a/src/vs/workbench/parts/git/browser/gitActions.ts b/src/vs/workbench/parts/git/browser/gitActions.ts index 11f4b998eea..de9a8af81e0 100644 --- a/src/vs/workbench/parts/git/browser/gitActions.ts +++ b/src/vs/workbench/parts/git/browser/gitActions.ts @@ -173,7 +173,6 @@ export class OpenFileAction extends GitAction { return this.fileService.resolveFile(resource) .then(stat => this.editorService.openEditor({ resource: stat.resource, - mime: stat.mime, options: { forceOpen: true } })); } @@ -395,7 +394,6 @@ export abstract class BaseUndoAction extends GitAction { return this.fileService.resolveFile(this.contextService.toResource(path)).then((stat: IFileStat) => { return this.editorService.openEditor({ resource: stat.resource, - mime: stat.mime, options: { forceOpen: true } diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 27c433ae478..c5f826a7ed9 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -6,8 +6,8 @@ import {TPromise} from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; -import network = require('vs/base/common/network'); import {guessMimeTypes} from 'vs/base/common/mime'; +import network = require('vs/base/common/network'); import {Registry} from 'vs/platform/platform'; import {basename, dirname} from 'vs/base/common/paths'; import types = require('vs/base/common/types'); @@ -263,7 +263,7 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { // Base Text Editor Support for file resources else if (this.fileInputDescriptor && resourceInput.resource instanceof URI && resourceInput.resource.scheme === network.Schemas.file) { - return this.createFileInput(resourceInput.resource, resourceInput.mime, resourceInput.encoding); + return this.createFileInput(resourceInput.resource, resourceInput.encoding); } // Treat an URI as ResourceEditorInput @@ -277,10 +277,10 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { return TPromise.as(null); } - private createFileInput(resource: URI, mime?: string, encoding?: string): TPromise { + private createFileInput(resource: URI, encoding?: string): TPromise { return this.instantiationService.createInstance(this.fileInputDescriptor).then((typedFileInput) => { typedFileInput.setResource(resource); - typedFileInput.setMime(mime || guessMimeTypes(resource.fsPath).join(', ')); + typedFileInput.setMime(guessMimeTypes(resource.fsPath).join(', ')); typedFileInput.setPreferredEncoding(encoding); return typedFileInput; diff --git a/src/vs/workbench/test/browser/services.test.ts b/src/vs/workbench/test/browser/services.test.ts index c942d30c79f..29ba658646e 100644 --- a/src/vs/workbench/test/browser/services.test.ts +++ b/src/vs/workbench/test/browser/services.test.ts @@ -299,13 +299,12 @@ suite('Workbench UI Services', () => { }); // Open Untyped Input - service.openEditor({ resource: toResource('/index.html'), mime: 'text/html', options: { selection: { startLineNumber: 1, startColumn: 1 } } }).then((editor) => { + service.openEditor({ resource: toResource('/index.html'), options: { selection: { startLineNumber: 1, startColumn: 1 } } }).then((editor) => { assert.strictEqual(editor, activeEditor); assert(openedEditorInput instanceof FileEditorInput); let contentInput = openedEditorInput; assert.strictEqual(contentInput.getResource().fsPath, toResource('/index.html').fsPath); - assert.strictEqual(contentInput.getMime(), 'text/html'); assert(openedEditorOptions instanceof TextEditorOptions); let textEditorOptions = openedEditorOptions; @@ -327,7 +326,7 @@ suite('Workbench UI Services', () => { }); // Resolve Editor Model (Untyped Input) - service.resolveEditorModel({ resource: toResource('/index.html'), mime: 'text/html' }, true).then((model) => { + service.resolveEditorModel({ resource: toResource('/index.html') }, true).then((model) => { assert(model instanceof TextFileEditorModel); }); }); From 4cd0bf095d9b7854333e45138c8b953023c8ffdf Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 4 Oct 2016 13:08:28 +0200 Subject: [PATCH 033/163] debt: get rid of mime in file input --- src/vs/base/common/mime.ts | 6 +- src/vs/base/test/common/mime.test.ts | 38 +++++------ src/vs/base/test/node/mime/mime.test.ts | 2 +- .../common/services/languagesRegistry.ts | 8 +-- .../editor/common/services/modeServiceImpl.ts | 2 +- .../browser/parts/editor/binaryDiffEditor.ts | 4 +- .../browser/parts/editor/textDiffEditor.ts | 4 +- src/vs/workbench/common/editor.ts | 24 +++---- .../common/editor/diffEditorInput.ts | 22 +----- .../common/editor/stringEditorInput.ts | 4 -- .../common/editor/stringEditorModel.ts | 4 -- .../common/editor/untitledEditorInput.ts | 17 ++--- .../files/browser/editors/textFileEditor.ts | 5 +- .../parts/files/browser/fileActions.ts | 4 +- .../parts/files/browser/files.contribution.ts | 4 +- .../parts/files/browser/saveErrorHandler.ts | 2 +- .../files/common/editors/fileEditorInput.ts | 67 +++---------------- src/vs/workbench/parts/files/common/files.ts | 4 -- .../test/browser/fileEditorInput.test.ts | 30 ++++----- .../test/browser/fileEditorModel.test.ts | 4 +- .../files/test/browser/textFileEditor.test.ts | 46 ------------- .../textFileEditorModelManager.test.ts | 2 +- .../services/editor/browser/editorService.ts | 2 - .../workbench/test/browser/services.test.ts | 4 +- .../test/common/editor/editorInput.test.ts | 4 -- .../common/editor/editorStacksModel.test.ts | 7 -- .../common/editor/rangeDecorations.test.ts | 2 +- 27 files changed, 89 insertions(+), 233 deletions(-) delete mode 100644 src/vs/workbench/parts/files/test/browser/textFileEditor.test.ts diff --git a/src/vs/base/common/mime.ts b/src/vs/base/common/mime.ts index 272e14bd738..8357520cda7 100644 --- a/src/vs/base/common/mime.ts +++ b/src/vs/base/common/mime.ts @@ -14,6 +14,7 @@ export let MIME_BINARY = 'application/octet-stream'; export let MIME_UNKNOWN = 'application/unknown'; export interface ITextMimeAssociation { + id: string; mime: string; filename?: string; extension?: string; @@ -75,6 +76,7 @@ export function registerTextMime(association: ITextMimeAssociation): void { function toTextMimeAssociationItem(association: ITextMimeAssociation): ITextMimeAssociationItem { return { + id: association.id, mime: association.mime, filename: association.filename, extension: association.extension, @@ -240,14 +242,14 @@ export function isUnspecific(mime: string[] | string): boolean { return mime.length === 1 && isUnspecific(mime[0]); } -export function suggestFilename(theMime: string, prefix: string): string { +export function suggestFilename(langId: string, prefix: string): string { for (var i = 0; i < registeredAssociations.length; i++) { let association = registeredAssociations[i]; if (association.userConfigured) { continue; // only support registered ones } - if (association.mime === theMime && association.extension) { + if (association.id === langId && association.extension) { return prefix + association.extension; } } diff --git a/src/vs/base/test/common/mime.test.ts b/src/vs/base/test/common/mime.test.ts index 03ab4b905cf..574db7c4e67 100644 --- a/src/vs/base/test/common/mime.test.ts +++ b/src/vs/base/test/common/mime.test.ts @@ -12,28 +12,28 @@ suite('Mime', () => { var guess = guessMimeTypes('foo.monaco'); assert.deepEqual(guess, ['application/unknown']); - registerTextMime({ extension: '.monaco', mime: 'text/monaco' }); + registerTextMime({ id: 'monaco', extension: '.monaco', mime: 'text/monaco' }); guess = guessMimeTypes('foo.monaco'); assert.deepEqual(guess, ['text/monaco', 'text/plain']); guess = guessMimeTypes('.monaco'); assert.deepEqual(guess, ['text/monaco', 'text/plain']); - registerTextMime({ filename: 'Codefile', mime: 'text/code' }); + registerTextMime({ id: 'codefile', filename: 'Codefile', mime: 'text/code' }); guess = guessMimeTypes('Codefile'); assert.deepEqual(guess, ['text/code', 'text/plain']); guess = guessMimeTypes('foo.Codefile'); assert.deepEqual(guess, ['application/unknown']); - registerTextMime({ filepattern: 'Docker*', mime: 'text/docker' }); + registerTextMime({ id: 'docker', filepattern: 'Docker*', mime: 'text/docker' }); guess = guessMimeTypes('Docker-debug'); assert.deepEqual(guess, ['text/docker', 'text/plain']); guess = guessMimeTypes('docker-PROD'); assert.deepEqual(guess, ['text/docker', 'text/plain']); - registerTextMime({ mime: 'text/nice-regex', firstline: /RegexesAreNice/ }); + registerTextMime({ id: 'niceregex', mime: 'text/nice-regex', firstline: /RegexesAreNice/ }); guess = guessMimeTypes('Randomfile.noregistration', 'RegexesAreNice'); assert.deepEqual(guess, ['text/nice-regex', 'text/plain']); @@ -45,8 +45,8 @@ suite('Mime', () => { }); test('Mimes Priority', () => { - registerTextMime({ extension: '.monaco', mime: 'text/monaco' }); - registerTextMime({ mime: 'text/foobar', firstline: /foobar/ }); + registerTextMime({ id: 'monaco', extension: '.monaco', mime: 'text/monaco' }); + registerTextMime({ id: 'foobar', mime: 'text/foobar', firstline: /foobar/ }); var guess = guessMimeTypes('foo.monaco'); assert.deepEqual(guess, ['text/monaco', 'text/plain']); @@ -54,32 +54,32 @@ suite('Mime', () => { guess = guessMimeTypes('foo.monaco', 'foobar'); assert.deepEqual(guess, ['text/monaco', 'text/plain']); - registerTextMime({ filename: 'dockerfile', mime: 'text/winner' }); - registerTextMime({ filepattern: 'dockerfile*', mime: 'text/looser' }); + registerTextMime({ id: 'docker', filename: 'dockerfile', mime: 'text/winner' }); + registerTextMime({ id: 'docker', filepattern: 'dockerfile*', mime: 'text/looser' }); guess = guessMimeTypes('dockerfile'); assert.deepEqual(guess, ['text/winner', 'text/plain']); }); test('Specificity priority 1', () => { - registerTextMime({ extension: '.monaco2', mime: 'text/monaco2' }); - registerTextMime({ filename: 'specific.monaco2', mime: 'text/specific-monaco2' }); + registerTextMime({ id: 'monaco2', extension: '.monaco2', mime: 'text/monaco2' }); + registerTextMime({ id: 'monaco2', filename: 'specific.monaco2', mime: 'text/specific-monaco2' }); assert.deepEqual(guessMimeTypes('specific.monaco2'), ['text/specific-monaco2', 'text/plain']); assert.deepEqual(guessMimeTypes('foo.monaco2'), ['text/monaco2', 'text/plain']); }); test('Specificity priority 2', () => { - registerTextMime({ filename: 'specific.monaco3', mime: 'text/specific-monaco3' }); - registerTextMime({ extension: '.monaco3', mime: 'text/monaco3' }); + registerTextMime({ id: 'monaco3', filename: 'specific.monaco3', mime: 'text/specific-monaco3' }); + registerTextMime({ id: 'monaco3', extension: '.monaco3', mime: 'text/monaco3' }); assert.deepEqual(guessMimeTypes('specific.monaco3'), ['text/specific-monaco3', 'text/plain']); assert.deepEqual(guessMimeTypes('foo.monaco3'), ['text/monaco3', 'text/plain']); }); test('Mimes Priority - Longest Extension wins', () => { - registerTextMime({ extension: '.monaco', mime: 'text/monaco' }); - registerTextMime({ extension: '.monaco.xml', mime: 'text/monaco-xml' }); - registerTextMime({ extension: '.monaco.xml.build', mime: 'text/monaco-xml-build' }); + registerTextMime({ id: 'monaco', extension: '.monaco', mime: 'text/monaco' }); + registerTextMime({ id: 'monaco', extension: '.monaco.xml', mime: 'text/monaco-xml' }); + registerTextMime({ id: 'monaco', extension: '.monaco.xml.build', mime: 'text/monaco-xml-build' }); var guess = guessMimeTypes('foo.monaco'); assert.deepEqual(guess, ['text/monaco', 'text/plain']); @@ -92,16 +92,16 @@ suite('Mime', () => { }); test('Mimes Priority - User configured wins', () => { - registerTextMime({ extension: '.monaco.xnl', mime: 'text/monaco', userConfigured: true }); - registerTextMime({ extension: '.monaco.xml', mime: 'text/monaco-xml' }); + registerTextMime({ id: 'monaco', extension: '.monaco.xnl', mime: 'text/monaco', userConfigured: true }); + registerTextMime({ id: 'monaco', extension: '.monaco.xml', mime: 'text/monaco-xml' }); var guess = guessMimeTypes('foo.monaco.xnl'); assert.deepEqual(guess, ['text/monaco', 'text/plain']); }); test('Mimes Priority - Pattern matches on path if specified', () => { - registerTextMime({ filepattern: '**/dot.monaco.xml', mime: 'text/monaco' }); - registerTextMime({ filepattern: '*ot.other.xml', mime: 'text/other' }); + registerTextMime({ id: 'monaco', filepattern: '**/dot.monaco.xml', mime: 'text/monaco' }); + registerTextMime({ id: 'other', filepattern: '*ot.other.xml', mime: 'text/other' }); var guess = guessMimeTypes('/some/path/dot.monaco.xml'); assert.deepEqual(guess, ['text/monaco', 'text/plain']); diff --git a/src/vs/base/test/node/mime/mime.test.ts b/src/vs/base/test/node/mime/mime.test.ts index 05cd05c7456..0c70e0de9e0 100644 --- a/src/vs/base/test/node/mime/mime.test.ts +++ b/src/vs/base/test/node/mime/mime.test.ts @@ -23,7 +23,7 @@ suite('Mime', () => { }); test('detectMimesFromFile (PNG saved as TXT)', function (done: () => void) { - mimeCommon.registerTextMime({ mime: 'text/plain', extension: '.txt' }); + mimeCommon.registerTextMime({ id: 'text', mime: 'text/plain', extension: '.txt' }); var file = require.toUrl('./fixtures/some.png.txt'); mime.detectMimesFromFile(file, (error, mimes) => { assert.equal(error, null); diff --git a/src/vs/editor/common/services/languagesRegistry.ts b/src/vs/editor/common/services/languagesRegistry.ts index d75938dc3a6..5111fa0c4a7 100644 --- a/src/vs/editor/common/services/languagesRegistry.ts +++ b/src/vs/editor/common/services/languagesRegistry.ts @@ -123,7 +123,7 @@ export class LanguagesRegistry { if (Array.isArray(lang.extensions)) { this.id2Extensions[lang.id] = this.id2Extensions[lang.id] || []; for (let extension of lang.extensions) { - mime.registerTextMime({ mime: primaryMime, extension: extension }); + mime.registerTextMime({ id: lang.id, mime: primaryMime, extension: extension }); this.id2Extensions[lang.id].push(extension); } } @@ -131,14 +131,14 @@ export class LanguagesRegistry { if (Array.isArray(lang.filenames)) { this.id2Filenames[lang.id] = this.id2Filenames[lang.id] || []; for (let filename of lang.filenames) { - mime.registerTextMime({ mime: primaryMime, filename: filename }); + mime.registerTextMime({ id: lang.id, mime: primaryMime, filename: filename }); this.id2Filenames[lang.id].push(filename); } } if (Array.isArray(lang.filenamePatterns)) { for (let filenamePattern of lang.filenamePatterns) { - mime.registerTextMime({ mime: primaryMime, filepattern: filenamePattern }); + mime.registerTextMime({ id: lang.id, mime: primaryMime, filepattern: filenamePattern }); } } @@ -150,7 +150,7 @@ export class LanguagesRegistry { try { var firstLineRegex = new RegExp(firstLineRegexStr); if (!strings.regExpLeadsToEndlessLoop(firstLineRegex)) { - mime.registerTextMime({ mime: primaryMime, firstline: firstLineRegex }); + mime.registerTextMime({ id: lang.id, mime: primaryMime, firstline: firstLineRegex }); } } catch (err) { // Most likely, the regex was bad diff --git a/src/vs/editor/common/services/modeServiceImpl.ts b/src/vs/editor/common/services/modeServiceImpl.ts index 8818607fe08..96cddb7b9d2 100644 --- a/src/vs/editor/common/services/modeServiceImpl.ts +++ b/src/vs/editor/common/services/modeServiceImpl.ts @@ -513,7 +513,7 @@ export class MainThreadModeServiceImpl extends ModeServiceImpl { const langId = configuration.files.associations[pattern]; const mimetype = this.getMimeForMode(langId) || `text/x-${langId}`; - mime.registerTextMime({ mime: mimetype, filepattern: pattern, userConfigured: true }); + mime.registerTextMime({ id: langId, mime: mimetype, filepattern: pattern, userConfigured: true }); }); } } diff --git a/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts b/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts index e406a24e3b3..3cd86c44573 100644 --- a/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts @@ -15,7 +15,7 @@ import {Dimension, Builder, $} from 'vs/base/browser/builder'; import {ResourceViewer} from 'vs/base/browser/ui/resourceviewer/resourceViewer'; import {DomScrollableElement} from 'vs/base/browser/ui/scrollbar/scrollableElement'; import {BaseEditor} from 'vs/workbench/browser/parts/editor/baseEditor'; -import {EditorInput, EditorOptions} from 'vs/workbench/common/editor'; +import {EditorInput, EditorOptions, BINARY_DIFF_EDITOR_ID} from 'vs/workbench/common/editor'; import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; import {DiffEditorModel} from 'vs/workbench/common/editor/diffEditorModel'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; @@ -27,7 +27,7 @@ import {ScrollbarVisibility} from 'vs/base/common/scrollable'; */ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSashLayoutProvider { - public static ID = 'workbench.editors.binaryResourceDiffEditor'; + public static ID = BINARY_DIFF_EDITOR_ID; private static MIN_CONTAINER_WIDTH = 100; diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 8e219979834..5eec2f06a73 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -16,7 +16,7 @@ import {Position} from 'vs/platform/editor/common/editor'; import {IDiffEditor} from 'vs/editor/browser/editorBrowser'; import {IDiffEditorOptions, IEditorOptions} from 'vs/editor/common/editorCommon'; import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor'; -import {TextEditorOptions, TextDiffEditorOptions, EditorModel, EditorInput, EditorOptions} from 'vs/workbench/common/editor'; +import {TextEditorOptions, TextDiffEditorOptions, EditorModel, EditorInput, EditorOptions, TEXT_DIFF_EDITOR_ID} from 'vs/workbench/common/editor'; import {StringEditorInput} from 'vs/workbench/common/editor/stringEditorInput'; import {ResourceEditorInput} from 'vs/workbench/common/editor/resourceEditorInput'; import {DiffEditorInput} from 'vs/workbench/common/editor/diffEditorInput'; @@ -44,7 +44,7 @@ export const TextCompareEditorVisible = new RawContextKey('textCompareE */ export class TextDiffEditor extends BaseTextEditor { - public static ID = 'workbench.editors.textDiffEditor'; + public static ID = TEXT_DIFF_EDITOR_ID; private diffNavigator: DiffNavigator; private nextDiffAction: NavigateAction; diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index b25dccd6e9d..a62afe5e8f1 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -36,6 +36,16 @@ export const Extensions = { Editors: 'workbench.contributions.editors' }; +/** + * Text diff editor id. + */ +export const TEXT_DIFF_EDITOR_ID = 'workbench.editors.textDiffEditor'; + +/** + * Binary diff editor id. + */ +export const BINARY_DIFF_EDITOR_ID = 'workbench.editors.binaryResourceDiffEditor'; + export interface IEditorRegistry { /** @@ -323,16 +333,6 @@ export interface IEncodingSupport { */ export interface IFileEditorInput extends IEditorInput, IEncodingSupport { - /** - * Gets the mime type of the file this input is about. - */ - getMime(): string; - - /** - * Sets the mime type of the file this input is about. - */ - setMime(mime: string): void; - /** * Gets the absolute file resource URI this input is about. */ @@ -360,8 +360,6 @@ export abstract class UntitledEditorInput extends EditorInput implements IEncodi abstract suggestFileName(): string; - abstract getMime(): string; - abstract getEncoding(): string; abstract setEncoding(encoding: string, mode: EncodingMode): void; @@ -799,7 +797,7 @@ export function asFileEditorInput(obj: any, supportDiff?: boolean): IFileEditorI let i = obj; - return i instanceof EditorInput && types.areFunctions(i.setResource, i.setMime, i.setEncoding, i.getEncoding, i.getResource, i.getMime) ? i : null; + return i instanceof EditorInput && types.areFunctions(i.setResource, i.setEncoding, i.getEncoding, i.getResource) ? i : null; } export interface IStacksModelChangeEvent { diff --git a/src/vs/workbench/common/editor/diffEditorInput.ts b/src/vs/workbench/common/editor/diffEditorInput.ts index f2fd52ce51f..87506881db4 100644 --- a/src/vs/workbench/common/editor/diffEditorInput.ts +++ b/src/vs/workbench/common/editor/diffEditorInput.ts @@ -6,12 +6,10 @@ import nls = require('vs/nls'); import {TPromise} from 'vs/base/common/winjs.base'; -import types = require('vs/base/common/types'); import {once} from 'vs/base/common/event'; import URI from 'vs/base/common/uri'; import {getPathLabel, IWorkspaceProvider} from 'vs/base/common/labels'; -import {isBinaryMime} from 'vs/base/common/mime'; -import {EditorModel, IFileEditorInput, EditorInput, BaseDiffEditorInput} from 'vs/workbench/common/editor'; +import {EditorModel, EditorInput, BaseDiffEditorInput, TEXT_DIFF_EDITOR_ID, BINARY_DIFF_EDITOR_ID} from 'vs/workbench/common/editor'; import {BaseTextEditorModel} from 'vs/workbench/common/editor/textEditorModel'; import {DiffEditorModel} from 'vs/workbench/common/editor/diffEditorModel'; import {TextDiffEditorModel} from 'vs/workbench/common/editor/textDiffEditorModel'; @@ -109,23 +107,7 @@ export class DiffEditorInput extends BaseDiffEditorInput { } public getPreferredEditorId(candidates: string[]): string { - - // Find the right diff editor for the given isBinary/isText state - const useBinaryEditor = this.forceOpenAsBinary || this.isBinary(this.originalInput) || this.isBinary(this.modifiedInput); - - return !useBinaryEditor ? 'workbench.editors.textDiffEditor' : 'workbench.editors.binaryResourceDiffEditor'; - } - - private isBinary(input: EditorInput): boolean { - let mime: string; - - // Find mime by checking for IFileEditorInput implementors - const fileInput = (input); - if (types.isFunction(fileInput.getMime)) { - mime = fileInput.getMime(); - } - - return mime && isBinaryMime(mime); + return this.forceOpenAsBinary ? BINARY_DIFF_EDITOR_ID : TEXT_DIFF_EDITOR_ID; } private createModel(refresh?: boolean): TPromise { diff --git a/src/vs/workbench/common/editor/stringEditorInput.ts b/src/vs/workbench/common/editor/stringEditorInput.ts index 08e817bfe3b..6d1f65c9a1a 100644 --- a/src/vs/workbench/common/editor/stringEditorInput.ts +++ b/src/vs/workbench/common/editor/stringEditorInput.ts @@ -63,10 +63,6 @@ export class StringEditorInput extends EditorInput { return this.value; } - public getMime(): string { - return this.mime; - } - /** * Sets the textual value of this input and will also update the underlying model if this input is resolved. */ diff --git a/src/vs/workbench/common/editor/stringEditorModel.ts b/src/vs/workbench/common/editor/stringEditorModel.ts index f97fa3c43d6..c56930a3194 100644 --- a/src/vs/workbench/common/editor/stringEditorModel.ts +++ b/src/vs/workbench/common/editor/stringEditorModel.ts @@ -99,10 +99,6 @@ export class StringEditorModel extends BaseTextEditorModel { return null; } - public getMime(): string { - return this.mime; - } - public load(): TPromise { // Create text editor model if not yet done diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index 8d527ae4189..2ab31e5a1dc 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -16,6 +16,7 @@ import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IModeService} from 'vs/editor/common/services/modeService'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import Event, {Emitter} from 'vs/base/common/event'; +import {PLAINTEXT_MODE_ID} from 'vs/editor/common/modes/modesRegistry'; import {ITextFileService} from 'vs/workbench/parts/files/common/files'; // TODO@Ben layer breaker @@ -98,23 +99,17 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { public suggestFileName(): string { if (!this.hasAssociatedFilePath) { - const mime = this.getMime(); - if (mime && mime !== MIME_TEXT /* do not suggest when the mime type is simple plain text */) { - return suggestFilename(mime, this.getName()); + if (this.cachedModel) { + const modeId = this.cachedModel.getModeId(); + if (modeId !== PLAINTEXT_MODE_ID) { // do not suggest when the mime type is simple plain text + return suggestFilename(modeId, this.getName()); + } } } return this.getName(); } - public getMime(): string { - if (this.cachedModel) { - return this.modeService.getMimeForMode(this.cachedModel.getModeId()); - } - - return null; - } - public getEncoding(): string { if (this.cachedModel) { return this.cachedModel.getEncoding(); diff --git a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts index e3f87ff280a..eb634f695e5 100644 --- a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts @@ -8,7 +8,6 @@ import {TPromise} from 'vs/base/common/winjs.base'; import nls = require('vs/nls'); import errors = require('vs/base/common/errors'); import {toErrorMessage} from 'vs/base/common/errorMessage'; -import {MIME_BINARY} from 'vs/base/common/mime'; import types = require('vs/base/common/types'); import paths = require('vs/base/common/paths'); import {IEditorViewState} from 'vs/editor/common/editorCommon'; @@ -199,7 +198,9 @@ export class TextFileEditor extends BaseTextEditor { } private openAsBinary(input: FileEditorInput, options: EditorOptions): void { - const fileInputBinary = this.instantiationService.createInstance(FileEditorInput, input.getResource(), MIME_BINARY, void 0); + const fileInputBinary = this.instantiationService.createInstance(FileEditorInput, input.getResource(), void 0); + fileInputBinary.setForceOpenAsBinary(); + this.editorService.openEditor(fileInputBinary, options, this.position).done(null, errors.onUnexpectedError); } diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index d6bc9be0b65..ce0c98dbdcd 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -1355,8 +1355,8 @@ export class CompareResourcesAction extends Action { this.tree.clearHighlight(); } - const leftInput = this.instantiationService.createInstance(FileEditorInput, globalResourceToCompare, void 0, void 0); - const rightInput = this.instantiationService.createInstance(FileEditorInput, this.resource, void 0, void 0); + const leftInput = this.instantiationService.createInstance(FileEditorInput, globalResourceToCompare, void 0); + const rightInput = this.instantiationService.createInstance(FileEditorInput, this.resource, void 0); return this.editorService.openEditor(new DiffEditorInput(toDiffLabel(globalResourceToCompare, this.resource, this.contextService), null, leftInput, rightInput)); } diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index 313abce7888..214832ce9b3 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -115,7 +115,7 @@ Registry.as(EditorExtensions.Editors).registerEditor( // Note: because of service injection, the descriptor needs to have the exact count // of arguments as the FileEditorInput constructor. Otherwise when creating an // instance through the instantiation service he will inject the services wrong! -const descriptor = new AsyncDescriptor('vs/workbench/parts/files/common/editors/fileEditorInput', 'FileEditorInput', /* DO NOT REMOVE */ void 0, /* DO NOT REMOVE */ void 0, /* DO NOT REMOVE */ void 0); +const descriptor = new AsyncDescriptor('vs/workbench/parts/files/common/editors/fileEditorInput', 'FileEditorInput', /* DO NOT REMOVE */ void 0, /* DO NOT REMOVE */ void 0); Registry.as(EditorExtensions.Editors).registerDefaultFileInput(descriptor); interface ISerializedFileInput { @@ -139,7 +139,7 @@ class FileEditorInputFactory implements IEditorInputFactory { public deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput { const fileInput: ISerializedFileInput = JSON.parse(serializedEditorInput); - return instantiationService.createInstance(FileEditorInput, URI.parse(fileInput.resource), void 0, void 0); + return instantiationService.createInstance(FileEditorInput, URI.parse(fileInput.resource), void 0); } } diff --git a/src/vs/workbench/parts/files/browser/saveErrorHandler.ts b/src/vs/workbench/parts/files/browser/saveErrorHandler.ts index 3614332c656..b31911389a6 100644 --- a/src/vs/workbench/parts/files/browser/saveErrorHandler.ts +++ b/src/vs/workbench/parts/files/browser/saveErrorHandler.ts @@ -263,7 +263,7 @@ class ResolveSaveConflictMessage implements IMessageWithAction { if (!this.model.isDisposed()) { const mime = guessMimeTypes(resource.fsPath).join(', '); const originalInput = this.instantiationService.createInstance(FileOnDiskEditorInput, resource, mime, paths.basename(resource.fsPath), resource.fsPath); - const modifiedInput = this.instantiationService.createInstance(FileEditorInput, resource, mime, void 0); + const modifiedInput = this.instantiationService.createInstance(FileEditorInput, resource, void 0); const conflictInput = this.instantiationService.createInstance(ConflictResolutionDiffEditorInput, this.model, nls.localize('saveConflictDiffLabel', "{0} (on disk) ↔ {1} (in {2})", modifiedInput.getName(), modifiedInput.getName(), product.nameLong), nls.localize('resolveSaveConflict', "Resolve save conflict"), originalInput, modifiedInput); return this.editorService.openEditor(conflictInput).then(() => { diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts index 7d9caf81aba..fd348e70f79 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts @@ -5,18 +5,13 @@ 'use strict'; import {TPromise} from 'vs/base/common/winjs.base'; -import {Registry} from 'vs/platform/platform'; -import types = require('vs/base/common/types'); import paths = require('vs/base/common/paths'); -import {guessMimeTypes} from 'vs/base/common/mime'; import labels = require('vs/base/common/labels'); import URI from 'vs/base/common/uri'; -import strings = require('vs/base/common/strings'); -import assert = require('vs/base/common/assert'); -import {IEditorRegistry, Extensions, EditorModel, EncodingMode, ConfirmResult, IEditorDescriptor} from 'vs/workbench/common/editor'; +import {EditorModel, EncodingMode, ConfirmResult} from 'vs/workbench/common/editor'; import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; import {IFileOperationResult, FileOperationResult, FileChangesEvent, EventType} from 'vs/platform/files/common/files'; -import {ITextFileService, BINARY_FILE_EDITOR_ID, FILE_EDITOR_INPUT_ID, FileEditorInput as CommonFileEditorInput, AutoSaveMode, ModelState, TextFileModelChangeEvent, IFileEditorDescriptor, LocalFileChangeEvent} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService, BINARY_FILE_EDITOR_ID, TEXT_FILE_EDITOR_ID, FILE_EDITOR_INPUT_ID, FileEditorInput as CommonFileEditorInput, AutoSaveMode, ModelState, TextFileModelChangeEvent, LocalFileChangeEvent} from 'vs/workbench/parts/files/common/files'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IEventService} from 'vs/platform/event/common/event'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; @@ -28,8 +23,8 @@ import {IHistoryService} from 'vs/workbench/services/history/common/history'; */ export class FileEditorInput extends CommonFileEditorInput { private resource: URI; - private mime: string; private preferredEncoding: string; + private forceOpenAsBinary: boolean; private name: string; private description: string; @@ -42,7 +37,6 @@ export class FileEditorInput extends CommonFileEditorInput { */ constructor( resource: URI, - mime: string, preferredEncoding: string, @IInstantiationService private instantiationService: IInstantiationService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @@ -56,7 +50,6 @@ export class FileEditorInput extends CommonFileEditorInput { if (resource) { this.setResource(resource); - this.setMime(mime || guessMimeTypes(this.resource.fsPath).join(', ')); this.preferredEncoding = preferredEncoding; } @@ -112,16 +105,6 @@ export class FileEditorInput extends CommonFileEditorInput { return this.resource; } - public getMime(): string { - return this.mime; - } - - public setMime(mime: string): void { - assert.ok(mime, 'Editor input needs mime type'); - - this.mime = mime; - } - public setPreferredEncoding(encoding: string): void { this.preferredEncoding = encoding; } @@ -144,6 +127,10 @@ export class FileEditorInput extends CommonFileEditorInput { } } + public setForceOpenAsBinary(): void { + this.forceOpenAsBinary = true; + } + public getTypeId(): string { return FILE_EDITOR_INPUT_ID; } @@ -203,38 +190,7 @@ export class FileEditorInput extends CommonFileEditorInput { } public getPreferredEditorId(candidates: string[]): string { - const editorRegistry = (Registry.as(Extensions.Editors)); - - // Lookup Editor by Mime - let descriptor: IEditorDescriptor; - const mimes = this.mime.split(','); - for (let m = 0; m < mimes.length; m++) { - const mime = strings.trim(mimes[m]); - - for (let i = 0; i < candidates.length; i++) { - descriptor = editorRegistry.getEditorById(candidates[i]); - - if (types.isFunction((descriptor).getMimeTypes)) { - const mimetypes = (descriptor).getMimeTypes(); - for (let j = 0; j < mimetypes.length; j++) { - const mimetype = mimetypes[j]; - - // Check for direct mime match - if (mime === mimetype) { - return descriptor.getId(); - } - - // Otherwise check for wildcard mime matches - if (strings.endsWith(mimetype, '/*') && strings.startsWith(mime, mimetype.substring(0, mimetype.length - 1))) { - return descriptor.getId(); - } - } - } - } - } - - // Otherwise use default editor - return BINARY_FILE_EDITOR_ID; + return this.forceOpenAsBinary ? BINARY_FILE_EDITOR_ID : TEXT_FILE_EDITOR_ID; } public resolve(refresh?: boolean): TPromise { @@ -283,13 +239,6 @@ export class FileEditorInput extends CommonFileEditorInput { } if (otherInput) { - - // Note that we can not test for the mime type here because we cache resolved file editor input models by resource. And - // these models have a fixed mode association that can not be changed afterwards. As such, we always treat this input - // equal if the resource is equal so that there is always just one text editor model (with undo hisotry etc.) around. - // - // !!! DO NOT CHANGE THIS ASSUMPTION !!! - // return otherInput instanceof FileEditorInput && (otherInput).resource.toString() === this.resource.toString(); } diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index b25d71ee21a..a11089d3977 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -50,10 +50,6 @@ export abstract class FileEditorInput extends EditorInput implements IFileEditor public abstract getResource(): URI; - public abstract setMime(mime: string): void; - - public abstract getMime(): string; - public abstract setPreferredEncoding(encoding: string): void; public abstract setEncoding(encoding: string, mode: EncodingMode): void; diff --git a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts index 6ca8b272514..d01ff1e5e15 100644 --- a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts +++ b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts @@ -53,9 +53,9 @@ suite('Files - FileEditorInput', () => { }); test('Basics', function (done) { - let input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/file.js'), 'text/javascript', void 0); - const otherInput = instantiationService.createInstance(FileEditorInput, toResource('foo/bar/otherfile.js'), 'text/javascript', void 0); - const otherInputSame = instantiationService.createInstance(FileEditorInput, toResource('foo/bar/file.js'), 'text/javascript', void 0); + let input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/file.js'), void 0); + const otherInput = instantiationService.createInstance(FileEditorInput, toResource('foo/bar/otherfile.js'), void 0); + const otherInputSame = instantiationService.createInstance(FileEditorInput, toResource('foo/bar/file.js'), void 0); assert(input.matches(input)); assert(input.matches(otherInputSame)); @@ -72,8 +72,8 @@ suite('Files - FileEditorInput', () => { input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar.html'), 'text/html', void 0); - const inputToResolve: any = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/file.js'), 'text/javascript', void 0); - const sameOtherInput = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/file.js'), 'text/javascript', void 0); + const inputToResolve: any = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/file.js'), void 0); + const sameOtherInput = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/file.js'), void 0); return accessor.editorService.resolveEditorModel(inputToResolve, true).then(resolved => { const resolvedModelA = resolved; @@ -115,8 +115,8 @@ suite('Files - FileEditorInput', () => { }); test('matches', function () { - const input1 = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), 'text/javascript', void 0); - const input2 = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), 'text/javascript', void 0); + const input1 = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), void 0); + const input2 = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), void 0); assert.strictEqual(input1.matches(null), false); assert.strictEqual(input1.matches(input1), true); @@ -124,7 +124,7 @@ suite('Files - FileEditorInput', () => { }); test('getEncoding/setEncoding', function (done) { - const input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), 'text/javascript', void 0); + const input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), void 0); input.setEncoding('utf16', EncodingMode.Encode); assert.equal(input.getEncoding(), 'utf16'); @@ -139,7 +139,7 @@ suite('Files - FileEditorInput', () => { }); test('save', function (done) { - const input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), 'text/javascript', void 0); + const input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), void 0); return accessor.editorService.resolveEditorModel(input, true).then((resolved: ITextFileEditorModel) => { resolved.textEditorModel.setValue('changed'); @@ -156,7 +156,7 @@ suite('Files - FileEditorInput', () => { }); test('revert', function (done) { - const input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), 'text/javascript', void 0); + const input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), void 0); return accessor.editorService.resolveEditorModel(input, true).then((resolved: ITextFileEditorModel) => { resolved.textEditorModel.setValue('changed'); @@ -173,7 +173,7 @@ suite('Files - FileEditorInput', () => { }); test('resolve handles binary files', function (done) { - const input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), 'text/javascript', void 0); + const input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/updatefile.js'), void 0); accessor.textFileService.setResolveTextContentErrorOnce({ message: 'error', @@ -192,14 +192,14 @@ suite('Files - FileEditorInput', () => { test('disposes when resource gets deleted - local file changes', function () { const parent = toResource('/foo/bar'); const resource = toResource('/foo/bar/updatefile.js'); - let input = instantiationService.createInstance(FileEditorInput, resource, 'text/javascript', void 0); + let input = instantiationService.createInstance(FileEditorInput, resource, void 0); assert.ok(!input.isDisposed()); accessor.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(toStat(resource))); assert.ok(input.isDisposed()); - input = instantiationService.createInstance(FileEditorInput, resource, 'text/javascript', void 0); + input = instantiationService.createInstance(FileEditorInput, resource, void 0); const other = toResource('/foo/barfoo'); @@ -218,14 +218,14 @@ suite('Files - FileEditorInput', () => { test('disposes when resource gets deleted - remote file changes', function () { const parent = toResource('/foo/bar'); const resource = toResource('/foo/bar/updatefile.js'); - let input = instantiationService.createInstance(FileEditorInput, resource, 'text/javascript', void 0); + let input = instantiationService.createInstance(FileEditorInput, resource, void 0); assert.ok(!input.isDisposed()); accessor.eventService.emit(EventType.FILE_CHANGES, new FileChangesEvent([{ resource, type: FileChangeType.DELETED }])); assert.ok(input.isDisposed()); - input = instantiationService.createInstance(FileEditorInput, resource, 'text/javascript', void 0); + input = instantiationService.createInstance(FileEditorInput, resource, void 0); const other = toResource('/foo/barfoo'); diff --git a/src/vs/workbench/parts/files/test/browser/fileEditorModel.test.ts b/src/vs/workbench/parts/files/test/browser/fileEditorModel.test.ts index e3bd65fbd1e..9752c86157b 100644 --- a/src/vs/workbench/parts/files/test/browser/fileEditorModel.test.ts +++ b/src/vs/workbench/parts/files/test/browser/fileEditorModel.test.ts @@ -238,8 +238,8 @@ suite('Files - TextFileEditorModel', () => { }); test('save() and isDirty() - proper with check for mtimes', function (done) { - const input1 = instantiationService.createInstance(FileEditorInput, toResource('/path/index_async2.txt'), 'text/plain', 'utf8'); - const input2 = instantiationService.createInstance(FileEditorInput, toResource('/path/index_async.txt'), 'text/plain', 'utf8'); + const input1 = instantiationService.createInstance(FileEditorInput, toResource('/path/index_async2.txt'), 'utf8'); + const input2 = instantiationService.createInstance(FileEditorInput, toResource('/path/index_async.txt'), 'utf8'); input1.resolve().then((model1: TextFileEditorModel) => { input2.resolve().then((model2: TextFileEditorModel) => { diff --git a/src/vs/workbench/parts/files/test/browser/textFileEditor.test.ts b/src/vs/workbench/parts/files/test/browser/textFileEditor.test.ts deleted file mode 100644 index 0fa1f69a078..00000000000 --- a/src/vs/workbench/parts/files/test/browser/textFileEditor.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -import {strictEqual, equal} from 'assert'; -import {join} from 'vs/base/common/paths'; -import URI from 'vs/base/common/uri'; -import {FileEditorDescriptor} from 'vs/workbench/parts/files/browser/files'; -import {Registry} from 'vs/platform/platform'; -import {SyncDescriptor} from 'vs/platform/instantiation/common/descriptors'; -import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; -import {Extensions} from 'vs/workbench/common/editor'; -import {workbenchInstantiationService} from 'vs/test/utils/servicesTestUtils'; - -const ExtensionId = Extensions.Editors; - -suite('Files - TextFileEditor', () => { - - test('TextFile Editor Registration', function () { - const d1 = new FileEditorDescriptor('ce-id1', 'name', 'vs/workbench/parts/files/browser/tests/contentEditor.test', 'MyClass', ['test-text/html', 'test-text/javascript']); - const d2 = new FileEditorDescriptor('ce-id2', 'name', 'vs/workbench/parts/files/browser/tests/contentEditor.test', 'MyOtherClass', ['test-text/css', 'test-text/javascript']); - - const oldEditors = Registry.as(ExtensionId).getEditors(); - Registry.as(ExtensionId).setEditors([]); - - const oldEditorCnt = Registry.as(ExtensionId).getEditors().length; - const oldInputCnt = Registry.as(ExtensionId).getEditorInputs().length; - - Registry.as(ExtensionId).registerEditor(d1, new SyncDescriptor(FileEditorInput)); - Registry.as(ExtensionId).registerEditor(d2, new SyncDescriptor(FileEditorInput)); - - equal(Registry.as(ExtensionId).getEditors().length, oldEditorCnt + 2); - equal(Registry.as(ExtensionId).getEditorInputs().length, oldInputCnt + 2); - - const instantiationService = workbenchInstantiationService(); - - strictEqual(Registry.as(ExtensionId).getEditor(instantiationService.createInstance(FileEditorInput, URI.file(join('C:\\', '/foo/bar/foobar.html')), 'test-text/html', void 0)), d1); - strictEqual(Registry.as(ExtensionId).getEditor(instantiationService.createInstance(FileEditorInput, URI.file(join('C:\\', '/foo/bar/foobar.js')), 'test-text/javascript', void 0)), d1); - strictEqual(Registry.as(ExtensionId).getEditor(instantiationService.createInstance(FileEditorInput, URI.file(join('C:\\', '/foo/bar/foobar.css')), 'test-text/css', void 0)), d2); - - Registry.as(ExtensionId).setEditors(oldEditors); - }); -}); \ No newline at end of file diff --git a/src/vs/workbench/parts/files/test/browser/textFileEditorModelManager.test.ts b/src/vs/workbench/parts/files/test/browser/textFileEditorModelManager.test.ts index 12c67a17a79..21616e674c3 100644 --- a/src/vs/workbench/parts/files/test/browser/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/parts/files/test/browser/textFileEditorModelManager.test.ts @@ -146,7 +146,7 @@ suite('Files - TextFileEditorModelManager', () => { const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, resource, 'utf8'); manager.add(resource, model); - const input = instantiationService.createInstance(FileEditorInput, resource, 'text/plain', void 0); + const input = instantiationService.createInstance(FileEditorInput, resource, void 0); const stacks = accessor.editorGroupService.getStacksModel(); const group = stacks.openGroup('group', true); diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index c5f826a7ed9..bfbbbeaaa1c 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -6,7 +6,6 @@ import {TPromise} from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; -import {guessMimeTypes} from 'vs/base/common/mime'; import network = require('vs/base/common/network'); import {Registry} from 'vs/platform/platform'; import {basename, dirname} from 'vs/base/common/paths'; @@ -280,7 +279,6 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { private createFileInput(resource: URI, encoding?: string): TPromise { return this.instantiationService.createInstance(this.fileInputDescriptor).then((typedFileInput) => { typedFileInput.setResource(resource); - typedFileInput.setMime(guessMimeTypes(resource.fsPath).join(', ')); typedFileInput.setPreferredEncoding(encoding); return typedFileInput; diff --git a/src/vs/workbench/test/browser/services.test.ts b/src/vs/workbench/test/browser/services.test.ts index 29ba658646e..64e1260235c 100644 --- a/src/vs/workbench/test/browser/services.test.ts +++ b/src/vs/workbench/test/browser/services.test.ts @@ -272,7 +272,7 @@ suite('Workbench UI Services', () => { test('WorkbenchEditorService', function () { let instantiationService = workbenchInstantiationService(); - let activeInput: EditorInput = instantiationService.createInstance(FileEditorInput, toResource('/something.js'), 'text/javascript', void 0); + let activeInput: EditorInput = instantiationService.createInstance(FileEditorInput, toResource('/something.js'), void 0); let testEditorPart = new TestEditorPart(); testEditorPart.setActiveEditorInput(activeInput); @@ -333,7 +333,7 @@ suite('Workbench UI Services', () => { test('DelegatingWorkbenchEditorService', function () { let instantiationService = workbenchInstantiationService(); - let activeInput: EditorInput = instantiationService.createInstance(FileEditorInput, toResource('/something.js'), 'text/javascript', void 0); + let activeInput: EditorInput = instantiationService.createInstance(FileEditorInput, toResource('/something.js'), void 0); let testEditorPart = new TestEditorPart(); testEditorPart.setActiveEditorInput(activeInput); diff --git a/src/vs/workbench/test/common/editor/editorInput.test.ts b/src/vs/workbench/test/common/editor/editorInput.test.ts index b5a6e4e10fa..be9922707af 100644 --- a/src/vs/workbench/test/common/editor/editorInput.test.ts +++ b/src/vs/workbench/test/common/editor/editorInput.test.ts @@ -10,10 +10,6 @@ import {EditorInput} from 'vs/workbench/common/editor'; import {DiffEditorInput} from 'vs/workbench/common/editor/diffEditorInput'; class MyEditorInput extends EditorInput { - getMime() { - return 'text/css'; - } - public getTypeId(): string { return ''; } diff --git a/src/vs/workbench/test/common/editor/editorStacksModel.test.ts b/src/vs/workbench/test/common/editor/editorStacksModel.test.ts index a529a78850d..94c3822ec46 100644 --- a/src/vs/workbench/test/common/editor/editorStacksModel.test.ts +++ b/src/vs/workbench/test/common/editor/editorStacksModel.test.ts @@ -144,9 +144,6 @@ class TestFileEditorInput extends EditorInput implements IFileEditorInput { public setResource(r: URI): void { } - public setMime(mime: string) { - } - public setEncoding(encoding: string) { } @@ -160,10 +157,6 @@ class TestFileEditorInput extends EditorInput implements IFileEditorInput { public getResource(): URI { return this.resource; } - - public getMime(): string { - return null; - } } function input(id = String(index++), nonSerializable?: boolean, resource?: URI): EditorInput { diff --git a/src/vs/workbench/test/common/editor/rangeDecorations.test.ts b/src/vs/workbench/test/common/editor/rangeDecorations.test.ts index ae2c0c1dbef..6e0b98dddc2 100644 --- a/src/vs/workbench/test/common/editor/rangeDecorations.test.ts +++ b/src/vs/workbench/test/common/editor/rangeDecorations.test.ts @@ -149,7 +149,7 @@ suite('Editor - Range decorations', () => { function mockEditorService(editorInput: IEditorInput) function mockEditorService(resource: URI) function mockEditorService(arg: any) { - let editorInput: IEditorInput = arg instanceof URI ? instantiationService.createInstance(FileEditorInput, arg, '', '') : arg; + let editorInput: IEditorInput = arg instanceof URI ? instantiationService.createInstance(FileEditorInput, arg, void 0) : arg; instantiationService.stub(WorkbenchEditorService.IWorkbenchEditorService, 'getActiveEditorInput', editorInput); } From 03468f68786c08dacea82095c85f75837f124985 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 4 Oct 2016 13:17:00 +0200 Subject: [PATCH 034/163] remove (now) unused code --- .../parts/files/browser/fileActions.ts | 18 ------------- .../parts/files/browser/files.contribution.ts | 25 ++++------------- src/vs/workbench/parts/files/browser/files.ts | 27 ------------------- src/vs/workbench/parts/files/common/files.ts | 6 +---- 4 files changed, 6 insertions(+), 70 deletions(-) delete mode 100644 src/vs/workbench/parts/files/browser/files.ts diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index ce0c98dbdcd..53431f18786 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -10,7 +10,6 @@ import {TPromise} from 'vs/base/common/winjs.base'; import nls = require('vs/nls'); import {isWindows, isLinux, isMacintosh} from 'vs/base/common/platform'; import {sequence, ITask} from 'vs/base/common/async'; -import {isBinaryMime, guessMimeTypes} from 'vs/base/common/mime'; import paths = require('vs/base/common/paths'); import URI from 'vs/base/common/uri'; import errors = require('vs/base/common/errors'); @@ -1328,23 +1327,6 @@ export class CompareResourcesAction extends Action { return false; } - const mimeA = guessMimeTypes(this.resource.fsPath).join(', '); - const mimeB = guessMimeTypes(globalResourceToCompare.fsPath).join(', '); - - // Check if target has same mime - if (mimeA === mimeB) { - return true; - } - - // Ensure the mode is equal if this is text (limitation of current diff infrastructure) - const isBinaryA = isBinaryMime(mimeA); - const isBinaryB = isBinaryMime(mimeB); - - // Ensure we are not comparing binary with text - if (isBinaryA !== isBinaryB) { - return false; - } - return true; } diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index 214832ce9b3..b750e467a74 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -16,8 +16,8 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory, EditorInput, IFileEditorInput } from 'vs/workbench/common/editor'; -import { FileEditorDescriptor } from 'vs/workbench/parts/files/browser/files'; import { AutoSaveConfiguration, SUPPORTED_ENCODINGS } from 'vs/platform/files/common/files'; +import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { FILE_EDITOR_INPUT_ID, VIEWLET_ID } from 'vs/workbench/parts/files/common/files'; import { FileEditorTracker } from 'vs/workbench/parts/files/common/editors/fileEditorTracker'; import { SaveErrorHandler } from 'vs/workbench/parts/files/browser/saveErrorHandler'; @@ -73,19 +73,11 @@ registry.registerWorkbenchAction( // Register file editors Registry.as(EditorExtensions.Editors).registerEditor( - new FileEditorDescriptor( + new EditorDescriptor( TextFileEditor.ID, // explicit dependency because we don't want these editors lazy loaded nls.localize('textFileEditor', "Text File Editor"), 'vs/workbench/parts/files/browser/editors/textFileEditor', - 'TextFileEditor', - [ - 'text/*', - - // In case the mime type is unknown, we prefer the text file editor over the binary editor to leave a chance - // of opening a potential text file properly. The resolution of the file in the text file editor will fail - // early on in case the file is actually binary, to prevent downloading a potential large binary file. - 'application/unknown' - ] + 'TextFileEditor' ), [ new SyncDescriptor(FileEditorInput) @@ -93,18 +85,11 @@ Registry.as(EditorExtensions.Editors).registerEditor( ); Registry.as(EditorExtensions.Editors).registerEditor( - new FileEditorDescriptor( + new EditorDescriptor( BinaryFileEditor.ID, // explicit dependency because we don't want these editors lazy loaded nls.localize('binaryFileEditor', "Binary File Editor"), 'vs/workbench/parts/files/browser/editors/binaryFileEditor', - 'BinaryFileEditor', - [ - 'image/*', - 'application/pdf', - 'audio/*', - 'video/*', - 'application/octet-stream' - ] + 'BinaryFileEditor' ), [ new SyncDescriptor(FileEditorInput) diff --git a/src/vs/workbench/parts/files/browser/files.ts b/src/vs/workbench/parts/files/browser/files.ts deleted file mode 100644 index fd8b85e2e49..00000000000 --- a/src/vs/workbench/parts/files/browser/files.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import {EditorDescriptor} from 'vs/workbench/browser/parts/editor/baseEditor'; -import {IFileEditorDescriptor} from 'vs/workbench/parts/files/common/files'; - -/** - * A lightweight descriptor of an editor for files. Optionally allows to specify a list of mime types the editor - * should be used for. This allows for fine grained contribution of editors to the Platform based on mime types. Wildcards - * can be used (e.g. text/*) to register an editor on a wider range of mime types. - */ -export class FileEditorDescriptor extends EditorDescriptor implements IFileEditorDescriptor { - private mimetypes: string[]; - - constructor(id: string, name: string, moduleId: string, ctorName: string, mimetypes: string[]) { - super(id, name, moduleId, ctorName); - - this.mimetypes = mimetypes; - } - - public getMimeTypes(): string[] { - return this.mimetypes; - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index a11089d3977..2525244dea5 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -10,7 +10,7 @@ import URI from 'vs/base/common/uri'; import Event from 'vs/base/common/event'; import {IEditorOptions, IRawText} from 'vs/editor/common/editorCommon'; import {IDisposable} from 'vs/base/common/lifecycle'; -import {IEncodingSupport, EncodingMode, EditorInput, IFileEditorInput, ConfirmResult, IWorkbenchEditorConfiguration, IEditorDescriptor} from 'vs/workbench/common/editor'; +import {IEncodingSupport, EncodingMode, EditorInput, IFileEditorInput, ConfirmResult, IWorkbenchEditorConfiguration} from 'vs/workbench/common/editor'; import {IFileStat, IFilesConfiguration, IBaseStat, IResolveContentOptions} from 'vs/platform/files/common/files'; import {createDecorator} from 'vs/platform/instantiation/common/instantiation'; import {FileStat} from 'vs/workbench/parts/files/common/explorerViewModel'; @@ -236,10 +236,6 @@ export enum SaveReason { WINDOW_CHANGE = 4 } -export interface IFileEditorDescriptor extends IEditorDescriptor { - getMimeTypes(): string[]; -} - export const ITextFileService = createDecorator(TEXT_FILE_SERVICE_ID); export interface IRawTextContent extends IBaseStat { From 88c3cad7a054044ea64e25c3a8589828fd1f8cbe Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 4 Oct 2016 13:30:40 +0200 Subject: [PATCH 035/163] debt: no more mimes in any workbench editor --- .../common/editor/binaryEditorModel.ts | 2 +- .../common/editor/stringEditorInput.ts | 21 ++++++++++--------- .../common/editor/stringEditorModel.ts | 8 +++---- .../common/editor/textEditorModel.ts | 14 ++++++------- .../common/editor/untitledEditorInput.ts | 16 ++++---------- .../common/editor/untitledEditorModel.ts | 14 ++++++------- 6 files changed, 34 insertions(+), 41 deletions(-) diff --git a/src/vs/workbench/common/editor/binaryEditorModel.ts b/src/vs/workbench/common/editor/binaryEditorModel.ts index 4f619860b69..e9008b320c5 100644 --- a/src/vs/workbench/common/editor/binaryEditorModel.ts +++ b/src/vs/workbench/common/editor/binaryEditorModel.ts @@ -10,7 +10,7 @@ import URI from 'vs/base/common/uri'; import {IFileService} from 'vs/platform/files/common/files'; /** - * An editor model that just represents a resource and mime for a resource that can be loaded. + * An editor model that just represents a resource that can be loaded. */ export class BinaryEditorModel extends EditorModel { private name: string; diff --git a/src/vs/workbench/common/editor/stringEditorInput.ts b/src/vs/workbench/common/editor/stringEditorInput.ts index 6d1f65c9a1a..cbab9f5d331 100644 --- a/src/vs/workbench/common/editor/stringEditorInput.ts +++ b/src/vs/workbench/common/editor/stringEditorInput.ts @@ -5,14 +5,14 @@ 'use strict'; import {TPromise} from 'vs/base/common/winjs.base'; -import {MIME_TEXT} from 'vs/base/common/mime'; +import {PLAINTEXT_MODE_ID} from 'vs/editor/common/modes/modesRegistry'; import {EditorModel, EditorInput} from 'vs/workbench/common/editor'; import {StringEditorModel} from 'vs/workbench/common/editor/stringEditorModel'; import URI from 'vs/base/common/uri'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; /** - * A read-only text editor input whos contents are made of the provided value and mime type. + * A read-only text editor input whos contents are made of the provided value and mode ID. */ export class StringEditorInput extends EditorInput { @@ -20,17 +20,18 @@ export class StringEditorInput extends EditorInput { protected cachedModel: StringEditorModel; + protected value: string; + private name: string; private description: string; - protected value: string; - protected mime: string; + private modeId: string; private singleton: boolean; constructor( name: string, description: string, value: string, - mime: string, + modeId: string, singleton: boolean, @IInstantiationService private instantiationService: IInstantiationService ) { @@ -39,7 +40,7 @@ export class StringEditorInput extends EditorInput { this.name = name; this.description = description; this.value = value; - this.mime = mime || MIME_TEXT; + this.modeId = modeId || PLAINTEXT_MODE_ID; this.singleton = singleton; } @@ -119,7 +120,7 @@ export class StringEditorInput extends EditorInput { } //Otherwise Create Model and Load - let model = this.instantiationService.createInstance(StringEditorModel, this.value, this.mime, this.getResource()); + let model = this.instantiationService.createInstance(StringEditorModel, this.value, this.modeId, this.getResource()); return model.load().then((resolvedModel: StringEditorModel) => { this.cachedModel = resolvedModel; @@ -135,8 +136,8 @@ export class StringEditorInput extends EditorInput { if (otherInput instanceof StringEditorInput) { let otherStringEditorInput = otherInput; - // If both inputs are singletons, check on the mime for equalness - if (otherStringEditorInput.singleton && this.singleton && otherStringEditorInput.mime === this.mime) { + // If both inputs are singletons, check on the modeId for equalness + if (otherStringEditorInput.singleton && this.singleton && otherStringEditorInput.modeId === this.modeId) { return true; } @@ -149,7 +150,7 @@ export class StringEditorInput extends EditorInput { // Otherwise compare by properties return otherStringEditorInput.value === this.value && - otherStringEditorInput.mime === this.mime && + otherStringEditorInput.modeId === this.modeId && otherStringEditorInput.description === this.description && otherStringEditorInput.name === this.name; } diff --git a/src/vs/workbench/common/editor/stringEditorModel.ts b/src/vs/workbench/common/editor/stringEditorModel.ts index c56930a3194..02dbd71eb6e 100644 --- a/src/vs/workbench/common/editor/stringEditorModel.ts +++ b/src/vs/workbench/common/editor/stringEditorModel.ts @@ -19,12 +19,12 @@ import {EditOperation} from 'vs/editor/common/core/editOperation'; */ export class StringEditorModel extends BaseTextEditorModel { protected value: string; - protected mime: string; + protected modeId: string; protected resource: URI; constructor( value: string, - mime: string, + modeId: string, resource: URI, @IModeService modeService: IModeService, @IModelService modelService: IModelService @@ -32,7 +32,7 @@ export class StringEditorModel extends BaseTextEditorModel { super(modelService, modeService); this.value = value; - this.mime = mime; + this.modeId = modeId; this.resource = resource; } @@ -103,7 +103,7 @@ export class StringEditorModel extends BaseTextEditorModel { // Create text editor model if not yet done if (!this.textEditorModel) { - return this.createTextEditorModel(this.value, this.resource, this.mime); + return this.createTextEditorModel(this.value, this.resource, this.modeId); } // Otherwise update diff --git a/src/vs/workbench/common/editor/textEditorModel.ts b/src/vs/workbench/common/editor/textEditorModel.ts index aac6121f159..c03cd043456 100644 --- a/src/vs/workbench/common/editor/textEditorModel.ts +++ b/src/vs/workbench/common/editor/textEditorModel.ts @@ -65,11 +65,11 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd } /** - * Creates the text editor model with the provided value, mime (can be comma separated for multiple values) and optional resource URL. + * Creates the text editor model with the provided value, modeId (can be comma separated for multiple values) and optional resource URL. */ - protected createTextEditorModel(value: string | IRawText, resource?: URI, mime?: string): TPromise { + protected createTextEditorModel(value: string | IRawText, resource?: URI, modeId?: string): TPromise { const firstLineText = this.getFirstLineText(value); - const mode = this.getOrCreateMode(this.modeService, mime, firstLineText); + const mode = this.getOrCreateMode(this.modeService, modeId, firstLineText); // To avoid flickering, give the mode at most 50ms to load. If the mode doesn't load in 50ms, proceed creating the model with a mode promise return TPromise.any([TPromise.timeout(50), mode]).then(() => { @@ -125,8 +125,8 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd * * @param firstLineText optional first line of the text buffer to set the mode on. This can be used to guess a mode from content. */ - protected getOrCreateMode(modeService: IModeService, mime: string, firstLineText?: string): TPromise { - return modeService.getOrCreateMode(mime); + protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): TPromise { + return modeService.getOrCreateMode(modeId); } /** @@ -156,13 +156,13 @@ export abstract class BaseTextEditorModel extends EditorModel implements ITextEd /** * Updates the text editor model mode based on the settings and configuration. */ - protected updateTextEditorModelMode(mime?: string): void { + protected updateTextEditorModelMode(modeId?: string): void { if (!this.textEditorModel) { return; } const firstLineText = this.getFirstLineText(this.textEditorModel.getValue()); - const mode = this.getOrCreateMode(this.modeService, mime, firstLineText); + const mode = this.getOrCreateMode(this.modeService, modeId, firstLineText); this.modelService.setMode(this.textEditorModel, mode); } diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index 2ab31e5a1dc..0159864a62c 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -6,8 +6,9 @@ import {TPromise} from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; -import {isUnspecific, guessMimeTypes, MIME_TEXT, suggestFilename} from 'vs/base/common/mime'; +import {suggestFilename} from 'vs/base/common/mime'; import labels = require('vs/base/common/labels'); +import {PLAINTEXT_MODE_ID} from 'vs/editor/common/modes/modesRegistry'; import paths = require('vs/base/common/paths'); import {UntitledEditorInput as AbstractUntitledEditorInput, EncodingMode, ConfirmResult} from 'vs/workbench/common/editor'; import {UntitledEditorModel} from 'vs/workbench/common/editor/untitledEditorModel'; @@ -16,7 +17,6 @@ import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IModeService} from 'vs/editor/common/services/modeService'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import Event, {Emitter} from 'vs/base/common/event'; -import {PLAINTEXT_MODE_ID} from 'vs/editor/common/modes/modesRegistry'; import {ITextFileService} from 'vs/workbench/parts/files/common/files'; // TODO@Ben layer breaker @@ -101,7 +101,7 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { if (!this.hasAssociatedFilePath) { if (this.cachedModel) { const modeId = this.cachedModel.getModeId(); - if (modeId !== PLAINTEXT_MODE_ID) { // do not suggest when the mime type is simple plain text + if (modeId !== PLAINTEXT_MODE_ID) { // do not suggest when the mode ID is simple plain text return suggestFilename(modeId, this.getName()); } } @@ -142,15 +142,7 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { private createModel(): UntitledEditorModel { const content = ''; - let mime = this.modeId; - if (!mime && this.hasAssociatedFilePath) { - const mimeFromPath = guessMimeTypes(this.resource.fsPath)[0]; - if (!isUnspecific(mimeFromPath)) { - mime = mimeFromPath; // take most specific mime type if file path is associated and mime is specific - } - } - - const model = this.instantiationService.createInstance(UntitledEditorModel, content, mime || MIME_TEXT, this.resource, this.hasAssociatedFilePath); + const model = this.instantiationService.createInstance(UntitledEditorModel, content, this.modeId, this.resource, this.hasAssociatedFilePath); // re-emit some events from the model this.toUnbind.push(model.onDidChangeDirty(() => this._onDidChangeDirty.fire())); diff --git a/src/vs/workbench/common/editor/untitledEditorModel.ts b/src/vs/workbench/common/editor/untitledEditorModel.ts index c3f5c3cb1d1..177ab7cb73c 100644 --- a/src/vs/workbench/common/editor/untitledEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledEditorModel.ts @@ -9,13 +9,13 @@ import {TPromise} from 'vs/base/common/winjs.base'; import {EditorModel, IEncodingSupport} from 'vs/workbench/common/editor'; import {StringEditorModel} from 'vs/workbench/common/editor/stringEditorModel'; import URI from 'vs/base/common/uri'; +import {PLAINTEXT_MODE_ID} from 'vs/editor/common/modes/modesRegistry'; import {EndOfLinePreference} from 'vs/editor/common/editorCommon'; import {IFilesConfiguration} from 'vs/platform/files/common/files'; import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {IModeService} from 'vs/editor/common/services/modeService'; import {IModelService} from 'vs/editor/common/services/modelService'; import {IMode} from 'vs/editor/common/modes'; -import {isUnspecific} from 'vs/base/common/mime'; import Event, {Emitter} from 'vs/base/common/event'; export class UntitledEditorModel extends StringEditorModel implements IEncodingSupport { @@ -33,14 +33,14 @@ export class UntitledEditorModel extends StringEditorModel implements IEncodingS constructor( value: string, - mime: string, + modeId: string, resource: URI, hasAssociatedFilePath: boolean, @IModeService modeService: IModeService, @IModelService modelService: IModelService, @IConfigurationService private configurationService: IConfigurationService ) { - super(value, mime, resource, modeService, modelService); + super(value, modeId, resource, modeService, modelService); this.hasAssociatedFilePath = hasAssociatedFilePath; this.dirty = hasAssociatedFilePath; // untitled associated to file path are dirty right away @@ -59,12 +59,12 @@ export class UntitledEditorModel extends StringEditorModel implements IEncodingS return this._onDidChangeEncoding.event; } - protected getOrCreateMode(modeService: IModeService, mime: string, firstLineText?: string): TPromise { - if (isUnspecific(mime)) { - return modeService.getOrCreateModeByFilenameOrFirstLine(this.resource.fsPath, firstLineText); // lookup mode via resource path if the provided mime is unspecific + protected getOrCreateMode(modeService: IModeService, modeId: string, firstLineText?: string): TPromise { + if (!modeId || modeId === PLAINTEXT_MODE_ID) { + return modeService.getOrCreateModeByFilenameOrFirstLine(this.resource.fsPath, firstLineText); // lookup mode via resource path if the provided modeId is unspecific } - return super.getOrCreateMode(modeService, mime, firstLineText); + return super.getOrCreateMode(modeService, modeId, firstLineText); } private registerListeners(): void { From 2d5c428787399861c19601fa1d67592648799559 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 4 Oct 2016 13:43:09 +0200 Subject: [PATCH 036/163] polish based on feedback --- .../platform/actions/browser/menusExtensionPoint.ts | 7 ++++++- src/vs/platform/actions/common/actions.ts | 2 +- .../workbench/browser/parts/editor/titleControl.ts | 12 ++++++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 25be267fc03..8c9d818d1b1 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -30,7 +30,7 @@ namespace schema { case 'editor/title': return MenuId.EditorTitle; case 'editor/context': return MenuId.EditorContext; case 'explorer/context': return MenuId.ExplorerContext; - case 'editor/tab': return MenuId.EditorTab; + case 'editortab/context': return MenuId.EditorTabContext; } } @@ -98,6 +98,11 @@ namespace schema { type: 'array', items: menuItem }, + 'editortab/context': { + description: localize('menus.editorTabContext', "The editor tabs context menu"), + type: 'array', + items: menuItem + }, 'explorer/context': { description: localize('menus.explorerContext', "The file explorer context menu"), type: 'array', diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 3de63bfcab8..5e517209238 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -40,7 +40,7 @@ export enum MenuId { EditorTitle = 1, EditorContext = 2, ExplorerContext = 3, - EditorTab = 4 + EditorTabContext = 4 } export const IMenuService = createDecorator('menuService'); diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index eda18501325..6bbe529c0d5 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -35,7 +35,7 @@ import {IContextKeyService} from 'vs/platform/contextkey/common/contextkey'; import {CloseEditorsInGroupAction, SplitEditorAction, CloseEditorAction, KeepEditorAction, CloseOtherEditorsInGroupAction, CloseRightEditorsInGroupAction, ShowEditorsInGroupAction} from 'vs/workbench/browser/parts/editor/editorActions'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import {createActionItem, fillInActions} from 'vs/platform/actions/browser/menuItemActionItem'; -import {IMenuService, MenuId} from 'vs/platform/actions/common/actions'; +import {IMenuService, MenuId, IMenu} from 'vs/platform/actions/common/actions'; import {ResourceContextKey} from 'vs/platform/actions/common/resourceContextKey'; export interface IToolbarActions { @@ -90,6 +90,8 @@ export abstract class TitleControl implements ITitleAreaControl { private resourceContext: ResourceContextKey; private disposeOnEditorActions: IDisposable[] = []; + private contextMenu: IMenu; + constructor( @IContextMenuService protected contextMenuService: IContextMenuService, @IInstantiationService protected instantiationService: IInstantiationService, @@ -114,6 +116,9 @@ export abstract class TitleControl implements ITitleAreaControl { this.resourceContext = instantiationService.createInstance(ResourceContextKey); + this.contextMenu = this.menuService.createMenu(MenuId.EditorTabContext, this.contextKeyService); + this.toDispose.push(this.contextMenu); + this.initActions(); this.registerListeners(); } @@ -471,9 +476,8 @@ export abstract class TitleControl implements ITitleAreaControl { actions.push(new Separator(), this.pinEditorAction); } - const titleBarMenu = this.menuService.createMenu(MenuId.EditorTab, this.contextKeyService); - fillInActions(titleBarMenu, actions); - titleBarMenu.dispose(); // not needed anymore + // Fill in contributed actions + fillInActions(this.contextMenu, actions); return actions; } From 7666a930a2fd8c8caba59b808833a6108553e138 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 4 Oct 2016 15:04:13 +0200 Subject: [PATCH 037/163] :lipstick: --- .../node/extensionManagementService.ts | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index daac9847e3b..d0dcde0b013 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -243,26 +243,24 @@ export class ExtensionManagementService implements IExtensionManagementService { private rollback(localExtension: ILocalExtension, dependecies: IGalleryExtension[]): TPromise { return this.uninstall(localExtension) - .then(() => this.filterOutUnInstalled(dependecies)) - .then(installed => TPromise.join(installed.map((i) => this.uninstall(i)))) - .then(() => null); + .then(() => this.filterOutUninstalled(dependecies)) + .then(installed => TPromise.join(installed.map((i) => this.uninstall(i)))) + .then(() => null); } private filterOutInstalled(extensions: IGalleryExtension[]): TPromise { - return this.getInstalled().then(local => { - return extensions.filter(extension => { - const extensionId = getExtensionId(extension, extension.version); - return local.every(local => local.id !== extensionId); + return this.getInstalled() + .then(local => { + return extensions.filter(extension => { + const extensionId = getExtensionId(extension, extension.version); + return local.every(local => local.id !== extensionId); + }); }); - }); } - private filterOutUnInstalled(extensions: IGalleryExtension[]): TPromise { - return this.getInstalled().then(installed => { - return installed.filter(local => { - return !!this.getGalleryExtensionForLocalExtension(extensions, local); - }); - }); + private filterOutUninstalled(extensions: IGalleryExtension[]): TPromise { + return this.getInstalled() + .then(installed => installed.filter(local => !!this.getGalleryExtensionForLocalExtension(extensions, local))); } private getGalleryExtensionForLocalExtension(galleryExtensions: IGalleryExtension[], localExtension: ILocalExtension): IGalleryExtension { @@ -273,10 +271,11 @@ export class ExtensionManagementService implements IExtensionManagementService { private downloadAndInstall(extension: IGalleryExtension): TPromise { const id = getExtensionId(extension, extension.version); const metadata = { - id: extension.id, - publisherId: extension.publisherId, - publisherDisplayName: extension.publisherDisplayName, - }; + id: extension.id, + publisherId: extension.publisherId, + publisherDisplayName: extension.publisherDisplayName, + }; + return this.galleryService.download(extension) .then(zipPath => validate(zipPath).then(() => zipPath)) .then(zipPath => this.installExtension(zipPath, id, metadata)); From 1ac264400a6d567fa2032005a10ce042427fa7f9 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 4 Oct 2016 15:11:26 +0200 Subject: [PATCH 038/163] fixes #12761 --- .../node/extensionManagementService.ts | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index d0dcde0b013..95594d97399 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -307,12 +307,14 @@ export class ExtensionManagementService implements IExtensionManagementService { } uninstall(extension: ILocalExtension): TPromise { - return this.scanUserExtensions().then(installed => { - const promises = installed - .filter(e => e.manifest.publisher === extension.manifest.publisher && e.manifest.name === extension.manifest.name) - .map(({ id }) => this.uninstallExtension(id)); + return this.removeOutdatedExtensions().then(() => { + return this.scanUserExtensions().then(installed => { + const promises = installed + .filter(e => e.manifest.publisher === extension.manifest.publisher && e.manifest.name === extension.manifest.name) + .map(({ id }) => this.uninstallExtension(id)); - return TPromise.join(promises); + return TPromise.join(promises); + }); }); } @@ -379,21 +381,30 @@ export class ExtensionManagementService implements IExtensionManagementService { }); } - removeDeprecatedExtensions(): TPromise { - const outdated = this.getOutdatedExtensionIds() - .then(extensions => extensions.map(e => getExtensionId(e.manifest, e.manifest.version))); + removeDeprecatedExtensions(): TPromise { + return TPromise.join([ + this.removeOutdatedExtensions(), + this.removeObsoleteExtensions() + ]); + } - const obsolete = this.getObsoleteExtensions() - .then(obsolete => Object.keys(obsolete)); + private removeOutdatedExtensions(): TPromise { + return this.getOutdatedExtensionIds() + .then(extensions => extensions.map(e => getExtensionId(e.manifest, e.manifest.version))) + .then(extensionIds => this.removeExtensions(extensionIds)); + } - return TPromise.join([outdated, obsolete]) - .then(result => flatten(result)) - .then(extensionsIds => { - return TPromise.join(extensionsIds.map(id => { - return pfs.rimraf(path.join(this.extensionsPath, id)) - .then(() => this.withObsoleteExtensions(obsolete => delete obsolete[id])); - })); - }); + private removeObsoleteExtensions(): TPromise { + return this.getObsoleteExtensions() + .then(obsolete => Object.keys(obsolete)) + .then(extensionIds => this.removeExtensions(extensionIds)); + } + + private removeExtensions(extensionsIds: string[]): TPromise { + return TPromise.join(extensionsIds.map(id => { + return pfs.rimraf(path.join(this.extensionsPath, id)) + .then(() => this.withObsoleteExtensions(obsolete => delete obsolete[id])); + })); } private getOutdatedExtensionIds(): TPromise { From e925936c012899b674598f96c9123469aefbfc83 Mon Sep 17 00:00:00 2001 From: isidor Date: Tue, 4 Oct 2016 15:57:10 +0200 Subject: [PATCH 039/163] breakpoint widget: fix placeholders and background color --- .../parts/debug/browser/breakpointWidget.ts | 22 ++++++++----------- .../debug/browser/media/breakpointWidget.css | 3 +-- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/breakpointWidget.ts b/src/vs/workbench/parts/debug/browser/breakpointWidget.ts index 35354848338..6c2f1b4223d 100644 --- a/src/vs/workbench/parts/debug/browser/breakpointWidget.ts +++ b/src/vs/workbench/parts/debug/browser/breakpointWidget.ts @@ -26,6 +26,10 @@ import {IKeyboardEvent} from 'vs/base/browser/keyboardEvent'; const $ = dom.$; const CONTEXT_BREAKPOINT_WIDGET_VISIBLE = new RawContextKey('breakpointWidgetVisible', false); const CLOSE_BREAKPOINT_WIDGET_COMMAND_ID = 'closeBreakpointWidget'; +const EXPRESSION_PLACEHOLDER = nls.localize('breakpointWidgetExpressionPlaceholder', "Break when expression evaluates to true"); +const EXPRESSION_ARIA_LABEL = nls.localize('breakpointWidgetAriaLabel', "The program will only stop here if this condition is true. Press Enter to accept or Escape to cancel."); +const HIT_COUNT_PLACEHOLDER = nls.localize('breakpointWidgetHitCountPlaceholder', "Break when expression equals the hit count"); +const HIT_COUNT_ARIA_LABEL = nls.localize('breakpointWidgetHitCountAriaLabel', "The program will only stop here if the hit count is met. Press Enter to accept or Escape to cancel."); export class BreakpointWidget extends ZoneWidget { @@ -34,10 +38,6 @@ export class BreakpointWidget extends ZoneWidget { private inputBox: InputBox; private toDispose: lifecycle.IDisposable[]; private breakpointWidgetVisible: IContextKey; - private expressionPlaceholder: string; - private expressionAriaLabel: string; - private hitCountPlaceholder: string; - private hitCountAriaLabel: string; private hitCountContext: boolean; constructor(editor: editorbrowser.ICodeEditor, private lineNumber: number, @@ -48,10 +48,6 @@ export class BreakpointWidget extends ZoneWidget { super(editor, { showFrame: true, showArrow: false, frameColor: '#007ACC', frameWidth: 1 }); this.toDispose = []; - this.expressionPlaceholder = nls.localize('breakpointWidgetExpressionPlaceholder', "Breakpoint on line {0} will only stop if this expression is true.", this.lineNumber); - this.expressionAriaLabel = nls.localize('breakpointWidgetAriaLabel', "Type the breakpoint condition for line {0}. The program will only stop here if this condition is true. Press Enter to accept or Escape to cancel.", this.lineNumber); - this.hitCountPlaceholder = nls.localize('breakpointWidgetHitCountPlaceholder', "Breakpoint on line {0} will only stop if the hit count condition is true.", this.lineNumber); - this.hitCountAriaLabel = nls.localize('breakpointWidgetHitCountAriaLabel', "Type the breakpoint hit count condition for line {0}. The program will only stop here if the hit count is met. Press Enter to accept or Escape to cancel.", this.lineNumber); this.create(); this.breakpointWidgetVisible = CONTEXT_BREAKPOINT_WIDGET_VISIBLE.bindTo(contextKeyService); @@ -70,7 +66,7 @@ export class BreakpointWidget extends ZoneWidget { } protected _fillContainer(container: HTMLElement): void { - dom.addClass(container, 'breakpoint-widget'); + dom.addClass(container, 'breakpoint-widget monaco-editor-background'); const uri = this.editor.getModel().uri; const breakpoint = this.debugService.getModel().getBreakpoints().filter(bp => bp.lineNumber === this.lineNumber && bp.source.uri.toString() === uri.toString()).pop(); @@ -78,15 +74,15 @@ export class BreakpointWidget extends ZoneWidget { selectBox.render(dom.append(container, $('.breakpoint-select-container'))); selectBox.onDidSelect(e => { this.hitCountContext = e === 'Hit Count'; - this.inputBox.setAriaLabel(this.hitCountContext ? this.hitCountAriaLabel : this.expressionAriaLabel); - this.inputBox.setPlaceHolder(this.hitCountContext ? this.hitCountPlaceholder : this.expressionPlaceholder); + this.inputBox.setAriaLabel(this.hitCountContext ? HIT_COUNT_ARIA_LABEL : EXPRESSION_ARIA_LABEL); + this.inputBox.setPlaceHolder(this.hitCountContext ? HIT_COUNT_PLACEHOLDER : EXPRESSION_PLACEHOLDER); this.inputBox.value = (this.hitCountContext && breakpoint && breakpoint.hitCondition) ? breakpoint.hitCondition : breakpoint && breakpoint.condition ? breakpoint.condition : ''; }); const inputBoxContainer = dom.append(container, $('.inputBoxContainer')); this.inputBox = new InputBox(inputBoxContainer, this.contextViewService, { - placeholder: this.expressionPlaceholder, - ariaLabel: this.expressionAriaLabel + placeholder: EXPRESSION_PLACEHOLDER, + ariaLabel: EXPRESSION_ARIA_LABEL }); this.toDispose.push(this.inputBox); diff --git a/src/vs/workbench/parts/debug/browser/media/breakpointWidget.css b/src/vs/workbench/parts/debug/browser/media/breakpointWidget.css index 0fb6516a856..b19784a9748 100644 --- a/src/vs/workbench/parts/debug/browser/media/breakpointWidget.css +++ b/src/vs/workbench/parts/debug/browser/media/breakpointWidget.css @@ -6,7 +6,6 @@ .monaco-editor .zone-widget .zone-widget-container.breakpoint-widget { height: 30px !important; display: flex; - background-color: var(--input-bgcolor); } .monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .breakpoint-select-container { @@ -17,7 +16,6 @@ } .monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .breakpoint-select-container .select-box { - margin-top: 0px; border-color: rgba(128, 128, 128, 0.35); } @@ -32,6 +30,7 @@ .monaco-editor .breakpoint-widget .input { font-family: Monaco, Menlo, Consolas, "Droid Sans Mono", "Inconsolata", "Courier New", monospace, "Droid Sans Fallback"; line-height: 22px; + background-color: transparent; } .monaco-workbench.mac .monaco-editor .breakpoint-widget .input { From 105168b486c95d42f38e3a65c9c80ecf778fce46 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Tue, 4 Oct 2016 17:11:17 +0200 Subject: [PATCH 040/163] fix #11871 --- src/vs/code/electron-main/menus.ts | 2 +- .../search/browser/search.contribution.ts | 64 ++++++++----------- .../parts/search/browser/searchActions.ts | 31 ++++++++- .../parts/search/common/constants.ts | 2 + 4 files changed, 57 insertions(+), 42 deletions(-) diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 68c626fc167..aa0d07a1e46 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -451,7 +451,7 @@ export class VSCodeMenu { const find = this.createMenuItem(nls.localize({ key: 'miFind', comment: ['&& denotes a mnemonic'] }, "&&Find"), 'actions.find'); const replace = this.createMenuItem(nls.localize({ key: 'miReplace', comment: ['&& denotes a mnemonic'] }, "&&Replace"), 'editor.action.startFindReplaceAction'); - const findInFiles = this.createMenuItem(nls.localize({ key: 'miFindInFiles', comment: ['&& denotes a mnemonic'] }, "Find &&in Files"), 'workbench.view.search'); + const findInFiles = this.createMenuItem(nls.localize({ key: 'miFindInFiles', comment: ['&& denotes a mnemonic'] }, "Find &&in Files"), 'workbench.action.findInFiles'); const replaceInFiles = this.createMenuItem(nls.localize({ key: 'miReplaceInFiles', comment: ['&& denotes a mnemonic'] }, "Replace &&in Files"), 'workbench.action.replaceInFiles'); [ diff --git a/src/vs/workbench/parts/search/browser/search.contribution.ts b/src/vs/workbench/parts/search/browser/search.contribution.ts index 603887028f8..e1dcc19ad9a 100644 --- a/src/vs/workbench/parts/search/browser/search.contribution.ts +++ b/src/vs/workbench/parts/search/browser/search.contribution.ts @@ -21,7 +21,6 @@ import {KeybindingsRegistry} from 'vs/platform/keybinding/common/keybindingsRegi import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {AsyncDescriptor} from 'vs/platform/instantiation/common/descriptors'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; -import {IKeybindings} from 'vs/platform/keybinding/common/keybinding'; import {IQuickOpenService} from 'vs/workbench/services/quickopen/common/quickOpenService'; import {IViewletService} from 'vs/workbench/services/viewlet/common/viewletService'; import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; @@ -113,23 +112,34 @@ class ShowAllSymbolsAction extends QuickOpenAction { 10 )); -// Register Action to Open Viewlet -const openSearchViewletKb: IKeybindings = { - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F -}; +// Actions +const registry = Registry.as(ActionExtensions.WorkbenchActions); -(Registry.as(ActionExtensions.WorkbenchActions)).registerWorkbenchAction( - new SyncActionDescriptor(searchActions.OpenSearchViewletAction, searchActions.OpenSearchViewletAction.ID, searchActions.OpenSearchViewletAction.LABEL, openSearchViewletKb), - 'View: Show Search', - nls.localize('view', "View") -); -(Registry.as(ActionExtensions.WorkbenchActions)).registerWorkbenchAction( - new SyncActionDescriptor(searchActions.ReplaceInFilesAction, searchActions.ReplaceInFilesAction.ID, searchActions.ReplaceInFilesAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_H - }), - 'Replace in Files' -); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.OpenSearchViewletAction, Constants.VIEWLET_ID, nls.localize('showSearchViewlet', "Show Search"), { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, + Constants.SearchViewletVisibleKey.toNegated()), 'View: Show Search', nls.localize('view', "View")); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusActiveEditorAction, Constants.FocusActiveEditorActionId, '', { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, + ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FindInFilesAction, Constants.FindInFilesActionId, nls.localize('findInFiles', "Find in Files"), { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_F }, + Constants.SearchInputBoxFocussedKey.toNegated()), 'Find in Files'); + +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ReplaceInFilesAction, searchActions.ReplaceInFilesAction.ID, searchActions.ReplaceInFilesAction.LABEL, {primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_H}), 'Replace in Files'); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.CloseReplaceAction, Constants.CloseReplaceWidgetActionId, '', { primary: KeyCode.Escape }, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.ReplaceInputBoxFocussedKey)), ''); + +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowNextSearchTermAction, searchActions.ShowNextSearchTermAction.ID, searchActions.ShowNextSearchTermAction.LABEL, ShowNextFindTermKeybinding, + ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowPreviousSearchTermAction, searchActions.ShowPreviousSearchTermAction.ID, searchActions.ShowPreviousSearchTermAction.LABEL, ShowPreviousFindTermKeybinding, + ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusNextInputAction, searchActions.FocusNextInputAction.ID, searchActions.FocusNextInputAction.LABEL, { primary: KeyCode.DownArrow }, + ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.InputBoxFocussedKey)), ''); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusPreviousInputAction, searchActions.FocusPreviousInputAction.ID, searchActions.FocusPreviousInputAction.LABEL, { primary: KeyCode.UpArrow }, + ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.InputBoxFocussedKey, Constants.SearchInputBoxFocussedKey.toNegated())), ''); + +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleCaseSensitiveAction, Constants.ToggleCaseSensitiveActionId, '', ToggleCaseSensitiveKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleWholeWordAction, Constants.ToggleWholeWordActionId, '', ToggleWholeWordKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); +registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleRegexAction, Constants.ToggleRegexActionId, '', ToggleRegexKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); + +registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllSymbolsAction, ACTION_ID, ACTION_LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_T }), 'Go to Symbol in Workspace...'); // Contribute to Explorer Viewer const actionBarRegistry = Registry.as(ActionBarExtensions.Actionbar); @@ -160,28 +170,6 @@ actionBarRegistry.registerActionBarContributor(Scope.VIEWER, ExplorerViewerActio ) ); -// Actions -const registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllSymbolsAction, ACTION_ID, ACTION_LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.KEY_T -}), 'Go to Symbol in Workspace...'); - -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowNextSearchTermAction, searchActions.ShowNextSearchTermAction.ID, searchActions.ShowNextSearchTermAction.LABEL, ShowNextFindTermKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); - -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ShowPreviousSearchTermAction, searchActions.ShowPreviousSearchTermAction.ID, searchActions.ShowPreviousSearchTermAction.LABEL, ShowPreviousFindTermKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); - -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusNextInputAction, searchActions.FocusNextInputAction.ID, searchActions.FocusNextInputAction.LABEL, { - primary: KeyCode.DownArrow -}, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.InputBoxFocussedKey)), ''); - -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.FocusPreviousInputAction, searchActions.FocusPreviousInputAction.ID, searchActions.FocusPreviousInputAction.LABEL, { - primary: KeyCode.UpArrow -}, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.InputBoxFocussedKey, Constants.SearchInputBoxFocussedKey.toNegated())), ''); - -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleCaseSensitiveAction, Constants.ToggleCaseSensitiveActionId, '', ToggleCaseSensitiveKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleWholeWordAction, Constants.ToggleWholeWordActionId, '', ToggleWholeWordKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.ToggleRegexAction, Constants.ToggleRegexActionId, '', ToggleRegexKeybinding, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.SearchInputBoxFocussedKey)), ''); -registry.registerWorkbenchAction(new SyncActionDescriptor(searchActions.CloseReplaceAction, Constants.CloseReplaceWidgetActionId, '', { primary: KeyCode.Escape }, ContextKeyExpr.and(Constants.SearchViewletVisibleKey, Constants.ReplaceInputBoxFocussedKey)), ''); // Configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index a84377313be..f0039e41e7a 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -143,15 +143,40 @@ export class FocusPreviousInputAction extends Action { export class OpenSearchViewletAction extends ToggleViewletAction { - public static ID = Constants.VIEWLET_ID; - public static LABEL = nls.localize('showSearchViewlet', "Show Search"); - constructor(id: string, label: string, @IViewletService viewletService: IViewletService, @IWorkbenchEditorService editorService: IWorkbenchEditorService) { super(id, label, Constants.VIEWLET_ID, viewletService, editorService); } } +export class FocusActiveEditorAction extends Action { + + constructor(id: string, label: string, @IWorkbenchEditorService private editorService: IWorkbenchEditorService) { + super(id, label); + } + + public run(): TPromise { + let editor = this.editorService.getActiveEditor(); + if (editor) { + editor.focus(); + } + return TPromise.as(true); + } + +} + +export class FindInFilesAction extends Action { + + constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) { + super(id, label); + } + + public run(): TPromise { + return this.viewletService.openViewlet(Constants.VIEWLET_ID, true); + } + +} + export class ReplaceInFilesAction extends Action { public static ID = 'workbench.action.replaceInFiles'; diff --git a/src/vs/workbench/parts/search/common/constants.ts b/src/vs/workbench/parts/search/common/constants.ts index 26a5f3bf3bb..a569abc60dc 100644 --- a/src/vs/workbench/parts/search/common/constants.ts +++ b/src/vs/workbench/parts/search/common/constants.ts @@ -7,6 +7,8 @@ import {RawContextKey} from 'vs/platform/contextkey/common/contextkey'; export const VIEWLET_ID = 'workbench.view.search'; +export const FindInFilesActionId = 'workbench.action.findInFiles'; +export const FocusActiveEditorActionId = 'search.action.focusActiveEditor'; export const ToggleCaseSensitiveActionId = 'toggleSearchCaseSensitive'; export const ToggleWholeWordActionId = 'toggleSearchWholeWord'; export const ToggleRegexActionId = 'toggleSearchRegex'; From 9fcf0f62495e51d78fb4596c3e4ca812293a4955 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Tue, 4 Oct 2016 17:47:55 +0200 Subject: [PATCH 041/163] compute score from highlights, fixes #11423 --- .../contrib/suggest/common/completionModel.ts | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/vs/editor/contrib/suggest/common/completionModel.ts b/src/vs/editor/contrib/suggest/common/completionModel.ts index 0e3ddaaf89d..c19c0ea5b4c 100644 --- a/src/vs/editor/contrib/suggest/common/completionModel.ts +++ b/src/vs/editor/contrib/suggest/common/completionModel.ts @@ -5,10 +5,10 @@ 'use strict'; -import {isFalsyOrEmpty} from 'vs/base/common/arrays'; -import {IMatch, fuzzyContiguousFilter} from 'vs/base/common/filters'; -import {ISuggestSupport} from 'vs/editor/common/modes'; -import {ISuggestionItem} from './suggest'; +import { isFalsyOrEmpty } from 'vs/base/common/arrays'; +import { IMatch, fuzzyContiguousFilter } from 'vs/base/common/filters'; +import { ISuggestSupport } from 'vs/editor/common/modes'; +import { ISuggestionItem } from './suggest'; export interface ICompletionItem extends ISuggestionItem { highlights?: IMatch[]; @@ -43,7 +43,7 @@ export class CompletionModel { this._lineContext = lineContext; } - replaceIncomplete(newItems: ISuggestionItem[], compareFn:(a:ISuggestionItem, b:ISuggestionItem) => number): void { + replaceIncomplete(newItems: ISuggestionItem[], compareFn: (a: ISuggestionItem, b: ISuggestionItem) => number): void { let newItemsIdx = 0; for (let i = 0; i < this._items.length; i++) { if (this._incomplete.indexOf(this._items[i].support) >= 0) { @@ -137,7 +137,7 @@ export class CompletionModel { match = item.highlights !== null; // no match on label nor codeSnippet -> check on filterText - if(!match && typeof suggestion.filterText === 'string') { + if (!match && typeof suggestion.filterText === 'string') { if (!isFalsyOrEmpty(filter(word, suggestion.filterText))) { match = true; @@ -155,7 +155,7 @@ export class CompletionModel { // compute score against word const wordLowerCase = word.toLowerCase(); - const score = CompletionModel._score(suggestion.insertText, word, wordLowerCase); + const score = CompletionModel._scoreByHighlight(item, word, wordLowerCase); if (score > topScore) { topScore = score; this._topScoreIdx = this._filteredItems.length - 1; @@ -176,20 +176,22 @@ export class CompletionModel { } } - private static _score(suggestion: string, currentWord: string, currentWordLowerCase: string): number { - const suggestionLowerCase = suggestion.toLowerCase(); + private static _scoreByHighlight(item: ICompletionItem, currentWord: string, currentWordLowerCase: string): number { + const {highlights, suggestion} = item; let score = 0; + if (!isFalsyOrEmpty(highlights)) { + for (const {start, end} of highlights) { + // find the highlight in the current word and + // score it based on case-match and start index + const part = suggestion.label.substring(start, end); + if (currentWord.indexOf(part) >= 0) { + score += (2 * part.length) / (start + 1); - for (let i = 0, len = Math.min(currentWord.length, suggestion.length); i < len; i++) { - if (currentWord[i] === suggestion[i]) { - score += 2; - } else if (currentWordLowerCase[i] === suggestionLowerCase[i]) { - score += 1; - } else { - break; + } else if (currentWordLowerCase.indexOf(part) >= 0) { + score += part.length / (start + 1); + } } } - return score; } } From 804729f775f9ab68083ffbe756f492726588665d Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Tue, 4 Oct 2016 09:17:40 -0700 Subject: [PATCH 042/163] Fix overflow with watermark (fixes #12980) --- src/vs/workbench/parts/watermark/watermark.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/parts/watermark/watermark.css b/src/vs/workbench/parts/watermark/watermark.css index 3a9b9094c1f..ae749d0f7a6 100644 --- a/src/vs/workbench/parts/watermark/watermark.css +++ b/src/vs/workbench/parts/watermark/watermark.css @@ -14,6 +14,7 @@ top: calc(50% + 55px); text-align: center; white-space: nowrap; + overflow: hidden; } .monaco-workbench > .part.editor > .watermark > .watermark-box { From ac837a1d9cc6b8934a0ebc04d01df03ce79e9099 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 4 Oct 2016 10:55:51 -0700 Subject: [PATCH 043/163] Make s in "script" upper case Fixes #13208 --- .../parts/execution/electron-browser/terminalService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/execution/electron-browser/terminalService.ts b/src/vs/workbench/parts/execution/electron-browser/terminalService.ts index bf639a00575..10a4c2b69e8 100644 --- a/src/vs/workbench/parts/execution/electron-browser/terminalService.ts +++ b/src/vs/workbench/parts/execution/electron-browser/terminalService.ts @@ -149,7 +149,7 @@ export class MacTerminalService implements ITerminalService { const lines = stderr.split('\n', 1); e(new Error(lines[0])); } else { - e(new Error(nls.localize('mac.terminal.script.failed', "script '{0}' failed with exit code {1}", script, code))); + e(new Error(nls.localize('mac.terminal.script.failed', "Script '{0}' failed with exit code {1}", script, code))); } } }); @@ -277,4 +277,4 @@ function quote(args: string[]): string { r += ' '; } return r; -} \ No newline at end of file +} From 8bd60949abfca8cb88fef8f406bf0152e324fced Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 4 Oct 2016 14:27:04 -0700 Subject: [PATCH 044/163] Set line-height of xterm.js' text area to 0 It's taking up space when it has focus which breaks the terminal's position. This only seems to happen on Mac for some reason. Fixes #12038 --- src/vs/workbench/parts/terminal/electron-browser/media/xterm.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css index 24d687abcee..57e37d10f41 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css +++ b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css @@ -42,6 +42,7 @@ width: 0; height: 0; z-index: -10; + line-height: 0; } .monaco-workbench .panel.integrated-terminal .xterm .xterm-helper-textarea:focus { From 06947f29cb2c6e956597ededf6d3e61fad9b3576 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Tue, 4 Oct 2016 17:00:14 -0700 Subject: [PATCH 045/163] Add path end trivia and pass to find (fixes #12624) --- src/vs/base/common/glob.ts | 95 ++++++++++++++----- src/vs/base/test/common/glob.test.ts | 83 ++++++++++++++++ .../services/search/node/fileSearch.ts | 16 ++-- .../subfolder/anotherfolder/anotherfile.txt | 0 .../services/search/test/node/search.test.ts | 93 +++++++++++++++++- 5 files changed, 253 insertions(+), 34 deletions(-) create mode 100644 src/vs/workbench/services/search/test/node/fixtures/examples/subfolder/anotherfolder/anotherfile.txt diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index 433876df191..8ea9941c5c1 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -213,6 +213,7 @@ const T1 = /^\*\*\/\*\.[\w\.-]+$/; // **/*.something const T2 = /^\*\*\/([\w\.-]+)\/?$/; // **/something const T3 = /^{\*\*\/[\*\.]?[\w\.-]+\/?(,\*\*\/[\*\.]?[\w\.-]+\/?)*}$/; // {**/*.something,**/*.else} or {**/package.json,**/project.json} const T3_2 = /^{\*\*\/[\*\.]?[\w\.-]+(\/(\*\*)?)?(,\*\*\/[\*\.]?[\w\.-]+(\/(\*\*)?)?)*}$/; // Like T3, with optional trailing /** +const T4 = /^\*\*((\/[\w\.-]+)+)\/?$/; // **/something/else export type ParsedPattern = (path: string, basename?: string) => boolean; export type ParsedExpression = (path: string, basename?: string, siblingsFn?: () => string[]) => string /* the matching pattern */; @@ -226,12 +227,14 @@ interface ParsedStringPattern { basenames?: string[]; patterns?: string[]; allBasenames?: string[]; + allPathEnds?: string[]; } type SiblingsPattern = { siblings: string[], name: string }; interface ParsedExpressionPattern { (path: string, basename: string, siblingsPatternFn: () => SiblingsPattern): string /* the matching pattern */; requiresSiblings?: boolean; allBasenames?: string[]; + allPathEnds?: string[]; } const CACHE = new BoundedLinkedMap(10000); // bounded to 10000 elements @@ -266,33 +269,12 @@ function parsePattern(pattern: string, options: IGlobOptions): ParsedStringPatte parsedPattern = function (path, basename) { return path && strings.endsWith(path, base) ? pattern : null; }; - } else if (match = T2.exec(pattern)) { // common pattern: **/some.txt just need basename check - parsedPattern = trivia2(match[1], pattern); - } else if (options.trimForExclusions && strings.endsWith(pattern, '/**') && (match = T2.exec(pattern.substr(0, pattern.length - 2)))) { // common pattern: **/some/** for exclusions just need basename check + } else if (match = T2.exec(trimForExclusions(pattern, options))) { // common pattern: **/some.txt just need basename check parsedPattern = trivia2(match[1], pattern); } else if ((options.trimForExclusions ? T3_2 : T3).test(pattern)) { // repetition of common patterns (see above) {**/*.txt,**/*.png} - const parsedPatterns = aggregateBasenameMatches(pattern.slice(1, -1).split(',') - .map(pattern => parsePattern(pattern, options)) - .filter(pattern => pattern !== NULL), pattern); - const n = parsedPatterns.length; - if (!n) { - return NULL; - } - if (n === 1) { - return parsedPatterns[0]; - } - parsedPattern = function (path: string, basename: string) { - for (let i = 0, n = parsedPatterns.length; i < n; i++) { - if ((parsedPatterns[i])(path, basename)) { - return pattern; - } - } - return null; - }; - const withBasenames = arrays.first(parsedPatterns, pattern => !!(pattern).allBasenames); - if (withBasenames) { - parsedPattern.allBasenames = (withBasenames).allBasenames; - } + parsedPattern = trivia3(pattern, options); + } else if (match = T4.exec(trimForExclusions(pattern, options))) { // common pattern: **/something/else just need endsWith check + parsedPattern = trivia4(match[1], pattern); } // Otherwise convert to pattern @@ -306,6 +288,10 @@ function parsePattern(pattern: string, options: IGlobOptions): ParsedStringPatte return parsedPattern; } +function trimForExclusions(pattern: string, options: IGlobOptions): string { + return options.trimForExclusions && strings.endsWith(pattern, '/**') ? pattern.substr(0, pattern.length - 2) : pattern; // dropping **, tailing / is dropped later +} + // common pattern: **/some.txt just need basename check function trivia2(base: string, originalPattern: string): ParsedStringPattern { const slashBase = `/${base}`; @@ -326,6 +312,48 @@ function trivia2(base: string, originalPattern: string): ParsedStringPattern { return parsedPattern; } +// repetition of common patterns (see above) {**/*.txt,**/*.png} +function trivia3 (pattern: string, options: IGlobOptions): ParsedStringPattern { + const parsedPatterns = aggregateBasenameMatches(pattern.slice(1, -1).split(',') + .map(pattern => parsePattern(pattern, options)) + .filter(pattern => pattern !== NULL), pattern); + const n = parsedPatterns.length; + if (!n) { + return NULL; + } + if (n === 1) { + return parsedPatterns[0]; + } + const parsedPattern: ParsedStringPattern = function (path: string, basename: string) { + for (let i = 0, n = parsedPatterns.length; i < n; i++) { + if ((parsedPatterns[i])(path, basename)) { + return pattern; + } + } + return null; + }; + const withBasenames = arrays.first(parsedPatterns, pattern => !!(pattern).allBasenames); + if (withBasenames) { + parsedPattern.allBasenames = (withBasenames).allBasenames; + } + const allPathEnds = parsedPatterns.reduce((all, current) => current.allPathEnds ? all.concat(current.allPathEnds) : all, []); + if (allPathEnds.length) { + parsedPattern.allPathEnds = allPathEnds; + } + return parsedPattern; +} + +// common pattern: **/something/else just need endsWith check +function trivia4(pathEnd: string, pattern: string): ParsedStringPattern { + const nativePathEnd = pathEnd.replace(paths.sep, paths.nativeSep); + const nativePath = nativePathEnd.substr(1); + const parsedPattern: ParsedStringPattern = function (path, basename) { + return path && (path === nativePath || strings.endsWith(path, nativePathEnd)) ? pattern : null; + }; + parsedPattern.allPathEnds = [pathEnd]; + return parsedPattern; +} + function toRegExp(pattern: string): ParsedStringPattern { try { const regExp = new RegExp(`^${parseRegExp(pattern)}$`); @@ -383,6 +411,9 @@ export function parse(arg1: string | IExpression, options: IGlobOptions = {}): a if (parsedPattern.allBasenames) { (resultPattern).allBasenames = parsedPattern.allBasenames; } + if (parsedPattern.allPathEnds) { + (resultPattern).allPathEnds = parsedPattern.allPathEnds; + } return resultPattern; } @@ -394,6 +425,10 @@ export function getBasenameTerms(patternOrExpression: ParsedPattern | ParsedExpr return (patternOrExpression).allBasenames || []; } +export function getPathEndTerms(patternOrExpression: ParsedPattern | ParsedExpression): string[] { + return (patternOrExpression).allPathEnds || []; +} + function parsedExpression(expression: IExpression, options: IGlobOptions): ParsedExpression { const parsedPatterns = aggregateBasenameMatches(Object.getOwnPropertyNames(expression) .map(pattern => parseExpressionPattern(pattern, expression[pattern], options)) @@ -426,6 +461,11 @@ function parsedExpression(expression: IExpression, options: IGlobOptions): Parse resultExpression.allBasenames = (withBasenames).allBasenames; } + const allPathEnds = parsedPatterns.reduce((all, current) => current.allPathEnds ? all.concat(current.allPathEnds) : all, []); + if (allPathEnds.length) { + resultExpression.allPathEnds = allPathEnds; + } + return resultExpression; } @@ -465,6 +505,11 @@ function parsedExpression(expression: IExpression, options: IGlobOptions): Parse resultExpression.allBasenames = (withBasenames).allBasenames; } + const allPathEnds = parsedPatterns.reduce((all, current) => current.allPathEnds ? all.concat(current.allPathEnds) : all, []); + if (allPathEnds.length) { + resultExpression.allPathEnds = allPathEnds; + } + return resultExpression; } diff --git a/src/vs/base/test/common/glob.test.ts b/src/vs/base/test/common/glob.test.ts index 436e1f9c5a6..a085b05005a 100644 --- a/src/vs/base/test/common/glob.test.ts +++ b/src/vs/base/test/common/glob.test.ts @@ -771,4 +771,87 @@ suite('Glob', () => { assert.strictEqual(glob.parse('{**/foo/,**/abc/}', { trimForExclusions: true })('bar/foo', 'foo'), true); assert.strictEqual(glob.parse('{**/foo/,**/abc/}', { trimForExclusions: true })('bar/abc', 'abc'), true); }); + + test('expression/pattern path end', function () { + assert.strictEqual(glob.parse('**/foo/bar')('foo/baz', 'baz'), false); + assert.strictEqual(glob.parse('**/foo/bar')('foo/bar', 'bar'), true); + assert.strictEqual(glob.parse('**/foo/bar')('bar/foo/bar', 'bar'), true); + assert.strictEqual(glob.parse('**/foo/bar/**')('bar/foo/bar', 'bar'), true); + assert.strictEqual(glob.parse('**/foo/bar/**')('bar/foo/bar/baz', 'baz'), true); + assert.strictEqual(glob.parse('**/foo/bar/**', { trimForExclusions: true })('bar/foo/bar', 'bar'), true); + assert.strictEqual(glob.parse('**/foo/bar/**', { trimForExclusions: true })('bar/foo/bar/baz', 'baz'), false); + }); + + test('expression/pattern path ends', function () { + assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/*.foo')), []); + assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/foo')), []); + assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/foo/bar')), ['/foo/bar']); + assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/foo/bar/')), ['/foo/bar']); + // Not supported + // assert.deepStrictEqual(glob.getNativePathEnds(glob.parse('{**/baz/bar,**/foo/bar,**/bar}')), ['/baz/bar', '/foo/bar']); + // assert.deepStrictEqual(glob.getNativePathEnds(glob.parse('{**/baz/bar/,**/foo/bar/,**/bar/}')), ['/baz/bar', '/foo/bar']); + + const parsed = glob.parse({ + '**/foo/bar': true, + '**/foo2/bar2': true, + // Not supported + // '{**/bar/foo,**/baz/foo}': true, + // '{**/bar2/foo/,**/baz2/foo/}': true, + '**/bulb': true, + '**/bulb2': true, + '**/bulb/foo': false + }); + assert.deepStrictEqual(glob.getPathEndTerms(parsed), ['/foo/bar', '/foo2/bar2']); + assert.deepStrictEqual(glob.getBasenameTerms(parsed), ['bulb', 'bulb2']); + assert.deepStrictEqual(glob.getPathEndTerms(glob.parse({ + '**/foo/bar': { when: '$(basename).zip' }, + '**/bar/foo': true, + '**/bar2/foo2': true + })), ['/bar/foo', '/bar2/foo2']); + }); + + test('expression/pattern optimization for path ends', function () { + assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/foo/bar/**')), []); + assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/foo/bar/**', { trimForExclusions: true })), ['/foo/bar']); + + testOptimizationForPathEnds('**/*.foo/bar/**', [], [['baz/bar.foo/bar/baz', true]]); + testOptimizationForPathEnds('**/foo/bar/**', ['/foo/bar'], [['bar/foo/bar', true], ['bar/foo/bar/baz', false]]); + // Not supported + // testOptimizationForPathEnds('{**/baz/bar/**,**/foo/bar/**}', ['/baz/bar', '/foo/bar'], [['bar/baz/bar', true], ['bar/foo/bar', true]]); + + testOptimizationForPathEnds({ + '**/foo/bar/**': true, + // Not supported + // '{**/bar/bar/**,**/baz/bar/**}': true, + '**/bulb/bar/**': false + }, ['/foo/bar'], [ + ['bar/foo/bar', '**/foo/bar/**'], + // Not supported + // ['foo/bar/bar', '{**/bar/bar/**,**/baz/bar/**}'], + ['/foo/bar/nope', null] + ]); + + const siblingsFn = () => ['baz', 'baz.zip', 'nope']; + testOptimizationForPathEnds({ + '**/foo/123/**': { when: '$(basename).zip' }, + '**/bar/123/**': true + }, ['/bar/123'], [ + ['bar/foo/123', null], + ['bar/foo/123/baz', null], + ['bar/foo/123/nope', null], + ['foo/bar/123', '**/bar/123/**'], + ], [ + null, + siblingsFn, + siblingsFn + ]); + }); + + function testOptimizationForPathEnds(pattern: string|glob.IExpression, pathEndTerms: string[], matches: [string, string|boolean][], siblingsFns: (() => string[])[] = []) { + const parsed = glob.parse(pattern, { trimForExclusions: true }); + assert.deepStrictEqual(glob.getPathEndTerms(parsed), pathEndTerms); + matches.forEach(([text, result], i) => { + assert.strictEqual(parsed(text, null, siblingsFns[i]), result); + }); + } }); \ No newline at end of file diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index d7e2bc0d23a..600c1643577 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -256,15 +256,19 @@ export class FileWalker { */ public spawnFindCmd(rootFolder: string, excludePattern: glob.ParsedExpression) { const basenames = glob.getBasenameTerms(excludePattern); + const pathEnds = glob.getPathEndTerms(excludePattern); let args = ['-L', '.']; - if (basenames.length) { + if (basenames.length || pathEnds.length) { args.push('-not', '(', '('); - for (let i = 0, n = basenames.length; i < n; i++) { - if (i) { - args.push('-o'); - } - args.push('-name', FileWalker.escapeGlobSpecials(basenames[i])); + for (const basename of basenames) { + args.push('-name', FileWalker.escapeGlobSpecials(basename)); + args.push('-o'); } + for (const pathEnd of pathEnds) { + args.push('-path', '*' + FileWalker.escapeGlobSpecials(pathEnd)); + args.push('-o'); + } + args.pop(); args.push(')', '-prune', ')'); } args.push('-type', 'f'); diff --git a/src/vs/workbench/services/search/test/node/fixtures/examples/subfolder/anotherfolder/anotherfile.txt b/src/vs/workbench/services/search/test/node/fixtures/examples/subfolder/anotherfolder/anotherfile.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/vs/workbench/services/search/test/node/search.test.ts b/src/vs/workbench/services/search/test/node/search.test.ts index dd4aa07779e..d649a585c9a 100644 --- a/src/vs/workbench/services/search/test/node/search.test.ts +++ b/src/vs/workbench/services/search/test/node/search.test.ts @@ -85,7 +85,7 @@ suite('Search', () => { } }, () => { }, (error) => { assert.ok(!error); - assert.equal(count, 6); + assert.equal(count, 7); done(); }); }); @@ -121,7 +121,7 @@ suite('Search', () => { } }, () => { }, (error) => { assert.ok(!error); - assert.equal(count, 13); + assert.equal(count, 14); done(); }); }); @@ -237,7 +237,7 @@ suite('Search', () => { } }, () => { }, (error) => { assert.ok(!error); - assert.equal(count, 12); + assert.equal(count, 13); done(); }); }); @@ -478,6 +478,93 @@ suite('Search', () => { }); }); + test('Find: exclude folder path', function (done: () => void) { + if (platform.isWindows) { + done(); + return; + } + + const walker = new FileWalker({ rootFolders: rootfolders() }); + const file0 = './examples/company.js'; + const file1 = './examples/subfolder/subfile.txt'; + + const cmd1 = walker.spawnFindCmd(rootfolders()[0], glob.parse({ '**/examples/something': true })); + walker.readStdout(cmd1, 'utf8', (err1, stdout1) => { + assert.equal(err1, null); + assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); + assert.notStrictEqual(stdout1.split('\n').indexOf(file1), -1, stdout1); + + const cmd2 = walker.spawnFindCmd(rootfolders()[0], glob.parse({ '**/examples/subfolder': true })); + walker.readStdout(cmd2, 'utf8', (err2, stdout2) => { + assert.equal(err2, null); + assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); + assert.strictEqual(stdout2.split('\n').indexOf(file1), -1, stdout2); + done(); + }); + }); + }); + + test('Find: exclude subfolder path', function (done: () => void) { + if (platform.isWindows) { + done(); + return; + } + + const walker = new FileWalker({ rootFolders: rootfolders() }); + const file0 = './examples/subfolder/subfile.txt'; + const file1 = './examples/subfolder/anotherfolder/anotherfile.txt'; + + const cmd1 = walker.spawnFindCmd(rootfolders()[0], glob.parse({ '**/subfolder/something': true })); + walker.readStdout(cmd1, 'utf8', (err1, stdout1) => { + assert.equal(err1, null); + assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); + assert.notStrictEqual(stdout1.split('\n').indexOf(file1), -1, stdout1); + + const cmd2 = walker.spawnFindCmd(rootfolders()[0], glob.parse({ '**/subfolder/anotherfolder': true })); + walker.readStdout(cmd2, 'utf8', (err2, stdout2) => { + assert.equal(err2, null); + assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); + assert.strictEqual(stdout2.split('\n').indexOf(file1), -1, stdout2); + done(); + }); + }); + }); + + test('Find: exclude combination of paths', function (done: () => void) { + if (platform.isWindows) { + done(); + return; + } + + const walker = new FileWalker({ rootFolders: rootfolders() }); + const filesIn = [ + './examples/subfolder/subfile.txt', + './examples/company.js', + './index.html' + ]; + const filesOut = [ + './examples/subfolder/anotherfolder/anotherfile.txt', + './more/file.txt' + ]; + + const cmd1 = walker.spawnFindCmd(rootfolders()[0], glob.parse({ + '**/subfolder/anotherfolder': true, + '**/something/else': true, + '**/more': true, + '**/andmore': true + })); + walker.readStdout(cmd1, 'utf8', (err1, stdout1) => { + assert.equal(err1, null); + for (const fileIn of filesIn) { + assert.notStrictEqual(stdout1.split('\n').indexOf(fileIn), -1, stdout1); + } + for (const fileOut of filesOut) { + assert.strictEqual(stdout1.split('\n').indexOf(fileOut), -1, stdout1); + } + done(); + }); + }); + test('Text: GameOfLife', function (done: () => void) { let c = 0; let config = { From e8b516b34b0f01c0588297b14f6cd44d6ea94853 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 4 Oct 2016 18:40:05 -0700 Subject: [PATCH 046/163] Revert "Set line-height of xterm.js' text area to 0" This reverts commit 8bd60949abfca8cb88fef8f406bf0152e324fced. --- src/vs/workbench/parts/terminal/electron-browser/media/xterm.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css index 57e37d10f41..24d687abcee 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css +++ b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css @@ -42,7 +42,6 @@ width: 0; height: 0; z-index: -10; - line-height: 0; } .monaco-workbench .panel.integrated-terminal .xterm .xterm-helper-textarea:focus { From 23517f013ab919a5296a5d33af7f6cb9775f6219 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Tue, 4 Oct 2016 18:44:43 -0700 Subject: [PATCH 047/163] Add top to xterm.js' textarea Fixes #12038 --- src/vs/workbench/parts/terminal/electron-browser/media/xterm.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css index 24d687abcee..5e80769f86f 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css +++ b/src/vs/workbench/parts/terminal/electron-browser/media/xterm.css @@ -38,6 +38,7 @@ * Move textarea out of the screen to the far left, so that the cursor is not visible. */ left: -9999em; + top: -9999em; opacity: 0; width: 0; height: 0; From 8ba8ad18268290d377aeaf7143ab693c033eb896 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 09:02:14 +0200 Subject: [PATCH 048/163] bump to version 1.7.0 --- npm-shrinkwrap.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index c9f5485d0b8..76aace80bf5 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "code-oss-dev", - "version": "1.6.0", + "version": "1.7.0", "dependencies": { "agent-base": { "version": "1.0.2", diff --git a/package.json b/package.json index b1a20925add..7771417ae5d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "code-oss-dev", - "version": "1.6.0", + "version": "1.7.0", "electronVersion": "1.3.7", "distro": "b1e023235579beebbb3cc127676cc91cc7f3e823", "author": { From 6d41cf4c90f46dbf06cc421f8cb4c75a6a17f00b Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 5 Oct 2016 09:03:51 +0200 Subject: [PATCH 049/163] nls --- .../parts/extensions/electron-browser/extensionEditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index aeceb42d2c5..b11c205167d 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -349,7 +349,7 @@ export class ExtensionEditor extends BaseEditor { $('tr', null, $('th', null, localize('setting name', "Name")), $('th', null, localize('description', "Description")), - $('th', null, localize('default', "Default")) + $('th', null, localize('default setting value', "Default")) ), ...contrib.map(key => $('tr', null, $('td', null, $('code', null, key)), From 223cb620ea48ebe45e053883373460b72dc2a441 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 5 Oct 2016 09:04:40 +0200 Subject: [PATCH 050/163] nls --- .../parts/extensions/electron-browser/extensionEditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index b11c205167d..aeceb42d2c5 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -349,7 +349,7 @@ export class ExtensionEditor extends BaseEditor { $('tr', null, $('th', null, localize('setting name', "Name")), $('th', null, localize('description', "Description")), - $('th', null, localize('default setting value', "Default")) + $('th', null, localize('default', "Default")) ), ...contrib.map(key => $('tr', null, $('td', null, $('code', null, key)), From d99136f6ba7d8b1a43d4a0fbb006e7ba9234effb Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 09:05:31 +0200 Subject: [PATCH 051/163] change scope to editor/title/context --- src/vs/platform/actions/browser/menusExtensionPoint.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 8c9d818d1b1..ec73d5f1e3e 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -30,7 +30,7 @@ namespace schema { case 'editor/title': return MenuId.EditorTitle; case 'editor/context': return MenuId.EditorContext; case 'explorer/context': return MenuId.ExplorerContext; - case 'editortab/context': return MenuId.EditorTabContext; + case 'editor/title/context': return MenuId.EditorTabContext; } } From b7a8be16d4c9d5a9449fb7922fccf127bffe9056 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 09:06:48 +0200 Subject: [PATCH 052/163] also update schema --- src/vs/platform/actions/browser/menusExtensionPoint.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index ec73d5f1e3e..40f51309200 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -98,7 +98,7 @@ namespace schema { type: 'array', items: menuItem }, - 'editortab/context': { + 'editor/title/context': { description: localize('menus.editorTabContext', "The editor tabs context menu"), type: 'array', items: menuItem From 622797234dbc08eae803667ecb6a1b9c6bd66d72 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 09:21:50 +0200 Subject: [PATCH 053/163] more mime reduction --- .../parts/debug/browser/debugEditorInputs.ts | 6 ++--- .../files/browser/editors/textFileEditor.ts | 6 ++--- .../parts/files/browser/saveErrorHandler.ts | 9 ++------ src/vs/workbench/parts/files/common/files.ts | 2 -- .../output/browser/output.contribution.ts | 5 ++--- .../parts/output/browser/outputEditorInput.ts | 4 ++-- .../workbench/parts/output/common/output.ts | 5 ----- .../browser/parts/editor/baseEditor.test.ts | 16 +++++++------- .../common/editor/stringEditorInput.test.ts | 22 +++++++++---------- .../common/editor/stringEditorModel.test.ts | 4 ++-- 10 files changed, 33 insertions(+), 46 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/debugEditorInputs.ts b/src/vs/workbench/parts/debug/browser/debugEditorInputs.ts index 6cde849cf52..a5c38c3e137 100644 --- a/src/vs/workbench/parts/debug/browser/debugEditorInputs.ts +++ b/src/vs/workbench/parts/debug/browser/debugEditorInputs.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import {TPromise} from 'vs/base/common/winjs.base'; -import mime = require('vs/base/common/mime'); +import {PLAINTEXT_MODE_ID} from 'vs/editor/common/modes/modesRegistry'; import strinput = require('vs/workbench/common/editor/stringEditorInput'); import {EditorInput, EditorModel} from 'vs/workbench/common/editor'; import uri from 'vs/base/common/uri'; @@ -17,11 +17,11 @@ export class DebugStringEditorInput extends strinput.StringEditorInput { private resourceUrl: uri, description: string, value: string, - mimeType: string, + modeId: string, singleton: boolean, @IInstantiationService instantiationService: IInstantiationService ) { - super(name, description, value, mimeType || mime.MIME_TEXT, singleton, instantiationService); + super(name, description, value, modeId || PLAINTEXT_MODE_ID, singleton, instantiationService); } public getResource(): uri { diff --git a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts index eb634f695e5..ffbef7832e4 100644 --- a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts @@ -119,8 +119,8 @@ export class TextFileEditor extends BaseTextEditor { // Different Input (Reload) return this.editorService.resolveEditorModel(input, true /* Reload */).then(resolvedModel => { - // There is a special case where the text editor has to handle binary file editor input: if a file with application/unknown - // mime has been resolved and cached before, it maybe an actual instance of BinaryEditorModel. In this case our text + // There is a special case where the text editor has to handle binary file editor input: if a binary file + // has been resolved and cached before, it maybe an actual instance of BinaryEditorModel. In this case our text // editor has to open this model using the binary editor. We return early in this case. if (resolvedModel instanceof BinaryEditorModel) { return this.openAsBinary(input, options); @@ -161,7 +161,7 @@ export class TextFileEditor extends BaseTextEditor { // In case we tried to open a file inside the text editor and the response // indicates that this is not a text file, reopen the file through the binary - // editor by using application/octet-stream as mime. + // editor. if ((error).fileOperationResult === FileOperationResult.FILE_IS_BINARY) { return this.openAsBinary(input, options); } diff --git a/src/vs/workbench/parts/files/browser/saveErrorHandler.ts b/src/vs/workbench/parts/files/browser/saveErrorHandler.ts index b31911389a6..e4ebe91c532 100644 --- a/src/vs/workbench/parts/files/browser/saveErrorHandler.ts +++ b/src/vs/workbench/parts/files/browser/saveErrorHandler.ts @@ -13,7 +13,6 @@ import {Action} from 'vs/base/common/actions'; import URI from 'vs/base/common/uri'; import product from 'vs/platform/product'; import {EditorModel} from 'vs/workbench/common/editor'; -import {guessMimeTypes} from 'vs/base/common/mime'; import {EditorInputAction} from 'vs/workbench/browser/parts/editor/baseEditor'; import {ResourceEditorInput} from 'vs/workbench/common/editor/resourceEditorInput'; import {DiffEditorInput} from 'vs/workbench/common/editor/diffEditorInput'; @@ -174,12 +173,10 @@ export class ConflictResolutionDiffEditorInput extends DiffEditorInput { export class FileOnDiskEditorInput extends ResourceEditorInput { private fileResource: URI; private lastModified: number; - private mime: string; private createdEditorModel: boolean; constructor( fileResource: URI, - mime: string, name: string, description: string, @IModelService modelService: IModelService, @@ -193,7 +190,6 @@ export class FileOnDiskEditorInput extends ResourceEditorInput { super(name, description, URI.from({ scheme: 'disk', path: fileResource.fsPath }), modelService, instantiationService); this.fileResource = fileResource; - this.mime = mime; } public getLastModified(): number { @@ -208,7 +204,7 @@ export class FileOnDiskEditorInput extends ResourceEditorInput { const codeEditorModel = this.modelService.getModel(this.resource); if (!codeEditorModel) { - this.modelService.createModel(content.value, this.modeService.getOrCreateMode(this.mime), this.resource); + this.modelService.createModel(content.value, this.modeService.getOrCreateModeByFilenameOrFirstLine(this.resource.fsPath), this.resource); this.createdEditorModel = true; } else { codeEditorModel.setValueFromRawText(content.value); @@ -261,8 +257,7 @@ class ResolveSaveConflictMessage implements IMessageWithAction { this.actions = [ new Action('workbench.files.action.resolveConflict', nls.localize('compareChanges', "Compare"), null, true, () => { if (!this.model.isDisposed()) { - const mime = guessMimeTypes(resource.fsPath).join(', '); - const originalInput = this.instantiationService.createInstance(FileOnDiskEditorInput, resource, mime, paths.basename(resource.fsPath), resource.fsPath); + const originalInput = this.instantiationService.createInstance(FileOnDiskEditorInput, resource, paths.basename(resource.fsPath), resource.fsPath); const modifiedInput = this.instantiationService.createInstance(FileEditorInput, resource, void 0); const conflictInput = this.instantiationService.createInstance(ConflictResolutionDiffEditorInput, this.model, nls.localize('saveConflictDiffLabel', "{0} (on disk) ↔ {1} (in {2})", modifiedInput.getName(), modifiedInput.getName(), product.nameLong), nls.localize('resolveSaveConflict', "Resolve save conflict"), originalInput, modifiedInput); diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index 2525244dea5..05934c194d3 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -72,7 +72,6 @@ export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEdit export interface IFileResource { resource: URI; isDirectory: boolean; - mimes: string[]; } /** @@ -84,7 +83,6 @@ export function asFileResource(obj: any): IFileResource { return { resource: stat.resource, - mimes: stat.mime ? stat.mime.split(', ') : [], isDirectory: stat.isDirectory }; } diff --git a/src/vs/workbench/parts/output/browser/output.contribution.ts b/src/vs/workbench/parts/output/browser/output.contribution.ts index 9dae48a6029..97efc2508a0 100644 --- a/src/vs/workbench/parts/output/browser/output.contribution.ts +++ b/src/vs/workbench/parts/output/browser/output.contribution.ts @@ -15,7 +15,7 @@ import {registerSingleton} from 'vs/platform/instantiation/common/extensions'; import {IWorkbenchActionRegistry, Extensions as ActionExtensions} from 'vs/workbench/common/actionRegistry'; import {OutputService} from 'vs/workbench/parts/output/browser/outputServices'; import {ToggleOutputAction, ClearOutputAction} from 'vs/workbench/parts/output/browser/outputActions'; -import {OUTPUT_MIME, OUTPUT_MODE_ID, OUTPUT_PANEL_ID, IOutputService} from 'vs/workbench/parts/output/common/output'; +import {OUTPUT_MODE_ID, OUTPUT_PANEL_ID, IOutputService} from 'vs/workbench/parts/output/common/output'; import panel = require('vs/workbench/browser/panel'); import {EditorContextKeys} from 'vs/editor/common/editorCommon'; import {CommandsRegistry, ICommandHandler} from 'vs/platform/commands/common/commands'; @@ -28,8 +28,7 @@ registerSingleton(IOutputService, OutputService); ModesRegistry.registerLanguage({ id: OUTPUT_MODE_ID, extensions: [], - aliases: [null], - mimetypes: [OUTPUT_MIME] + aliases: [null] }); // Register Output Panel diff --git a/src/vs/workbench/parts/output/browser/outputEditorInput.ts b/src/vs/workbench/parts/output/browser/outputEditorInput.ts index 1f78496046b..54a73eb81e2 100644 --- a/src/vs/workbench/parts/output/browser/outputEditorInput.ts +++ b/src/vs/workbench/parts/output/browser/outputEditorInput.ts @@ -11,7 +11,7 @@ import {TPromise} from 'vs/base/common/winjs.base'; import {RunOnceScheduler} from 'vs/base/common/async'; import {EditorModel} from 'vs/workbench/common/editor'; import {StringEditorInput} from 'vs/workbench/common/editor/stringEditorInput'; -import {OUTPUT_EDITOR_INPUT_ID, OUTPUT_PANEL_ID, IOutputEvent, OUTPUT_MIME, IOutputService, MAX_OUTPUT_LENGTH, IOutputChannel} from 'vs/workbench/parts/output/common/output'; +import {OUTPUT_EDITOR_INPUT_ID, OUTPUT_PANEL_ID, IOutputEvent, OUTPUT_MODE_ID, IOutputService, MAX_OUTPUT_LENGTH, IOutputChannel} from 'vs/workbench/parts/output/common/output'; import {OutputPanel} from 'vs/workbench/parts/output/browser/outputPanel'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {IPanelService} from 'vs/workbench/services/panel/common/panelService'; @@ -49,7 +49,7 @@ export class OutputEditorInput extends StringEditorInput { @IOutputService private outputService: IOutputService, @IPanelService private panelService: IPanelService ) { - super(nls.localize('output', "Output"), outputChannel ? nls.localize('outputChannel', "for '{0}'", outputChannel.label) : '', '', OUTPUT_MIME, true, instantiationService); + super(nls.localize('output', "Output"), outputChannel ? nls.localize('outputChannel', "for '{0}'", outputChannel.label) : '', '', OUTPUT_MODE_ID, true, instantiationService); this.bufferedOutput = ''; this.toDispose = []; diff --git a/src/vs/workbench/parts/output/common/output.ts b/src/vs/workbench/parts/output/common/output.ts index 88b1a82730f..4b9379120fa 100644 --- a/src/vs/workbench/parts/output/common/output.ts +++ b/src/vs/workbench/parts/output/common/output.ts @@ -11,11 +11,6 @@ import {createDecorator} from 'vs/platform/instantiation/common/instantiation'; import {IEditor} from 'vs/platform/editor/common/editor'; import {RawContextKey} from 'vs/platform/contextkey/common/contextkey'; -/** - * Mime type used by the output editor. - */ -export const OUTPUT_MIME = 'text/x-code-output'; - /** * Id used by the output editor. */ diff --git a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts index 7899059e316..c21a26a2d9e 100644 --- a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts @@ -14,7 +14,7 @@ import * as Platform from 'vs/platform/platform'; import {SyncDescriptor} from 'vs/platform/instantiation/common/descriptors'; import {StringEditorInput} from 'vs/workbench/common/editor/stringEditorInput'; import {ITelemetryService, NullTelemetryService} from 'vs/platform/telemetry/common/telemetry'; -import mime = require('vs/base/common/mime'); +import {PLAINTEXT_MODE_ID} from 'vs/editor/common/modes/modesRegistry'; let EditorRegistry: IEditorRegistry = Platform.Registry.as(Extensions.Editors); @@ -189,10 +189,10 @@ suite('Workbench BaseEditor', () => { let inst = new TestInstantiationService(); - inst.createInstance(EditorRegistry.getEditor(inst.createInstance(MyStringInput, 'fake', '', '', mime.MIME_TEXT, false)), 'id').then(editor => { + inst.createInstance(EditorRegistry.getEditor(inst.createInstance(MyStringInput, 'fake', '', '', PLAINTEXT_MODE_ID, false)), 'id').then(editor => { assert.strictEqual(editor.getId(), 'myEditor'); - return inst.createInstance(EditorRegistry.getEditor(inst.createInstance(StringEditorInput, 'fake', '', '', mime.MIME_TEXT, false)), 'id').then(editor => { + return inst.createInstance(EditorRegistry.getEditor(inst.createInstance(StringEditorInput, 'fake', '', '', PLAINTEXT_MODE_ID, false)), 'id').then(editor => { assert.strictEqual(editor.getId(), 'myOtherEditor'); (EditorRegistry).setEditors(oldEditors); @@ -210,7 +210,7 @@ suite('Workbench BaseEditor', () => { let inst = new TestInstantiationService(); - inst.createInstance(EditorRegistry.getEditor(inst.createInstance(MyStringInput, 'fake', '', '', mime.MIME_TEXT, false)), 'id').then(editor => { + inst.createInstance(EditorRegistry.getEditor(inst.createInstance(MyStringInput, 'fake', '', '', PLAINTEXT_MODE_ID, false)), 'id').then(editor => { assert.strictEqual('myOtherEditor', editor.getId()); (EditorRegistry).setEditors(oldEditors); @@ -221,7 +221,7 @@ suite('Workbench BaseEditor', () => { let inst = new TestInstantiationService(); let action = new MyAction('id', 'label'); - action.input = inst.createInstance(StringEditorInput, 'input', '', '', mime.MIME_TEXT, false); + action.input = inst.createInstance(StringEditorInput, 'input', '', '', PLAINTEXT_MODE_ID, false); assert.equal(action.didCallIsEnabled, true); }); @@ -231,12 +231,12 @@ suite('Workbench BaseEditor', () => { let contributor = new MyEditorInputActionContributor(); assert(!contributor.hasActions(null)); - assert(contributor.hasActions({ editor: new MyEditor('id', NullTelemetryService), input: inst.createInstance(StringEditorInput, 'fake', '', '', mime.MIME_TEXT, false), position: 0 })); + assert(contributor.hasActions({ editor: new MyEditor('id', NullTelemetryService), input: inst.createInstance(StringEditorInput, 'fake', '', '', PLAINTEXT_MODE_ID, false), position: 0 })); - let actionsFirst = contributor.getActions({ editor: new MyEditor('id', NullTelemetryService), input: inst.createInstance(StringEditorInput, 'fake', '', '', mime.MIME_TEXT, false), position: 0 }); + let actionsFirst = contributor.getActions({ editor: new MyEditor('id', NullTelemetryService), input: inst.createInstance(StringEditorInput, 'fake', '', '', PLAINTEXT_MODE_ID, false), position: 0 }); assert.strictEqual(actionsFirst.length, 2); - let input = inst.createInstance(StringEditorInput, 'fake', '', '', mime.MIME_TEXT, false); + let input = inst.createInstance(StringEditorInput, 'fake', '', '', PLAINTEXT_MODE_ID, false); let actions = contributor.getActions({ editor: new MyEditor('id', NullTelemetryService), input: input, position: 0 }); assert(actions[0] === actionsFirst[0]); assert(actions[1] === actionsFirst[1]); diff --git a/src/vs/workbench/test/common/editor/stringEditorInput.test.ts b/src/vs/workbench/test/common/editor/stringEditorInput.test.ts index 57158059545..e0090fd3f5d 100644 --- a/src/vs/workbench/test/common/editor/stringEditorInput.test.ts +++ b/src/vs/workbench/test/common/editor/stringEditorInput.test.ts @@ -32,12 +32,12 @@ suite('Workbench - StringEditorInput', () => { test('StringEditorInput', function (done) { - let input = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mime', false); - let otherInput = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'othervalue', 'mime', false); - let otherInputSame = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mime', false); + let input = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', false); + let otherInput = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'othervalue', 'mode', false); + let otherInputSame = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', false); - let inputSingleton = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mime', true); - let otherInputSingleton = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'othervalue', 'mime', true); + let inputSingleton = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', true); + let otherInputSingleton = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'othervalue', 'mode', true); assert(inputSingleton.matches(otherInputSingleton)); (otherInputSingleton).singleton = false; assert(!inputSingleton.matches(otherInputSingleton)); @@ -48,15 +48,15 @@ suite('Workbench - StringEditorInput', () => { assert(!input.matches(null)); assert(input.getName()); - input = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mime', false); + input = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', false); - input = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mime', false); + input = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', false); editorService.resolveEditorModel(input, true).then(resolved => { let resolvedModelA = resolved; return editorService.resolveEditorModel(input, true).then(resolved => { assert(resolvedModelA === resolved); // assert: Resolved Model cached per instance - let otherInput = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mime', false); + let otherInput = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', false); return editorService.resolveEditorModel(otherInput, true).then(resolved => { assert(resolvedModelA !== resolved); // NOT assert: Different instance, different model @@ -78,7 +78,7 @@ suite('Workbench - StringEditorInput', () => { }); test('StringEditorInput - setValue, clearValue, append', function () { - let input = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mime', false); + let input = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', false); assert.strictEqual(input.getValue(), 'value'); input.setValue('foo'); @@ -94,10 +94,10 @@ suite('Workbench - StringEditorInput', () => { test('Input.matches() - StringEditorInput', function () { let inst = new TestInstantiationService(); - let stringEditorInput = inst.createInstance(StringEditorInput, 'name', 'description', 'value', 'mime', false); + let stringEditorInput = inst.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', false); let promiseEditorInput = inst.createInstance(ResourceEditorInput, 'name', 'description', URI.from({ scheme: 'inMemory', authority: null, path: 'thePath' })); - let stringEditorInput2 = inst.createInstance(StringEditorInput, 'name', 'description', 'value', 'mime', false); + let stringEditorInput2 = inst.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', false); let promiseEditorInput2 = inst.createInstance(ResourceEditorInput, 'name', 'description', URI.from({ scheme: 'inMemory', authority: null, path: 'thePath' })); assert.strictEqual(stringEditorInput.matches(null), false); diff --git a/src/vs/workbench/test/common/editor/stringEditorModel.test.ts b/src/vs/workbench/test/common/editor/stringEditorModel.test.ts index dab7dae73ac..d36f66ca699 100644 --- a/src/vs/workbench/test/common/editor/stringEditorModel.test.ts +++ b/src/vs/workbench/test/common/editor/stringEditorModel.test.ts @@ -23,7 +23,7 @@ suite('Workbench - StringEditorModel', () => { test('StringEditorModel', function (done) { instantiationService.stub(IModelService, createMockModelService(instantiationService)); - let m = instantiationService.createInstance(StringEditorModel, 'value', 'mime', null); + let m = instantiationService.createInstance(StringEditorModel, 'value', 'mode', null); m.load().then(model => { assert(model === m); @@ -45,7 +45,7 @@ suite('Workbench - StringEditorModel', () => { test('StringEditorModel - setValue, clearValue, append, trim', function (done) { instantiationService.stub(IModelService, createMockModelService(instantiationService)); - let m = instantiationService.createInstance(StringEditorModel, 'value', 'mime', null); + let m = instantiationService.createInstance(StringEditorModel, 'value', 'mode', null); m.load().then(model => { assert(model === m); From 89be12324c0868deb75a737bf3437c05edb4cd55 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 5 Oct 2016 09:22:17 +0200 Subject: [PATCH 054/163] fixes #13178 --- .../parts/extensions/electron-browser/extensionEditor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index aeceb42d2c5..01a24d3b11c 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -165,7 +165,7 @@ export class ExtensionEditor extends BaseEditor { const details = append(header, $('.details')); const title = append(details, $('.title')); this.name = append(title, $('span.name.clickable')); - this.identifier = append(title, $('span.identifier')); + this.identifier = append(title, $('span.identifier', { title: localize('extension id', "Extension identifier") })); const subtitle = append(details, $('.subtitle')); this.publisher = append(subtitle, $('span.publisher.clickable')); From 7d14e26db058bfa411db9aef447941353753669b Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 5 Oct 2016 09:25:55 +0200 Subject: [PATCH 055/163] fixes #13179 --- .../parts/extensions/electron-browser/extensionEditor.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 01a24d3b11c..f31ab5598ab 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -164,15 +164,15 @@ export class ExtensionEditor extends BaseEditor { const details = append(header, $('.details')); const title = append(details, $('.title')); - this.name = append(title, $('span.name.clickable')); + this.name = append(title, $('span.name.clickable', { title: localize('name', "Extension name") })); this.identifier = append(title, $('span.identifier', { title: localize('extension id', "Extension identifier") })); const subtitle = append(details, $('.subtitle')); - this.publisher = append(subtitle, $('span.publisher.clickable')); + this.publisher = append(subtitle, $('span.publisher.clickable', { title: localize('publisher', "Publisher name") })); - this.installCount = append(subtitle, $('span.install')); + this.installCount = append(subtitle, $('span.install', { title: localize('install count', "Install count") })); - this.rating = append(subtitle, $('span.rating.clickable')); + this.rating = append(subtitle, $('span.rating.clickable', { title: localize('rating', "Rating") })); this.license = append(subtitle, $('span.license.clickable')); this.license.textContent = localize('license', 'License'); From ef59b96b50583fb81db37b4bf8301e742a944626 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 5 Oct 2016 09:30:12 +0200 Subject: [PATCH 056/163] remove rating count fixes #13180 --- .../parts/extensions/electron-browser/extensionsWidgets.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts index 9ffb1cd1d82..dc9a8da8678 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts @@ -133,6 +133,9 @@ export class RatingsWidget implements IDisposable { if (this.options.small) { append(this.container, $('span.full.star')); + + const count = append(this.container, $('span.count')); + count.textContent = String(rating); } else { for (let i = 1; i <= 5; i++) { if (rating >= i) { @@ -144,9 +147,6 @@ export class RatingsWidget implements IDisposable { } } } - - const count = append(this.container, $('span.count')); - count.textContent = String(this.options.small ? rating : this.extension.ratingCount); } dispose(): void { From 3b1c07b118a05a2b061c14f9eba469aee2e2f5fe Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 09:34:02 +0200 Subject: [PATCH 057/163] debt: remove mime traces from files land --- src/vs/platform/files/common/files.ts | 8 +------- src/vs/test/utils/servicesTestUtils.ts | 7 +------ .../cli/electron-browser/cli.contribution.ts | 2 +- .../parts/files/browser/views/explorerView.ts | 3 --- .../files/common/editors/textFileEditorModel.ts | 6 +++--- .../parts/files/common/explorerViewModel.ts | 12 +++--------- .../files/electron-browser/textFileService.ts | 1 - .../test/browser/explorerViewModel.test.ts | 17 ++++++++--------- .../files/test/browser/fileEditorInput.test.ts | 3 +-- .../browser/textFileEditorModelManager.test.ts | 3 +-- .../services/files/node/fileService.ts | 16 +++------------- 11 files changed, 22 insertions(+), 56 deletions(-) diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 3b4c241d8e5..c01f2c3598f 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -307,12 +307,6 @@ export interface IBaseStat { * current state of the file or directory. */ etag: string; - - /** - * The mime type string. Applicate for files - * only. - */ - mime: string; } /** @@ -322,7 +316,7 @@ export interface IFileStat extends IBaseStat { /** * The resource is a directory. Iff {{true}} - * {{mime}} and {{encoding}} have no meaning. + * {{encoding}} has no meaning. */ isDirectory: boolean; diff --git a/src/vs/test/utils/servicesTestUtils.ts b/src/vs/test/utils/servicesTestUtils.ts index 483beed9908..6af456e2756 100644 --- a/src/vs/test/utils/servicesTestUtils.ts +++ b/src/vs/test/utils/servicesTestUtils.ts @@ -139,7 +139,6 @@ export class TestTextFileService extends TextFileService { name: content.name, mtime: content.mtime, etag: content.etag, - mime: content.mime, encoding: content.encoding, value: raw, valueLogicalHash: null @@ -255,7 +254,7 @@ export class TestPartService implements IPartService { public getWorkbenchElementId(): string { return ''; } public setRestoreSidebar(): void { - + } } @@ -523,7 +522,6 @@ export const TestFileService = { resource: resource, value: 'Hello Html', etag: 'index.txt', - mime: 'text/plain', encoding: 'utf8', mtime: Date.now(), name: paths.basename(resource.fsPath) @@ -534,7 +532,6 @@ export const TestFileService = { return TPromise.as({ resource: resource, etag: Date.now(), - mime: 'text/plain', encoding: 'utf8', mtime: Date.now(), name: paths.basename(resource.fsPath) @@ -555,7 +552,6 @@ export const TestFileService = { } }, etag: 'index.txt', - mime: 'text/plain', encoding: 'utf8', mtime: Date.now(), name: paths.basename(resource.fsPath) @@ -567,7 +563,6 @@ export const TestFileService = { return { resource: res, etag: 'index.txt', - mime: 'text/plain', encoding: 'utf8', mtime: Date.now(), name: paths.basename(res.fsPath) diff --git a/src/vs/workbench/parts/cli/electron-browser/cli.contribution.ts b/src/vs/workbench/parts/cli/electron-browser/cli.contribution.ts index 43cf9dcf42e..4fd7d974ec2 100644 --- a/src/vs/workbench/parts/cli/electron-browser/cli.contribution.ts +++ b/src/vs/workbench/parts/cli/electron-browser/cli.contribution.ts @@ -72,7 +72,7 @@ class InstallAction extends Action { ); const resource = URI.file(file); - const input = { resource, mime: 'text/x-shellscript' }; + const input = { resource }; const actions = [ new Action('inlineEdit', nls.localize('editFile', "Edit '{0}'", file), '', true, () => { return this.editorService.openEditor(input).then(() => { diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index fcc828278dd..9e101f8d307 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -412,9 +412,6 @@ export class ExplorerView extends CollapsibleViewletView { if (oldParentResource && newParentResource && oldParentResource.toString() === newParentResource.toString()) { modelElement = this.getInput().find(oldElement.resource); if (modelElement) { - if (!modelElement.isDirectory && !modelElement.mime) { - return; - } // Rename File (Model) modelElement.rename(newElement); diff --git a/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts b/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts index ba61631308e..434c5c139fa 100644 --- a/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts +++ b/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts @@ -8,6 +8,7 @@ import nls = require('vs/nls'); import Event, {Emitter} from 'vs/base/common/event'; import {TPromise} from 'vs/base/common/winjs.base'; import {onUnexpectedError} from 'vs/base/common/errors'; +import {guessMimeTypes} from 'vs/base/common/mime'; import {toErrorMessage} from 'vs/base/common/errorMessage'; import URI from 'vs/base/common/uri'; import * as assert from 'vs/base/common/assert'; @@ -204,7 +205,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil diag('load() - resolved content', this.resource, new Date()); // Telemetry - this.telemetryService.publicLog('fileGet', { mimeType: content.mime, ext: paths.extname(this.resource.fsPath), path: anonymize(this.resource.fsPath) }); + this.telemetryService.publicLog('fileGet', { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), ext: paths.extname(this.resource.fsPath), path: anonymize(this.resource.fsPath) }); // Update our resolved disk stat model const resolvedStat: IFileStat = { @@ -212,7 +213,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil name: content.name, mtime: content.mtime, etag: content.etag, - mime: content.mime, isDirectory: false, hasChildren: false, children: void 0, @@ -489,7 +489,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil delete this.mapPendingSaveToVersionId[versionId]; // Telemetry - this.telemetryService.publicLog('filePUT', { mimeType: stat.mime, ext: paths.extname(this.versionOnDiskStat.resource.fsPath) }); + this.telemetryService.publicLog('filePUT', { mimeType: guessMimeTypes(this.resource.fsPath).join(', '), ext: paths.extname(this.versionOnDiskStat.resource.fsPath) }); // Update dirty state unless model has changed meanwhile if (versionId === this.versionId) { diff --git a/src/vs/workbench/parts/files/common/explorerViewModel.ts b/src/vs/workbench/parts/files/common/explorerViewModel.ts index 11b2a496828..3a8cbe6143b 100644 --- a/src/vs/workbench/parts/files/common/explorerViewModel.ts +++ b/src/vs/workbench/parts/files/common/explorerViewModel.ts @@ -10,7 +10,6 @@ import URI from 'vs/base/common/uri'; import {isLinux} from 'vs/base/common/platform'; import paths = require('vs/base/common/paths'); import {IFileStat} from 'vs/platform/files/common/files'; -import {guessMimeTypes} from 'vs/base/common/mime'; export enum StatType { FILE, @@ -23,7 +22,6 @@ export class FileStat implements IFileStat { public name: string; public mtime: number; public etag: string; - public mime: string; public isDirectory: boolean; public hasChildren: boolean; public children: FileStat[]; @@ -31,12 +29,11 @@ export class FileStat implements IFileStat { public isDirectoryResolved: boolean; - constructor(resource: URI, isDirectory?: boolean, hasChildren?: boolean, name: string = paths.basename(resource.fsPath), mime = !isDirectory ? guessMimeTypes(resource.fsPath).join(', ') : void (0), mtime?: number, etag?: string) { + constructor(resource: URI, isDirectory?: boolean, hasChildren?: boolean, name: string = paths.basename(resource.fsPath), mtime?: number, etag?: string) { this.resource = resource; this.name = name; this.isDirectory = !!isDirectory; this.hasChildren = isDirectory && hasChildren; - this.mime = mime; this.etag = etag; this.mtime = mtime; @@ -53,7 +50,7 @@ export class FileStat implements IFileStat { } public static create(raw: IFileStat, resolveTo?: URI[]): FileStat { - const stat = new FileStat(raw.resource, raw.isDirectory, raw.hasChildren, raw.name, raw.mime, raw.mtime, raw.etag); + const stat = new FileStat(raw.resource, raw.isDirectory, raw.hasChildren, raw.name, raw.mtime, raw.etag); // Recursively add children if present if (stat.isDirectory) { @@ -99,7 +96,6 @@ export class FileStat implements IFileStat { local.isDirectory = disk.isDirectory; local.hasChildren = disk.isDirectory && disk.hasChildren; local.mtime = disk.mtime; - local.mime = disk.mime; local.isDirectoryResolved = disk.isDirectoryResolved; // Merge Children if resolved @@ -138,7 +134,7 @@ export class FileStat implements IFileStat { * Returns a deep copy of this model object. */ public clone(): FileStat { - const stat = new FileStat(URI.parse(this.resource.toString()), this.isDirectory, this.hasChildren, this.name, this.mime, this.mtime, this.etag); + const stat = new FileStat(URI.parse(this.resource.toString()), this.isDirectory, this.hasChildren, this.name, this.mtime, this.etag); stat.isDirectoryResolved = this.isDirectoryResolved; if (this.parent) { @@ -248,7 +244,6 @@ export class FileStat implements IFileStat { // Merge a subset of Properties that can change on rename this.name = renamedStat.name; - this.mime = renamedStat.mime; this.mtime = renamedStat.mtime; // Update Paths including children @@ -320,7 +315,6 @@ export class NewStatPlaceholder extends FileStat { this.isDirectory = void 0; this.hasChildren = void 0; this.mtime = void 0; - this.mime = void 0; } public getId(): string { diff --git a/src/vs/workbench/parts/files/electron-browser/textFileService.ts b/src/vs/workbench/parts/files/electron-browser/textFileService.ts index 7dce42fb035..cba7157bd68 100644 --- a/src/vs/workbench/parts/files/electron-browser/textFileService.ts +++ b/src/vs/workbench/parts/files/electron-browser/textFileService.ts @@ -60,7 +60,6 @@ export class TextFileService extends AbstractTextFileService { name: streamContent.name, mtime: streamContent.mtime, etag: streamContent.etag, - mime: streamContent.mime, encoding: streamContent.encoding, value: res.rawText, valueLogicalHash: res.hash diff --git a/src/vs/workbench/parts/files/test/browser/explorerViewModel.test.ts b/src/vs/workbench/parts/files/test/browser/explorerViewModel.test.ts index d8995765a01..9bbf77918c7 100644 --- a/src/vs/workbench/parts/files/test/browser/explorerViewModel.test.ts +++ b/src/vs/workbench/parts/files/test/browser/explorerViewModel.test.ts @@ -10,13 +10,12 @@ import {isUndefinedOrNull, isArray} from 'vs/base/common/types'; import {isLinux, isWindows} from 'vs/base/common/platform'; import URI from 'vs/base/common/uri'; import {join} from 'vs/base/common/paths'; -import {guessMimeTypes} from 'vs/base/common/mime'; import {validateFileName} from 'vs/workbench/parts/files/browser/fileActions'; import {LocalFileChangeEvent} from 'vs/workbench/parts/files/common/files'; import {FileStat} from 'vs/workbench/parts/files/common/explorerViewModel'; function createStat(path, name, isFolder, hasChildren, size, mtime) { - return new FileStat(toResource(path), isFolder, hasChildren, name, !isFolder ? guessMimeTypes(path).join(', ') : null, mtime); + return new FileStat(toResource(path), isFolder, hasChildren, name, mtime); } function toResource(path) { @@ -240,9 +239,9 @@ suite('Files - View Model', () => { test('File Change Event (with stats)', function () { const d = new Date().toUTCString(); - const s1 = new FileStat(toResource('/path/to/sName'), false, false, 'sName', void 0, 8096 /* Size */, d); - const s2 = new FileStat(toResource('/path/to/sName'), false, false, 'sName', void 0, 16000 /* Size */, d); - const s3 = new FileStat(toResource('/path/to/sNameMoved'), false, false, 'sNameMoved', void 0, 8096 /* Size */, d); + const s1 = new FileStat(toResource('/path/to/sName'), false, false, 'sName', Date.now(), d); + const s2 = new FileStat(toResource('/path/to/sName'), false, false, 'sName', Date.now(), d); + const s3 = new FileStat(toResource('/path/to/sNameMoved'), false, false, 'sNameMoved', Date.now(), d); // Got Added let event = new LocalFileChangeEvent(null, s1); @@ -283,20 +282,20 @@ suite('Files - View Model', () => { test('Merge Local with Disk', function () { const d = new Date().toUTCString(); - const merge1 = new FileStat(URI.file(join('C:\\', '/path/to')), true, false, 'to', void 0, 8096, d); - const merge2 = new FileStat(URI.file(join('C:\\', '/path/to')), true, false, 'to', void 0, 16000, new Date(0).toUTCString()); + const merge1 = new FileStat(URI.file(join('C:\\', '/path/to')), true, false, 'to', Date.now(), d); + const merge2 = new FileStat(URI.file(join('C:\\', '/path/to')), true, false, 'to', Date.now(), new Date(0).toUTCString()); // Merge Properties FileStat.mergeLocalWithDisk(merge2, merge1); assert.strictEqual(merge1.mtime, merge2.mtime); // Merge Child when isDirectoryResolved=false is a no-op - merge2.addChild(new FileStat(URI.file(join('C:\\', '/path/to/foo.html')), true, false, 'foo.html', void 0, 8096, d)); + merge2.addChild(new FileStat(URI.file(join('C:\\', '/path/to/foo.html')), true, false, 'foo.html', Date.now(), d)); FileStat.mergeLocalWithDisk(merge2, merge1); assert.strictEqual(merge1.children.length, 0); // Merge Child with isDirectoryResolved=true - const child = new FileStat(URI.file(join('C:\\', '/path/to/foo.html')), true, false, 'foo.html', void 0, 8096, d); + const child = new FileStat(URI.file(join('C:\\', '/path/to/foo.html')), true, false, 'foo.html', Date.now(), d); merge2.removeChild(child); merge2.addChild(child); merge2.isDirectoryResolved = true; diff --git a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts index d01ff1e5e15..386678a4e7b 100644 --- a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts +++ b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts @@ -28,8 +28,7 @@ function toStat(resource: URI) { hasChildren: false, name: basename(resource.fsPath), mtime: Date.now(), - etag: 'etag', - mime: 'text/plain' + etag: 'etag' }; } diff --git a/src/vs/workbench/parts/files/test/browser/textFileEditorModelManager.test.ts b/src/vs/workbench/parts/files/test/browser/textFileEditorModelManager.test.ts index 21616e674c3..a9d909ad739 100644 --- a/src/vs/workbench/parts/files/test/browser/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/parts/files/test/browser/textFileEditorModelManager.test.ts @@ -38,8 +38,7 @@ function toStat(resource: URI) { hasChildren: false, name: basename(resource.fsPath), mtime: Date.now(), - etag: 'etag', - mime: 'text/plain' + etag: 'etag' }; } diff --git a/src/vs/workbench/services/files/node/fileService.ts b/src/vs/workbench/services/files/node/fileService.ts index 1851192c098..11f5b5f3c74 100644 --- a/src/vs/workbench/services/files/node/fileService.ts +++ b/src/vs/workbench/services/files/node/fileService.ts @@ -188,13 +188,7 @@ export class FileService implements IFileService { } // 2.) get content - return contentResolver(resource, options && options.etag, preferredEncoding).then(content => { - - // set our knowledge about the mime on the content obj - content.mime = detected.mimes.join(', '); - - return content; - }); + return contentResolver(resource, options && options.etag, preferredEncoding); }, (error) => { // bubble up existing file operation results @@ -678,7 +672,6 @@ export class StatResolver { private isDirectory: boolean; private mtime: number; private name: string; - private mime: string; private etag: string; private size: number; private verboseLogging: boolean; @@ -690,7 +683,6 @@ export class StatResolver { this.isDirectory = isDirectory; this.mtime = mtime; this.name = paths.basename(resource.fsPath); - this.mime = !this.isDirectory ? baseMime.guessMimeTypes(resource.fsPath).join(', ') : void 0; this.etag = etag(size, mtime); this.size = size; @@ -707,8 +699,7 @@ export class StatResolver { name: this.name, etag: this.etag, size: this.size, - mtime: this.mtime, - mime: this.mime + mtime: this.mtime }; // File Specific Data @@ -791,8 +782,7 @@ export class StatResolver { name: file, mtime: fileStat.mtime.getTime(), etag: etag(fileStat), - size: fileStat.size, - mime: !fileStat.isDirectory() ? baseMime.guessMimeTypes(fileResource.fsPath).join(', ') : void 0 + size: fileStat.size }; // Return early for files From 7e299e73a158d9c885856f2f3e3a6aabe494218e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 09:55:15 +0200 Subject: [PATCH 058/163] =?UTF-8?q?=F0=9F=92=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/editors/textFileEditorModel.ts | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts b/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts index 434c5c139fa..c40fdd64f28 100644 --- a/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts +++ b/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts @@ -446,24 +446,23 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // We DO NOT run any save participant if we are in the shutdown phase and files are being // saved as a result of that. let saveParticipantPromise = TPromise.as(versionId); - if (TextFileEditorModel.saveParticipant && !this.lifecycleService.willShutdown) { + const onCompleteOrError = () => { + this.blockModelContentChange = false; + + return this.versionId; + }; + saveParticipantPromise = TPromise.as(undefined).then(() => { this.blockModelContentChange = true; + return TextFileEditorModel.saveParticipant.participate(this, { reason }); - }).then(() => { - this.blockModelContentChange = false; - return this.versionId; - }, err => { - // ignore error and proceed as if nothing has happend - this.blockModelContentChange = false; - return this.versionId; - }); + }).then(onCompleteOrError, onCompleteOrError); } this.mapPendingSaveToVersionId[versionId] = saveParticipantPromise.then(newVersionId => { - // remove save participant promise and update versionId with + // remove save participant promise from pending saves and update versionId with // its new value (if pre-save changes happened) delete this.mapPendingSaveToVersionId[versionId]; versionId = newVersionId; @@ -477,8 +476,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Save to Disk diag(`doSave(${versionId}) - before updateContent()`, this.resource, new Date()); this.mapPendingSaveToVersionId[versionId] = this.fileService.updateContent(this.versionOnDiskStat.resource, this.getValue(), { - overwriteReadonly: overwriteReadonly, - overwriteEncoding: overwriteEncoding, + overwriteReadonly, + overwriteEncoding, mtime: this.versionOnDiskStat.mtime, encoding: this.getEncoding(), etag: this.versionOnDiskStat.etag From 2876e9cc9d1c5c38503c39fa45d980460c631e9e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 12:18:49 +0200 Subject: [PATCH 059/163] some fixes around usage of file editor input --- src/vs/workbench/common/editor.ts | 20 +++++------ .../files/browser/editors/binaryFileEditor.ts | 2 +- .../parts/files/browser/fileActions.ts | 7 ++-- .../files/browser/views/openEditorsViewer.ts | 12 ++----- .../git/browser/views/changes/changesView.ts | 5 ++- .../common/editor/rangeDecorations.test.ts | 34 +++++++++---------- 6 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index a62afe5e8f1..a8ee5aa2930 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -459,7 +459,7 @@ export class EditorOptions implements IEditorOptions { * Helper to create EditorOptions inline. */ public static create(settings: IEditorOptions): EditorOptions { - let options = new EditorOptions(); + const options = new EditorOptions(); options.preserveFocus = settings.preserveFocus; options.forceOpen = settings.forceOpen; options.revealIfVisible = settings.revealIfVisible; @@ -537,7 +537,7 @@ export class TextEditorOptions extends EditorOptions { } if (input.options.selection) { - let selection = input.options.selection; + const selection = input.options.selection; options.selection(selection.startLineNumber, selection.startColumn, selection.endLineNumber, selection.endColumn); } @@ -573,7 +573,7 @@ export class TextEditorOptions extends EditorOptions { * Helper to create TextEditorOptions inline. */ public static create(settings: ITextEditorOptions): TextEditorOptions { - let options = new TextEditorOptions(); + const options = new TextEditorOptions(); options.preserveFocus = settings.preserveFocus; options.forceOpen = settings.forceOpen; options.revealIfVisible = settings.revealIfVisible; @@ -660,7 +660,7 @@ export class TextEditorOptions extends EditorOptions { // Select if (!types.isUndefinedOrNull(this.endLineNumber) && !types.isUndefinedOrNull(this.endColumn)) { - let range = { + const range = { startLineNumber: this.startLineNumber, startColumn: this.startColumn, endLineNumber: this.endLineNumber, @@ -672,7 +672,7 @@ export class TextEditorOptions extends EditorOptions { // Reveal else { - let pos = { + const pos = { lineNumber: this.startLineNumber, column: this.startColumn }; @@ -705,7 +705,7 @@ export class TextDiffEditorOptions extends TextEditorOptions { * Helper to create TextDiffEditorOptions inline. */ public static create(settings: ITextDiffEditorOptions): TextDiffEditorOptions { - let options = new TextDiffEditorOptions(); + const options = new TextDiffEditorOptions(); options.autoRevealFirstChange = settings.autoRevealFirstChange; @@ -746,7 +746,7 @@ export function getUntitledOrFileResource(input: IEditorInput, supportDiff?: boo } // File - let fileInput = asFileEditorInput(input, supportDiff); + const fileInput = asFileEditorInput(input, supportDiff); return fileInput && fileInput.getResource(); } @@ -754,7 +754,7 @@ export function getUntitledOrFileResource(input: IEditorInput, supportDiff?: boo // TODO@Ben every editor should have an associated resource export function getResource(input: IEditorInput): URI { if (input instanceof EditorInput && typeof (input).getResource === 'function') { - let candidate = (input).getResource(); + const candidate = (input).getResource(); if (candidate instanceof URI) { return candidate; } @@ -795,9 +795,9 @@ export function asFileEditorInput(obj: any, supportDiff?: boolean): IFileEditorI obj = (obj).modifiedInput; } - let i = obj; + const i = obj; - return i instanceof EditorInput && types.areFunctions(i.setResource, i.setEncoding, i.getEncoding, i.getResource) ? i : null; + return i instanceof EditorInput && types.areFunctions(i.setResource, i.setEncoding, i.getEncoding, i.getResource, i.setPreferredEncoding) ? i : null; } export interface IStacksModelChangeEvent { diff --git a/src/vs/workbench/parts/files/browser/editors/binaryFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/binaryFileEditor.ts index efcceabb886..0a23a31c342 100644 --- a/src/vs/workbench/parts/files/browser/editors/binaryFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/binaryFileEditor.ts @@ -11,7 +11,7 @@ import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; /** - * An implementation of editor for binary files like images or videos leveraging the FileEditorInput. + * An implementation of editor for binary files like images. */ export class BinaryFileEditor extends BaseBinaryResourceEditor { diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 53431f18786..1c6ec6683dc 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -26,7 +26,7 @@ import {dispose, IDisposable} from 'vs/base/common/lifecycle'; import {LocalFileChangeEvent, VIEWLET_ID, ITextFileService} from 'vs/workbench/parts/files/common/files'; import {IFileService, IFileStat, IImportResult} from 'vs/platform/files/common/files'; import {DiffEditorInput, toDiffLabel} from 'vs/workbench/common/editor/diffEditorInput'; -import {asFileEditorInput, getUntitledOrFileResource, UntitledEditorInput, IEditorIdentifier} from 'vs/workbench/common/editor'; +import {asFileEditorInput, getUntitledOrFileResource, IEditorIdentifier} from 'vs/workbench/common/editor'; import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import {FileStat, NewStatPlaceholder} from 'vs/workbench/parts/files/common/explorerViewModel'; import {ExplorerView} from 'vs/workbench/parts/files/browser/views/explorerView'; @@ -1633,8 +1633,9 @@ export class SaveAllInGroupAction extends BaseSaveAllAction { const editorGroup = editorIdentifier.group; const resourcesToSave = []; editorGroup.getEditors().forEach(editor => { - if (editor instanceof FileEditorInput || editor instanceof UntitledEditorInput) { - resourcesToSave.push(editor.getResource()); + const resource = getUntitledOrFileResource(editor, true); + if (resource) { + resourcesToSave.push(resource); } }); diff --git a/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts b/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts index 8b202d448bc..a0b52ef52e3 100644 --- a/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts @@ -22,9 +22,9 @@ import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService'; import {IContextMenuService} from 'vs/platform/contextview/browser/contextView'; import {IKeybindingService} from 'vs/platform/keybinding/common/keybinding'; -import {UntitledEditorInput, IEditorGroup, IEditorStacksModel} from 'vs/workbench/common/editor'; +import {UntitledEditorInput, IEditorGroup, IEditorStacksModel, getUntitledOrFileResource} from 'vs/workbench/common/editor'; import {ContributableActionProvider} from 'vs/workbench/browser/actionBarRegistry'; -import {ITextFileService, AutoSaveMode, FileEditorInput, asFileResource} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService, AutoSaveMode, asFileResource} from 'vs/workbench/parts/files/common/files'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; import {EditorStacksModel, EditorGroup} from 'vs/workbench/common/editor/editorStacksModel'; import {keybindingForAction, SaveFileAction, RevertFileAction, SaveFileAsAction, OpenToSideAction, SelectResourceForCompareAction, CompareResourcesAction, SaveAllInGroupAction} from 'vs/workbench/parts/files/browser/fileActions'; @@ -64,13 +64,7 @@ export class OpenEditor { } public getResource(): uri { - if (this.editor instanceof FileEditorInput) { - return (this.editor).getResource(); - } else if (this.editor instanceof UntitledEditorInput) { - return (this.editor).getResource(); - } - - return null; + return getUntitledOrFileResource(this.editor, true); } } diff --git a/src/vs/workbench/parts/git/browser/views/changes/changesView.ts b/src/vs/workbench/parts/git/browser/views/changes/changesView.ts index c208b75c5da..d27274df108 100644 --- a/src/vs/workbench/parts/git/browser/views/changes/changesView.ts +++ b/src/vs/workbench/parts/git/browser/views/changes/changesView.ts @@ -26,7 +26,6 @@ import GitActions = require('vs/workbench/parts/git/browser/gitActions'); import GitModel = require('vs/workbench/parts/git/common/gitModel'); import Viewer = require('vs/workbench/parts/git/browser/views/changes/changesViewer'); import GitEditorInputs = require('vs/workbench/parts/git/browser/gitEditorInputs'); -import Files = require('vs/workbench/parts/files/common/files'); import {IOutputService} from 'vs/workbench/parts/output/common/output'; import WorkbenchEditorCommon = require('vs/workbench/common/editor'); import InputBox = require('vs/base/browser/ui/inputbox/inputBox'); @@ -450,8 +449,8 @@ export class ChangesView extends EventEmitter.EventEmitter implements GitView.IV return ( input).getFileStatus() || null; } - if (input instanceof Files.FileEditorInput) { - const fileInput = input; + const fileInput = WorkbenchEditorCommon.asFileEditorInput(input); + if (fileInput) { const resource = fileInput.getResource(); const workspaceRoot = this.contextService.getWorkspace().resource.fsPath; diff --git a/src/vs/workbench/test/common/editor/rangeDecorations.test.ts b/src/vs/workbench/test/common/editor/rangeDecorations.test.ts index 6e0b98dddc2..794c0ce1cb7 100644 --- a/src/vs/workbench/test/common/editor/rangeDecorations.test.ts +++ b/src/vs/workbench/test/common/editor/rangeDecorations.test.ts @@ -6,20 +6,20 @@ import * as assert from 'assert'; import { TestInstantiationService } from 'vs/test/utils/instantiationTestUtils'; import URI from 'vs/base/common/uri'; -import {createMockModelService, TestEditorService, workbenchInstantiationService} from 'vs/test/utils/servicesTestUtils'; -import {IModelService} from 'vs/editor/common/services/modelService'; -import {IModeService} from 'vs/editor/common/services/modeService'; +import { createMockModelService, TestEditorService, workbenchInstantiationService } from 'vs/test/utils/servicesTestUtils'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IModeService } from 'vs/editor/common/services/modeService'; import WorkbenchEditorService = require('vs/workbench/services/editor/common/editorService'); import { RangeHighlightDecorations } from 'vs/workbench/common/editor/rangeDecorations'; -import {Model} from 'vs/editor/common/model/model'; -import {mockCodeEditor, MockCodeEditor} from 'vs/editor/test/common/mocks/mockCodeEditor'; +import { Model } from 'vs/editor/common/model/model'; +import { mockCodeEditor, MockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import {IEditorInput} from 'vs/platform/editor/common/editor'; -import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; -import {TextModel} from 'vs/editor/common/model/textModel'; -import {Range} from 'vs/editor/common/core/range'; -import {Position} from 'vs/editor/common/core/position'; -import {Cursor} from 'vs/editor/common/controller/cursor'; +import { IEditorInput } from 'vs/platform/editor/common/editor'; +import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; +import { TextModel } from 'vs/editor/common/model/textModel'; +import { Range } from 'vs/editor/common/core/range'; +import { Position } from 'vs/editor/common/core/position'; +import { Cursor } from 'vs/editor/common/controller/cursor'; suite('Editor - Range decorations', () => { @@ -36,8 +36,8 @@ suite('Editor - Range decorations', () => { setup(() => { instantiationService = workbenchInstantiationService(); - editorService= instantiationService.stub(WorkbenchEditorService.IWorkbenchEditorService, new TestEditorService(function () { })); - modeService= instantiationService.stub(IModeService); + editorService = instantiationService.stub(WorkbenchEditorService.IWorkbenchEditorService, new TestEditorService(function () { })); + modeService = instantiationService.stub(IModeService); modelService = instantiationService.stub(IModelService, createMockModelService(instantiationService)); text = 'LINE1' + '\n' + 'LINE2' + '\n' + 'LINE3' + '\n' + 'LINE4' + '\r\n' + 'LINE5'; model = aModel(URI.file('some_file')); @@ -65,7 +65,7 @@ suite('Editor - Range decorations', () => { }); test('remove highlight range', function () { - testObject.highlightRange({ resource: model.uri, range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }}); + testObject.highlightRange({ resource: model.uri, range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 } }); testObject.removeHighlightRange(); let actuals = rangeHighlightDecorations(model); @@ -74,7 +74,7 @@ suite('Editor - Range decorations', () => { }); test('highlight range for the resource removes previous highlight', function () { - testObject.highlightRange({ resource: model.uri, range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }}); + testObject.highlightRange({ resource: model.uri, range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 } }); let range: editorCommon.IRange = { startLineNumber: 2, startColumn: 2, endLineNumber: 4, endColumn: 3 }; testObject.highlightRange({ resource: model.uri, range }); @@ -124,7 +124,7 @@ suite('Editor - Range decorations', () => { test('previous highlight is not removed if not active editor', function () { let range: editorCommon.IRange = { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 }; - testObject.highlightRange({ resource: model.uri, range}); + testObject.highlightRange({ resource: model.uri, range }); let model1 = aModel(URI.file('some model')); testObject.highlightRange({ resource: model1.uri, range: { startLineNumber: 2, startColumn: 1, endLineNumber: 2, endColumn: 1 } }); @@ -150,7 +150,7 @@ suite('Editor - Range decorations', () => { function mockEditorService(resource: URI) function mockEditorService(arg: any) { let editorInput: IEditorInput = arg instanceof URI ? instantiationService.createInstance(FileEditorInput, arg, void 0) : arg; - instantiationService.stub(WorkbenchEditorService.IWorkbenchEditorService, 'getActiveEditorInput', editorInput); + instantiationService.stub(WorkbenchEditorService.IWorkbenchEditorService, 'getActiveEditorInput', editorInput); } function rangeHighlightDecorations(m: Model): editorCommon.IRange[] { From 95fec447ef5534e2531a5c0c4f95d4653cbc699c Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 5 Oct 2016 12:13:18 +0200 Subject: [PATCH 060/163] :lipstick: --- src/vs/editor/contrib/suggest/browser/suggestWidget.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index 588f7aaf3a8..236885ea69e 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -292,7 +292,8 @@ export class SuggestWidget implements IContentWidget, IDelegate static LOADING_MESSAGE: string = nls.localize('suggestWidget.loading', "Loading..."); static NO_SUGGESTIONS_MESSAGE: string = nls.localize('suggestWidget.noSuggestions', "No suggestions."); - allowEditorOverflow: boolean = true; // Editor.IContentWidget.allowEditorOverflow + // Editor.IContentWidget.allowEditorOverflow + allowEditorOverflow = true; private state: State; private isAuto: boolean; From 6b515aea3244d547c15f5b2e2ea3fe31d3897a4e Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 5 Oct 2016 12:34:36 +0200 Subject: [PATCH 061/163] stable tabstop at snippet line start, fixes #11890 --- .../editor/contrib/snippet/common/snippet.ts | 52 ++++++++++------- .../snippet/test/common/snippet.test.ts | 58 +++++++++++++++++++ .../test/common/snippetController.test.ts | 24 ++++++++ 3 files changed, 113 insertions(+), 21 deletions(-) diff --git a/src/vs/editor/contrib/snippet/common/snippet.ts b/src/vs/editor/contrib/snippet/common/snippet.ts index 6bfbd8ba6e7..4245228ea5d 100644 --- a/src/vs/editor/contrib/snippet/common/snippet.ts +++ b/src/vs/editor/contrib/snippet/common/snippet.ts @@ -60,43 +60,53 @@ export class CodeSnippet implements ICodeSnippet { } public bind(referenceLine: string, deltaLine: number, firstLineDeltaColumn: number, config: IIndentationNormalizer): ICodeSnippet { - var resultLines: string[] = []; - var resultPlaceHolders: IPlaceHolder[] = []; + const resultLines: string[] = []; + const resultPlaceHolders: IPlaceHolder[] = []; - var referenceIndentation = this.extractLineIndentation(referenceLine, firstLineDeltaColumn + 1); - var originalLine: string, originalLineIndentation: string, remainingLine: string, indentation: string; - var i: number, len: number, j: number, lenJ: number; + const referenceIndentation = this.extractLineIndentation(referenceLine, firstLineDeltaColumn + 1); // Compute resultLines & keep deltaColumns as a reference for adjusting placeholders - var deltaColumns: number[] = []; - for (i = 0, len = this.lines.length; i < len; i++) { - originalLine = this.lines[i]; + const deltaColumns: number[] = []; + + for (let i = 0, len = this.lines.length; i < len; i++) { + let originalLine = this.lines[i]; if (i === 0) { deltaColumns[i + 1] = firstLineDeltaColumn; resultLines[i] = originalLine; } else { - originalLineIndentation = this.extractLineIndentation(originalLine); - remainingLine = originalLine.substr(originalLineIndentation.length); - indentation = config.normalizeIndentation(referenceIndentation + originalLineIndentation); + let originalLineIndentation = this.extractLineIndentation(originalLine); + let remainingLine = originalLine.substr(originalLineIndentation.length); + let indentation = config.normalizeIndentation(referenceIndentation + originalLineIndentation); deltaColumns[i + 1] = indentation.length - originalLineIndentation.length; resultLines[i] = indentation + remainingLine; } } // Compute resultPlaceHolders - var originalPlaceHolder: IPlaceHolder, originalOccurence: editorCommon.IRange, resultOccurences: editorCommon.IRange[]; - for (i = 0, len = this.placeHolders.length; i < len; i++) { - originalPlaceHolder = this.placeHolders[i]; + for (const originalPlaceHolder of this.placeHolders) { + let resultOccurences = []; - resultOccurences = []; - for (j = 0, lenJ = originalPlaceHolder.occurences.length; j < lenJ; j++) { - originalOccurence = originalPlaceHolder.occurences[j]; + for (let {startLineNumber, startColumn, endLineNumber, endColumn} of originalPlaceHolder.occurences) { + + if (startColumn > 1) { + // placeholders that aren't at the beginning of the snippet line + // will be moved by how many characters the indentation has been + // adjusted + startColumn = startColumn + deltaColumns[startLineNumber]; + endColumn = endColumn + deltaColumns[endLineNumber]; + + } else { + // placeholders at the beginning of the snippet line + // will be indented by the reference indentation + startColumn += referenceIndentation.length; + endColumn += referenceIndentation.length; + } resultOccurences.push({ - startLineNumber: originalOccurence.startLineNumber + deltaLine, - startColumn: originalOccurence.startColumn + deltaColumns[originalOccurence.startLineNumber], - endLineNumber: originalOccurence.endLineNumber + deltaLine, - endColumn: originalOccurence.endColumn + deltaColumns[originalOccurence.endLineNumber] + startLineNumber: startLineNumber + deltaLine, + startColumn, + endLineNumber: endLineNumber + deltaLine, + endColumn }); } diff --git a/src/vs/editor/contrib/snippet/test/common/snippet.test.ts b/src/vs/editor/contrib/snippet/test/common/snippet.test.ts index b18834b9b0b..cdb521c40e6 100644 --- a/src/vs/editor/contrib/snippet/test/common/snippet.test.ts +++ b/src/vs/editor/contrib/snippet/test/common/snippet.test.ts @@ -179,5 +179,63 @@ suite('Editor Contrib - Snippets', () => { assert.equal(snippet.placeHolders.length, 0); assert.deepEqual(snippet.lines, ['', '$scope.$broadcast(\'scroll.infiniteScrollComplete\');', '']); }); + + test('bind, adjust indentation', () => { + + // don't move placeholder at the beginning of the line + let snippet = CodeSnippet.fromTextmate([ + 'afterEach((done) => {', + '\t${1}test${2}', + '})' + ].join('\n')); + + // replace tab-stop with two spaces + let boundSnippet = snippet.bind('', 0, 0, { + normalizeIndentation(str: string): string { + return str.replace(/\t/g, ' '); + } + }); + let [first, second] = boundSnippet.placeHolders; + assert.equal(first.occurences.length, 1); + assert.equal(first.occurences[0].startColumn, 3); + assert.equal(second.occurences.length, 1); + assert.equal(second.occurences[0].startColumn, 7); + + // keep tab-stop, identity + boundSnippet = snippet.bind('', 0, 0, { + normalizeIndentation(str: string): string { + return str; + } + }); + [first, second] = boundSnippet.placeHolders; + assert.equal(first.occurences.length, 1); + assert.equal(first.occurences[0].startColumn, 2); + assert.equal(second.occurences.length, 1); + assert.equal(second.occurences[0].startColumn, 6); + }); + + + test('issue #11890: Bad cursor position', () => { + + let snippet = CodeSnippet.fromTextmate([ + 'afterEach((done) => {', + '${1}\ttest${2}', + '})' + ].join('\n')); + + let boundSnippet = snippet.bind('', 0, 0, { + normalizeIndentation(str: string): string { + return str.replace(/\t/g, ' '); + } + }); + + assert.equal(boundSnippet.lines[1], ' test'); + assert.equal(boundSnippet.placeHolders.length, 2); + let [first, second] = boundSnippet.placeHolders; + assert.equal(first.occurences.length, 1); + assert.equal(first.occurences[0].startColumn, 1); + assert.equal(second.occurences.length, 1); + assert.equal(second.occurences[0].startColumn, 7); + }); }); diff --git a/src/vs/editor/contrib/snippet/test/common/snippetController.test.ts b/src/vs/editor/contrib/snippet/test/common/snippetController.test.ts index 5f9eb9a3647..e405b6ae79f 100644 --- a/src/vs/editor/contrib/snippet/test/common/snippetController.test.ts +++ b/src/vs/editor/contrib/snippet/test/common/snippetController.test.ts @@ -408,6 +408,30 @@ suite('SnippetController', () => { }, ['af', '\taf']); }); + test('Final tabstop, #11890 stay at the beginning', () => { + + snippetTest((editor, cursor, codeSnippet, controller) => { + + editor.setSelections([ + new Selection(1, 5, 1, 5) + ]); + + codeSnippet = CodeSnippet.fromTextmate([ + 'afterEach((done) => {', + '${1}\ttest', + '});' + ].join('\n')); + + controller.run(codeSnippet, 2, 0, true); + + assert.equal(editor.getSelections().length, 1); + const [first] = editor.getSelections(); + + assert.ok(first.equalsRange({ startLineNumber: 2, startColumn: 3, endLineNumber: 2, endColumn: 3 }), first.toString()); + + }, [' af']); + }); + test('Final tabstop, no tabstop', () => { snippetTest((editor, cursor, codeSnippet, controller) => { From cd6fb060c187c0a199954d1fe19704a164827761 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 12:35:11 +0200 Subject: [PATCH 062/163] hunt down flaky tests --- src/vs/editor/common/model/model.ts | 2 +- .../workbench/parts/files/test/browser/fileEditorInput.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/editor/common/model/model.ts b/src/vs/editor/common/model/model.ts index 7f8d2e82993..a38b3886b82 100644 --- a/src/vs/editor/common/model/model.ts +++ b/src/vs/editor/common/model/model.ts @@ -89,7 +89,7 @@ export class Model extends EditableTextModel implements IModel { if (aliveModels[String(this._associatedResource)]) { - throw new Error('Cannot instantiate a second Model with the same URI!'); + throw new Error('Cannot instantiate a second Model with the same URI: ' + String(this._associatedResource)); } this._attachedEditorCount = 0; diff --git a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts index 386678a4e7b..778c9702b2c 100644 --- a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts +++ b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts @@ -69,7 +69,7 @@ suite('Files - FileEditorInput', () => { assert.strictEqual(toResource('/foo/bar/file.js').fsPath, input.getResource().fsPath); assert(input.getResource() instanceof URI); - input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar.html'), 'text/html', void 0); + input = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar.html'), void 0); const inputToResolve: any = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/file.js'), void 0); const sameOtherInput = instantiationService.createInstance(FileEditorInput, toResource('/foo/bar/file.js'), void 0); From 39a3862d6577585cb7d469352148512bb2ab8174 Mon Sep 17 00:00:00 2001 From: Krzysztof Cieslak Date: Wed, 5 Oct 2016 14:12:47 +0200 Subject: [PATCH 063/163] Escape command title for CodeLens --- src/vs/editor/contrib/codelens/browser/codelens.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/contrib/codelens/browser/codelens.ts b/src/vs/editor/contrib/codelens/browser/codelens.ts index c43f561d31d..6b3cc7f0bb0 100644 --- a/src/vs/editor/contrib/codelens/browser/codelens.ts +++ b/src/vs/editor/contrib/codelens/browser/codelens.ts @@ -10,7 +10,7 @@ import {RunOnceScheduler, asWinJsPromise} from 'vs/base/common/async'; import {onUnexpectedError} from 'vs/base/common/errors'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import Severity from 'vs/base/common/severity'; -import {format} from 'vs/base/common/strings'; +import {format, escape} from 'vs/base/common/strings'; import {TPromise} from 'vs/base/common/winjs.base'; import * as dom from 'vs/base/browser/dom'; import {ICommandService} from 'vs/platform/commands/common/commands'; @@ -114,12 +114,13 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { let html: string[] = []; for (let i = 0; i < symbols.length; i++) { let command = symbols[i].command; + let title = escape(command.title); let part: string; if (command.id) { - part = format('{1}', i, command.title); + part = format('{1}', i, title); this._commands[i] = command; } else { - part = format('{0}', command.title); + part = format('{0}', title); } html.push(part); } From 2507cc202e9d0f6147f27d0e20259effbf37b654 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 14:36:11 +0200 Subject: [PATCH 064/163] =?UTF-8?q?=F0=9F=92=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/vs/base/parts/ipc/test/node/ipc.perf.ts | 8 -------- src/vs/platform/opener/browser/openerService.ts | 2 +- src/vs/workbench/browser/parts/editor/editorActions.ts | 2 +- src/vs/workbench/browser/parts/editor/editorCommands.ts | 1 - src/vs/workbench/electron-browser/actions.ts | 2 +- .../test/browser/parts/quickOpen/quickopen.perf.test.ts | 4 ++++ 6 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/vs/base/parts/ipc/test/node/ipc.perf.ts b/src/vs/base/parts/ipc/test/node/ipc.perf.ts index 2694f1ab0fa..24f88b2bd71 100644 --- a/src/vs/base/parts/ipc/test/node/ipc.perf.ts +++ b/src/vs/base/parts/ipc/test/node/ipc.perf.ts @@ -22,10 +22,6 @@ function createClient(): Client { suite('IPC performance', () => { test('increasing batch size', () => { - if (process.env['VSCODE_PID']) { - return; // TODO@Ben find out why test fails when run from within VS Code - } - const client = createClient(); const channel = client.getChannel('test'); const service = new TestServiceClient(channel); @@ -67,10 +63,6 @@ suite('IPC performance', () => { }); test('increasing raw data size', () => { - if (process.env['VSCODE_PID']) { - return; // TODO@Ben find out why test fails when run from within VS Code - } - const client = createClient(); const channel = client.getChannel('test'); const service = new TestServiceClient(channel); diff --git a/src/vs/platform/opener/browser/openerService.ts b/src/vs/platform/opener/browser/openerService.ts index 6d5dc1011fe..7c33ad82d9a 100644 --- a/src/vs/platform/opener/browser/openerService.ts +++ b/src/vs/platform/opener/browser/openerService.ts @@ -61,7 +61,7 @@ export class OpenerService implements IOpenerService { // remove fragment resource = resource.with({ fragment: '' }); } else if (resource.scheme === Schemas.file) { - resource = URI.file(normalize(resource.fsPath)); // TODO@Ben workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) + resource = URI.file(normalize(resource.fsPath)); // workaround for non-normalized paths (https://github.com/Microsoft/vscode/issues/12954) } promise = this._editorService.openEditor({ resource, options: { selection, } }, options && options.openToSide); } diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 5c769f4fc51..3f7fe6457ed 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -401,7 +401,7 @@ export class OpenToSideAction extends Action { public static OPEN_TO_SIDE_ID = 'workbench.action.openToSide'; public static OPEN_TO_SIDE_LABEL = nls.localize('openToSide', "Open to the Side"); - constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService) { + constructor(@IWorkbenchEditorService private editorService: IWorkbenchEditorService) { super(OpenToSideAction.OPEN_TO_SIDE_ID, OpenToSideAction.OPEN_TO_SIDE_LABEL); this.class = 'quick-open-sidebyside'; diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index c542173207f..8f4c719e873 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -191,7 +191,6 @@ function registerDiffEditorCommands(): void { }); } -// TODO@Ben remove eventually function handleCommandDeprecations(): void { const mapDeprecatedCommands = { 'workbench.action.focusFirstEditor': 'workbench.action.focusFirstEditorGroup', diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index 76e25d00308..8054efc6f45 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -569,7 +569,7 @@ CommandsRegistry.registerCommand('_workbench.diff', function (accessor: Services return TPromise.join([editorService.createInput({ resource: left }), editorService.createInput({ resource: right })]).then(inputs => { const [left, right] = inputs; - const diff = new DiffEditorInput(label, undefined, left, right); + const diff = new DiffEditorInput(label, void 0, left, right); return editorService.openEditor(diff); }).then(() => { return void 0; diff --git a/src/vs/workbench/test/browser/parts/quickOpen/quickopen.perf.test.ts b/src/vs/workbench/test/browser/parts/quickOpen/quickopen.perf.test.ts index ae8d044e5e3..680f09ad821 100644 --- a/src/vs/workbench/test/browser/parts/quickOpen/quickopen.perf.test.ts +++ b/src/vs/workbench/test/browser/parts/quickOpen/quickopen.perf.test.ts @@ -40,6 +40,10 @@ declare var __dirname: string; suite('QuickOpen performance', () => { test('Measure', () => { + if (process.env['VSCODE_PID']) { + return; // TODO@Christoph find out why test fails when run from within VS Code + } + const n = 3; const argv = minimist(process.argv); const testWorkspaceArg = argv['testWorkspace']; From 96f11177ebf7bb4a3ab4d93312f18d85a154ddd7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 15:19:18 +0200 Subject: [PATCH 065/163] push ITextFileService to be a workbench service (fixes #6429) --- src/vs/test/utils/servicesTestUtils.ts | 5 +- src/vs/workbench/api/node/extHost.protocol.ts | 2 +- .../node/extHostDocumentSaveParticipant.ts | 2 +- .../api/node/extHostTypeConverters.ts | 2 +- .../workbench/api/node/mainThreadDocuments.ts | 2 +- .../api/node/mainThreadSaveParticipant.ts | 5 +- .../workbench/api/node/mainThreadWorkspace.ts | 2 +- .../browser/parts/editor/editorStatus.ts | 3 +- .../common/editor/untitledEditorInput.ts | 3 +- .../workbench/electron-browser/workbench.ts | 5 + .../debug/electron-browser/debugService.ts | 2 +- .../files/browser/editors/textFileEditor.ts | 3 +- .../parts/files/browser/fileActions.ts | 3 +- .../parts/files/browser/saveErrorHandler.ts | 4 +- .../parts/files/browser/views/explorerView.ts | 3 +- .../files/browser/views/explorerViewer.ts | 3 +- .../files/browser/views/openEditorsView.ts | 3 +- .../files/browser/views/openEditorsViewer.ts | 3 +- .../files/common/editors/fileEditorInput.ts | 3 +- .../files/common/editors/fileEditorTracker.ts | 3 +- src/vs/workbench/parts/files/common/files.ts | 325 +---------------- .../electron-browser/dirtyFilesTracker.ts | 3 +- .../files.electron.contribution.ts | 9 +- .../test/browser/explorerViewModel.test.ts | 2 +- .../test/browser/fileEditorInput.test.ts | 3 +- .../files/test/browser/fileEvents.test.ts | 2 +- .../parts/git/browser/gitServices.ts | 2 +- .../electron-browser/electronGitService.ts | 2 +- .../electron-browser/task.contribution.ts | 2 +- .../textfile/browser}/textFileService.ts | 4 +- .../textfile/common}/textFileEditorModel.ts | 2 +- .../textFileEditorModelManager.test.ts | 6 +- .../common}/textFileEditorModelManager.ts | 4 +- .../services/textfile/common/textfiles.ts | 330 ++++++++++++++++++ .../electron-browser/textFileService.ts | 4 +- .../test/textFileEditorModel.test.ts} | 6 +- .../textfile/test}/textFileService.test.ts | 6 +- .../workbench/test/browser/services.test.ts | 2 +- .../extHostDocumentSaveParticipant.test.ts | 2 +- 39 files changed, 396 insertions(+), 381 deletions(-) rename src/vs/workbench/{parts/files/common => services/textfile/browser}/textFileService.ts (99%) rename src/vs/workbench/{parts/files/common/editors => services/textfile/common}/textFileEditorModel.ts (99%) rename src/vs/workbench/{parts/files/test/browser => services/textfile/common}/textFileEditorModelManager.test.ts (97%) rename src/vs/workbench/{parts/files/common/editors => services/textfile/common}/textFileEditorModelManager.ts (98%) create mode 100644 src/vs/workbench/services/textfile/common/textfiles.ts rename src/vs/workbench/{parts/files => services/textfile}/electron-browser/textFileService.ts (98%) rename src/vs/workbench/{parts/files/test/browser/fileEditorModel.test.ts => services/textfile/test/textFileEditorModel.test.ts} (97%) rename src/vs/workbench/{parts/files/test/browser => services/textfile/test}/textFileService.test.ts (95%) diff --git a/src/vs/test/utils/servicesTestUtils.ts b/src/vs/test/utils/servicesTestUtils.ts index 6af456e2756..60173af928e 100644 --- a/src/vs/test/utils/servicesTestUtils.ts +++ b/src/vs/test/utils/servicesTestUtils.ts @@ -30,17 +30,16 @@ import {EditorStacksModel} from 'vs/workbench/common/editor/editorStacksModel'; import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection'; import {InstantiationService} from 'vs/platform/instantiation/common/instantiationService'; import {IEditorGroupService, GroupArrangement} from 'vs/workbench/services/group/common/groupService'; -import {TextFileService} from 'vs/workbench/parts/files/common/textFileService'; +import {TextFileService} from 'vs/workbench/services/textfile/browser/textFileService'; import {IFileService, IResolveContentOptions, IFileOperationResult} from 'vs/platform/files/common/files'; import {IModelService} from 'vs/editor/common/services/modelService'; import {ModelServiceImpl} from 'vs/editor/common/services/modelServiceImpl'; -import {IRawTextContent} from 'vs/workbench/parts/files/common/files'; +import {IRawTextContent, ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; import {RawText} from 'vs/editor/common/model/textModel'; import {parseArgs} from 'vs/platform/environment/node/argv'; import {EnvironmentService} from 'vs/platform/environment/node/environmentService'; import {IModeService} from 'vs/editor/common/services/modeService'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; -import {ITextFileService} from 'vs/workbench/parts/files/common/files'; import {IHistoryService} from 'vs/workbench/services/history/common/history'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index e9dca2ef83d..45547c8fba1 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -30,7 +30,7 @@ import { IResourceEdit } from 'vs/editor/common/services/bulkEdit'; import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { IPickOpenEntry, IPickOptions } from 'vs/workbench/services/quickopen/common/quickOpenService'; -import { SaveReason } from 'vs/workbench/parts/files/common/files'; +import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkspaceSymbol } from 'vs/workbench/parts/search/common/search'; import { IApplyEditsOptions, TextEditorRevealType, ITextEditorConfigurationUpdate, IResolvedTextEditorConfiguration, ISelectionChangeEvent } from './mainThreadEditorsTracker'; diff --git a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts index 879ff76d236..7a11ebe66df 100644 --- a/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts +++ b/src/vs/workbench/api/node/extHostDocumentSaveParticipant.ts @@ -15,7 +15,7 @@ import { TextEdit } from 'vs/workbench/api/node/extHostTypes'; import { fromRange, TextDocumentSaveReason } from 'vs/workbench/api/node/extHostTypeConverters'; import { IResourceEdit } from 'vs/editor/common/services/bulkEdit'; import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments'; -import { SaveReason } from 'vs/workbench/parts/files/common/files'; +import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; declare class WeakMap { // delete(key: K): boolean; diff --git a/src/vs/workbench/api/node/extHostTypeConverters.ts b/src/vs/workbench/api/node/extHostTypeConverters.ts index 62006ea9bbd..1dd52ddbb79 100644 --- a/src/vs/workbench/api/node/extHostTypeConverters.ts +++ b/src/vs/workbench/api/node/extHostTypeConverters.ts @@ -16,7 +16,7 @@ import { IPosition, ISelection, IRange, IDecorationOptions, ISingleEditOperation import { IWorkspaceSymbol } from 'vs/workbench/parts/search/common/search'; import * as vscode from 'vscode'; import URI from 'vs/base/common/uri'; -import { SaveReason } from 'vs/workbench/parts/files/common/files'; +import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; export interface PositionLike { line: number; diff --git a/src/vs/workbench/api/node/mainThreadDocuments.ts b/src/vs/workbench/api/node/mainThreadDocuments.ts index 517cb71db93..c106c5e4073 100644 --- a/src/vs/workbench/api/node/mainThreadDocuments.ts +++ b/src/vs/workbench/api/node/mainThreadDocuments.ts @@ -14,7 +14,7 @@ import URI from 'vs/base/common/uri'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import {IEventService} from 'vs/platform/event/common/event'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; -import {TextFileModelChangeEvent, ITextFileService} from 'vs/workbench/parts/files/common/files'; +import {TextFileModelChangeEvent, ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; import {TPromise} from 'vs/base/common/winjs.base'; import {IFileService} from 'vs/platform/files/common/files'; import {IModeService} from 'vs/editor/common/services/modeService'; diff --git a/src/vs/workbench/api/node/mainThreadSaveParticipant.ts b/src/vs/workbench/api/node/mainThreadSaveParticipant.ts index ca01d746290..f9d0766641b 100644 --- a/src/vs/workbench/api/node/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/node/mainThreadSaveParticipant.ts @@ -9,7 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { sequence } from 'vs/base/common/async'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; -import { ISaveParticipant, ITextFileEditorModel } from 'vs/workbench/parts/files/common/files'; +import { ISaveParticipant, ITextFileEditorModel, SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IPosition, IModel, ICommonCodeEditor, ISingleEditOperation, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon'; import { Range } from 'vs/editor/common/core/range'; @@ -18,9 +18,8 @@ import { trimTrailingWhitespace } from 'vs/editor/common/commands/trimTrailingWh import { getDocumentRangeFormattingEdits } from 'vs/editor/contrib/format/common/format'; import { EditOperationsCommand } from 'vs/editor/contrib/format/common/formatCommand'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { TextFileEditorModel } from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; +import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { ExtHostContext, ExtHostDocumentSaveParticipantShape } from './extHost.protocol'; -import { SaveReason } from 'vs/workbench/parts/files/common/files'; class TrimWhitespaceParticipant implements ISaveParticipant { diff --git a/src/vs/workbench/api/node/mainThreadWorkspace.ts b/src/vs/workbench/api/node/mainThreadWorkspace.ts index e5f7a1b6234..ab1ee8a7ec2 100644 --- a/src/vs/workbench/api/node/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/node/mainThreadWorkspace.ts @@ -9,7 +9,7 @@ import {ISearchService, QueryType} from 'vs/platform/search/common/search'; import {IWorkspaceContextService, IWorkspace} from 'vs/platform/workspace/common/workspace'; import {IEventService} from 'vs/platform/event/common/event'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; -import {ITextFileService} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; import {ICommonCodeEditor} from 'vs/editor/common/editorCommon'; import {bulkEdit, IResourceEdit} from 'vs/editor/common/services/bulkEdit'; import {TPromise} from 'vs/base/common/winjs.base'; diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 381aa926f23..0e780cff534 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -44,8 +44,7 @@ import {StyleMutator} from 'vs/base/browser/styleMutator'; import {Selection} from 'vs/editor/common/core/selection'; import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService'; import {TabFocus} from 'vs/editor/common/config/commonEditorConfig'; - -import {ITextFileService} from 'vs/workbench/parts/files/common/files'; // TODO@Ben layer breaker +import {ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; function getCodeEditor(editorWidget: IEditor): ICommonCodeEditor { if (editorWidget) { diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index 0159864a62c..e4c7a6cf5b1 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -17,8 +17,7 @@ import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IModeService} from 'vs/editor/common/services/modeService'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import Event, {Emitter} from 'vs/base/common/event'; - -import {ITextFileService} from 'vs/workbench/parts/files/common/files'; // TODO@Ben layer breaker +import {ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; /** * An editor input to be used for untitled text buffers. diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 0f40393c703..10b851046f0 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -63,6 +63,8 @@ import {IEditorGroupService} from 'vs/workbench/services/group/common/groupServi import {IHistoryService} from 'vs/workbench/services/history/common/history'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {SyncDescriptor} from 'vs/platform/instantiation/common/descriptors'; +import {TextFileService} from 'vs/workbench/services/textfile/electron-browser/textFileService'; +import {ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; import {IMessageService} from 'vs/platform/message/common/message'; @@ -401,6 +403,9 @@ export class Workbench implements IPartService { this.toShutdown.push(this.quickOpen); serviceCollection.set(IQuickOpenService, this.quickOpen); + // Text File Service + serviceCollection.set(ITextFileService, this.instantiationService.createInstance(TextFileService)); + // Contributed services const contributedServices = getServices(); for (let contributedService of contributedServices) { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index ae9288f4147..3a1d38fa8a5 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -46,7 +46,7 @@ import {TaskError, TaskErrors} from 'vs/workbench/parts/tasks/common/taskSystem' import {IViewletService} from 'vs/workbench/services/viewlet/common/viewletService'; import {IPanelService} from 'vs/workbench/services/panel/common/panelService'; import {IPartService} from 'vs/workbench/services/part/common/partService'; -import {ITextFileService} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; diff --git a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts index ffbef7832e4..d4faecd8ab5 100644 --- a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts @@ -14,7 +14,8 @@ import {IEditorViewState} from 'vs/editor/common/editorCommon'; import {Action} from 'vs/base/common/actions'; import {Scope} from 'vs/workbench/common/memento'; import {IEditorOptions} from 'vs/editor/common/editorCommon'; -import {VIEWLET_ID, TEXT_FILE_EDITOR_ID, ITextFileEditorModel} from 'vs/workbench/parts/files/common/files'; +import {VIEWLET_ID, TEXT_FILE_EDITOR_ID} from 'vs/workbench/parts/files/common/files'; +import {ITextFileEditorModel} from 'vs/workbench/services/textfile/common/textfiles'; import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor'; import {EditorOptions, TextEditorOptions} from 'vs/workbench/common/editor'; import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 1c6ec6683dc..2a652404c1d 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -23,7 +23,8 @@ import {Action, IAction} from 'vs/base/common/actions'; import {MessageType, IInputValidator} from 'vs/base/browser/ui/inputbox/inputBox'; import {ITree, IHighlightEvent} from 'vs/base/parts/tree/browser/tree'; import {dispose, IDisposable} from 'vs/base/common/lifecycle'; -import {LocalFileChangeEvent, VIEWLET_ID, ITextFileService} from 'vs/workbench/parts/files/common/files'; +import {VIEWLET_ID} from 'vs/workbench/parts/files/common/files'; +import {LocalFileChangeEvent, ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; import {IFileService, IFileStat, IImportResult} from 'vs/platform/files/common/files'; import {DiffEditorInput, toDiffLabel} from 'vs/workbench/common/editor/diffEditorInput'; import {asFileEditorInput, getUntitledOrFileResource, IEditorIdentifier} from 'vs/workbench/common/editor'; diff --git a/src/vs/workbench/parts/files/browser/saveErrorHandler.ts b/src/vs/workbench/parts/files/browser/saveErrorHandler.ts index e4ebe91c532..ac7e2366aae 100644 --- a/src/vs/workbench/parts/files/browser/saveErrorHandler.ts +++ b/src/vs/workbench/parts/files/browser/saveErrorHandler.ts @@ -21,14 +21,14 @@ import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEdito import {SaveFileAsAction, RevertFileAction, SaveFileAction} from 'vs/workbench/parts/files/browser/fileActions'; import {IFileOperationResult, FileOperationResult} from 'vs/platform/files/common/files'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; -import {ITextFileService, ISaveErrorHandler, ITextFileEditorModel} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService, ISaveErrorHandler, ITextFileEditorModel} from 'vs/workbench/services/textfile/common/textfiles'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {IMessageService, IMessageWithAction, Severity, CancelAction} from 'vs/platform/message/common/message'; import {IModeService} from 'vs/editor/common/services/modeService'; import {IModelService} from 'vs/editor/common/services/modelService'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import {IWorkbenchContribution} from 'vs/workbench/common/contributions'; -import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; +import {TextFileEditorModel} from 'vs/workbench/services/textfile/common/textFileEditorModel'; // A handler for save error happening with conflict resolution actions export class SaveErrorHandler implements ISaveErrorHandler, IWorkbenchContribution { diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index 9e101f8d307..29c2f1e2d64 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -16,7 +16,8 @@ import {Action, IActionRunner, IAction} from 'vs/base/common/actions'; import {prepareActions} from 'vs/workbench/browser/actionBarRegistry'; import {ITree} from 'vs/base/parts/tree/browser/tree'; import {Tree} from 'vs/base/parts/tree/browser/treeImpl'; -import {LocalFileChangeEvent, IFilesConfiguration} from 'vs/workbench/parts/files/common/files'; +import {IFilesConfiguration} from 'vs/workbench/parts/files/common/files'; +import {LocalFileChangeEvent} from 'vs/workbench/services/textfile/common/textfiles'; import {IFileStat, IResolveFileOptions, FileChangeType, FileChangesEvent, IFileChange, EventType as FileEventType, IFileService} from 'vs/platform/files/common/files'; import {FileImportedEvent, RefreshViewExplorerAction, NewFolderAction, NewFileAction} from 'vs/workbench/parts/files/browser/fileActions'; import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index a36e842e6e4..87104902766 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -24,7 +24,8 @@ import glob = require('vs/base/common/glob'); import {FileLabel, IFileLabelOptions} from 'vs/workbench/browser/labels'; import {IDisposable} from 'vs/base/common/lifecycle'; import {ContributableActionProvider} from 'vs/workbench/browser/actionBarRegistry'; -import {LocalFileChangeEvent, IFilesConfiguration, ITextFileService} from 'vs/workbench/parts/files/common/files'; +import {IFilesConfiguration} from 'vs/workbench/parts/files/common/files'; +import {LocalFileChangeEvent, ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; import {IFileOperationResult, FileOperationResult, IFileStat, IFileService} from 'vs/platform/files/common/files'; import {DuplicateFileAction, ImportFileAction, PasteFileAction, keybindingForAction, IEditableData, IFileViewletState} from 'vs/workbench/parts/files/browser/fileActions'; import {IDataSource, ITree, IElementCallback, IAccessibilityProvider, IRenderer, ContextMenuEvent, ISorter, IFilter, IDragAndDrop, IDragAndDropData, IDragOverReaction, DRAG_OVER_ACCEPT_BUBBLE_DOWN, DRAG_OVER_ACCEPT_BUBBLE_DOWN_COPY, DRAG_OVER_ACCEPT_BUBBLE_UP, DRAG_OVER_ACCEPT_BUBBLE_UP_COPY, DRAG_OVER_REJECT} from 'vs/base/parts/tree/browser/tree'; diff --git a/src/vs/workbench/parts/files/browser/views/openEditorsView.ts b/src/vs/workbench/parts/files/browser/views/openEditorsView.ts index d02ad349e93..5c581bc83d5 100644 --- a/src/vs/workbench/parts/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/parts/files/browser/views/openEditorsView.ts @@ -19,7 +19,8 @@ import {IKeybindingService} from 'vs/platform/keybinding/common/keybinding'; import {IEditorStacksModel, IStacksModelChangeEvent, IEditorGroup} from 'vs/workbench/common/editor'; import {SaveAllAction} from 'vs/workbench/parts/files/browser/fileActions'; import {AdaptiveCollapsibleViewletView} from 'vs/workbench/browser/viewlet'; -import {ITextFileService, IFilesConfiguration, VIEWLET_ID, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; +import {IFilesConfiguration, VIEWLET_ID} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService, AutoSaveMode} from 'vs/workbench/services/textfile/common/textfiles'; import {IViewletService} from 'vs/workbench/services/viewlet/common/viewletService'; import {Renderer, DataSource, Controller, AccessibilityProvider, ActionProvider, OpenEditor, DragAndDrop} from 'vs/workbench/parts/files/browser/views/openEditorsViewer'; import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService'; diff --git a/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts b/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts index a0b52ef52e3..6bdcc3e553e 100644 --- a/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/openEditorsViewer.ts @@ -24,7 +24,8 @@ import {IContextMenuService} from 'vs/platform/contextview/browser/contextView'; import {IKeybindingService} from 'vs/platform/keybinding/common/keybinding'; import {UntitledEditorInput, IEditorGroup, IEditorStacksModel, getUntitledOrFileResource} from 'vs/workbench/common/editor'; import {ContributableActionProvider} from 'vs/workbench/browser/actionBarRegistry'; -import {ITextFileService, AutoSaveMode, asFileResource} from 'vs/workbench/parts/files/common/files'; +import {asFileResource} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService, AutoSaveMode} from 'vs/workbench/services/textfile/common/textfiles'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; import {EditorStacksModel, EditorGroup} from 'vs/workbench/common/editor/editorStacksModel'; import {keybindingForAction, SaveFileAction, RevertFileAction, SaveFileAsAction, OpenToSideAction, SelectResourceForCompareAction, CompareResourcesAction, SaveAllInGroupAction} from 'vs/workbench/parts/files/browser/fileActions'; diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts index fd348e70f79..15a70a23091 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts @@ -11,7 +11,8 @@ import URI from 'vs/base/common/uri'; import {EditorModel, EncodingMode, ConfirmResult} from 'vs/workbench/common/editor'; import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; import {IFileOperationResult, FileOperationResult, FileChangesEvent, EventType} from 'vs/platform/files/common/files'; -import {ITextFileService, BINARY_FILE_EDITOR_ID, TEXT_FILE_EDITOR_ID, FILE_EDITOR_INPUT_ID, FileEditorInput as CommonFileEditorInput, AutoSaveMode, ModelState, TextFileModelChangeEvent, LocalFileChangeEvent} from 'vs/workbench/parts/files/common/files'; +import {BINARY_FILE_EDITOR_ID, TEXT_FILE_EDITOR_ID, FILE_EDITOR_INPUT_ID, FileEditorInput as CommonFileEditorInput} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService, AutoSaveMode, ModelState, TextFileModelChangeEvent, LocalFileChangeEvent} from 'vs/workbench/services/textfile/common/textfiles'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IEventService} from 'vs/platform/event/common/event'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts index df9c192b1cb..824c30f44bf 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts @@ -12,7 +12,8 @@ import {DiffEditorInput} from 'vs/workbench/common/editor/diffEditorInput'; import {IEditor} from 'vs/editor/common/editorCommon'; import {IEditor as IBaseEditor} from 'vs/platform/editor/common/editor'; import {EditorInput, IEditorStacksModel} from 'vs/workbench/common/editor'; -import {LocalFileChangeEvent, BINARY_FILE_EDITOR_ID, ITextFileService, ModelState} from 'vs/workbench/parts/files/common/files'; +import {BINARY_FILE_EDITOR_ID} from 'vs/workbench/parts/files/common/files'; +import {LocalFileChangeEvent, ITextFileService, ModelState} from 'vs/workbench/services/textfile/common/textfiles'; import {FileChangeType, FileChangesEvent, EventType as CommonFileEventType} from 'vs/platform/files/common/files'; import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService'; diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index 05934c194d3..9b03fadd5a0 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -4,18 +4,12 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {TPromise} from 'vs/base/common/winjs.base'; -import {Event as BaseEvent, PropertyChangeEvent} from 'vs/base/common/events'; import URI from 'vs/base/common/uri'; -import Event from 'vs/base/common/event'; -import {IEditorOptions, IRawText} from 'vs/editor/common/editorCommon'; -import {IDisposable} from 'vs/base/common/lifecycle'; -import {IEncodingSupport, EncodingMode, EditorInput, IFileEditorInput, ConfirmResult, IWorkbenchEditorConfiguration} from 'vs/workbench/common/editor'; -import {IFileStat, IFilesConfiguration, IBaseStat, IResolveContentOptions} from 'vs/platform/files/common/files'; -import {createDecorator} from 'vs/platform/instantiation/common/instantiation'; +import {IEditorOptions} from 'vs/editor/common/editorCommon'; +import {EncodingMode, EditorInput, IFileEditorInput, IWorkbenchEditorConfiguration} from 'vs/workbench/common/editor'; +import {IFilesConfiguration} from 'vs/platform/files/common/files'; import {FileStat} from 'vs/workbench/parts/files/common/explorerViewModel'; import {RawContextKey} from 'vs/platform/contextkey/common/contextkey'; -import {ITextEditorModel} from 'vs/platform/editor/common/editor'; /** * Explorer viewlet id. @@ -88,317 +82,4 @@ export function asFileResource(obj: any): IFileResource { } return null; -} - -/** - * The save error handler can be installed on the text text file editor model to install code that executes when save errors occur. - */ -export interface ISaveErrorHandler { - - /** - * Called whenever a save fails. - */ - onSaveError(error: any, model: ITextFileEditorModel): void; -} - -export interface ISaveParticipant { - - /** - * Participate in a save of a model. Allows to change the model before it is being saved to disk. - */ - participate(model: ITextFileEditorModel, env: { reason: SaveReason }): TPromise; -} - -/** - * States the text text file editor model can be in. - */ -export enum ModelState { - SAVED, - DIRTY, - PENDING_SAVE, - CONFLICT, - ERROR -} - -/** - * Local file change events are being emitted when a file is added, removed, moved or its contents got updated. These events - * are being emitted from within the workbench and are not reflecting the truth on the disk file system. For that, please - * use FileChangesEvent instead. - */ -export class LocalFileChangeEvent extends PropertyChangeEvent { - - constructor(before?: IFileStat, after?: IFileStat, originalEvent?: BaseEvent) { - super(null, before, after, originalEvent); - } - - /** - * Returns the meta information of the file before the event occurred or null if the file is new. - */ - public getBefore(): IFileStat { - return this.oldValue; - } - - /** - * Returns the meta information of the file after the event occurred or null if the file got deleted. - */ - public getAfter(): IFileStat { - return this.newValue; - } - - /** - * Indicates if the file was added as a new file. - */ - public gotAdded(): boolean { - return !this.oldValue && !!this.newValue; - } - - /** - * Indicates if the file was moved to a different path. - */ - public gotMoved(): boolean { - return !!this.oldValue && !!this.newValue && this.oldValue.resource.toString() !== this.newValue.resource.toString(); - } - - /** - * Indicates if the files metadata was updated. - */ - public gotUpdated(): boolean { - return !!this.oldValue && !!this.newValue && !this.gotMoved() && this.oldValue !== this.newValue; - } - - /** - * Indicates if the file was deleted. - */ - public gotDeleted(): boolean { - return !!this.oldValue && !this.newValue; - } -} - -export enum StateChange { - DIRTY, - SAVING, - SAVE_ERROR, - SAVED, - REVERTED, - ENCODING -} - -export class TextFileModelChangeEvent { - private _resource: URI; - private _kind: StateChange; - - constructor(model: ITextFileEditorModel, kind: StateChange) { - this._resource = model.getResource(); - this._kind = kind; - } - - public get resource(): URI { - return this._resource; - } - - public get kind(): StateChange { - return this._kind; - } -} - -export const TEXT_FILE_SERVICE_ID = 'textFileService'; - -export interface ITextFileOperationResult { - results: IResult[]; -} - -export interface IResult { - source: URI; - target?: URI; - success?: boolean; -} - -export interface IAutoSaveConfiguration { - autoSaveDelay: number; - autoSaveFocusChange: boolean; - autoSaveApplicationChange: boolean; -} - -export enum AutoSaveMode { - OFF, - AFTER_SHORT_DELAY, - AFTER_LONG_DELAY, - ON_FOCUS_CHANGE, - ON_WINDOW_CHANGE -} - -export enum SaveReason { - EXPLICIT = 1, - AUTO = 2, - FOCUS_CHANGE = 3, - WINDOW_CHANGE = 4 -} - -export const ITextFileService = createDecorator(TEXT_FILE_SERVICE_ID); - -export interface IRawTextContent extends IBaseStat { - - /** - * The line grouped content of a text file. - */ - value: IRawText; - - /** - * The line grouped logical hash of a text file. - */ - valueLogicalHash: string; - - /** - * The encoding of the content if known. - */ - encoding: string; -} - -export interface ITextFileEditorModelManager { - - onModelDirty: Event; - onModelSaveError: Event; - onModelSaved: Event; - onModelReverted: Event; - onModelEncodingChanged: Event; - - get(resource: URI): ITextFileEditorModel; - - getAll(resource?: URI): ITextFileEditorModel[]; - - loadOrCreate(resource: URI, preferredEncoding: string, refresh?: boolean): TPromise; -} - -export interface IModelSaveOptions { - reason?: SaveReason; - overwriteReadonly?: boolean; - overwriteEncoding?: boolean; -} - -export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport { - - onDidStateChange: Event; - - getResource(): URI; - - getLastSaveAttemptTime(): number; - - getLastModifiedTime(): number; - - getState(): ModelState; - - updatePreferredEncoding(encoding: string): void; - - save(options?: IModelSaveOptions): TPromise; - - revert(): TPromise; - - setConflictResolutionMode(); - - getValue(): string; - - isDirty(): boolean; - - isResolved(): boolean; - - isDisposed(): boolean; -} - -export interface ISaveOptions { - - /** - * Save the file on disk even if not dirty. If the file is not dirty, it will be touched - * so that mtime and atime are updated. This helps to trigger external file watchers. - */ - force: boolean; -} - -export interface ITextFileService extends IDisposable { - _serviceBrand: any; - onAutoSaveConfigurationChange: Event; - onFilesAssociationChange: Event; - - /** - * Access to the manager of text file editor models providing further methods to work with them. - */ - models: ITextFileEditorModelManager; - - /** - * Resolve the contents of a file identified by the resource. - */ - resolveTextContent(resource: URI, options?: IResolveContentOptions): TPromise; - - /** - * A resource is dirty if it has unsaved changes or is an untitled file not yet saved. - * - * @param resource the resource to check for being dirty. If it is not specified, will check for - * all dirty resources. - */ - isDirty(resource?: URI): boolean; - - /** - * Returns all resources that are currently dirty matching the provided resources or all dirty resources. - * - * @param resources the resources to check for being dirty. If it is not specified, will check for - * all dirty resources. - */ - getDirty(resources?: URI[]): URI[]; - - /** - * Saves the resource. - * - * @param resource the resource to save - * @return true iff the resource was saved. - */ - save(resource: URI, options?: ISaveOptions): TPromise; - - /** - * Saves the provided resource asking the user for a file name. - * - * @param resource the resource to save as. - * @return true iff the file was saved. - */ - saveAs(resource: URI, targetResource?: URI): TPromise; - - /** - * Saves the set of resources and returns a promise with the operation result. - * - * @param resources can be null to save all. - * @param includeUntitled to save all resources and optionally exclude untitled ones. - */ - saveAll(includeUntitled?: boolean): TPromise; - saveAll(resources: URI[]): TPromise; - - /** - * Reverts the provided resource. - * - * @param resource the resource of the file to revert. - * @param force to force revert even when the file is not dirty - */ - revert(resource: URI, force?: boolean): TPromise; - - /** - * Reverts all the provided resources and returns a promise with the operation result. - * - * @param force to force revert even when the file is not dirty - */ - revertAll(resources?: URI[], force?: boolean): TPromise; - - /** - * Brings up the confirm dialog to either save, don't save or cancel. - * - * @param resources the resources of the files to ask for confirmation or null if - * confirming for all dirty resources. - */ - confirmSave(resources?: URI[]): ConfirmResult; - - /** - * Convinient fast access to the current auto save mode. - */ - getAutoSaveMode(): AutoSaveMode; - - /** - * Convinient fast access to the raw configured auto save settings. - */ - getAutoSaveConfiguration(): IAutoSaveConfiguration; } \ No newline at end of file diff --git a/src/vs/workbench/parts/files/electron-browser/dirtyFilesTracker.ts b/src/vs/workbench/parts/files/electron-browser/dirtyFilesTracker.ts index 91a532732cb..0abfd9912d2 100644 --- a/src/vs/workbench/parts/files/electron-browser/dirtyFilesTracker.ts +++ b/src/vs/workbench/parts/files/electron-browser/dirtyFilesTracker.ts @@ -8,7 +8,8 @@ import nls = require('vs/nls'); import errors = require('vs/base/common/errors'); import {IWorkbenchContribution} from 'vs/workbench/common/contributions'; -import {VIEWLET_ID, TextFileModelChangeEvent, ITextFileService, AutoSaveMode} from 'vs/workbench/parts/files/common/files'; +import {VIEWLET_ID} from 'vs/workbench/parts/files/common/files'; +import {TextFileModelChangeEvent, ITextFileService, AutoSaveMode} from 'vs/workbench/services/textfile/common/textfiles'; import {platform, Platform} from 'vs/base/common/platform'; import {IWindowService} from 'vs/workbench/services/window/electron-browser/windowService'; import {Position} from 'vs/platform/editor/common/editor'; diff --git a/src/vs/workbench/parts/files/electron-browser/files.electron.contribution.ts b/src/vs/workbench/parts/files/electron-browser/files.electron.contribution.ts index d8453578d70..b36bb3dfba7 100644 --- a/src/vs/workbench/parts/files/electron-browser/files.electron.contribution.ts +++ b/src/vs/workbench/parts/files/electron-browser/files.electron.contribution.ts @@ -12,14 +12,12 @@ import {Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarC import {IWorkbenchActionRegistry, Extensions as ActionExtensions} from 'vs/workbench/common/actionRegistry'; import {SyncActionDescriptor} from 'vs/platform/actions/common/actions'; import env = require('vs/base/common/platform'); -import {ITextFileService, asFileResource} from 'vs/workbench/parts/files/common/files'; +import {asFileResource} from 'vs/workbench/parts/files/common/files'; import {IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions} from 'vs/workbench/common/contributions'; import {GlobalNewUntitledFileAction, SaveFileAsAction} from 'vs/workbench/parts/files/browser/fileActions'; import {DirtyFilesTracker} from 'vs/workbench/parts/files/electron-browser/dirtyFilesTracker'; -import {TextFileService} from 'vs/workbench/parts/files/electron-browser/textFileService'; import {OpenFolderAction, OpenFileAction, OpenFileFolderAction, ShowOpenedFileInNewWindow, GlobalRevealInOSAction, GlobalCopyPathAction, CopyPathAction, RevealInOSAction} from 'vs/workbench/parts/files/electron-browser/electronFileActions'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; -import {registerSingleton} from 'vs/platform/instantiation/common/extensions'; import {KeyMod, KeyChord, KeyCode} from 'vs/base/common/keyCodes'; class FileViewerActionContributor extends ActionBarContributor { @@ -78,7 +76,4 @@ actionsRegistry.registerActionBarContributor(Scope.VIEWER, FileViewerActionContr // Register Dirty Files Tracker (Registry.as(WorkbenchExtensions.Workbench)).registerWorkbenchContribution( DirtyFilesTracker -); - -// Register Service -registerSingleton(ITextFileService, TextFileService); \ No newline at end of file +); \ No newline at end of file diff --git a/src/vs/workbench/parts/files/test/browser/explorerViewModel.test.ts b/src/vs/workbench/parts/files/test/browser/explorerViewModel.test.ts index 9bbf77918c7..c42b0951ca2 100644 --- a/src/vs/workbench/parts/files/test/browser/explorerViewModel.test.ts +++ b/src/vs/workbench/parts/files/test/browser/explorerViewModel.test.ts @@ -11,7 +11,7 @@ import {isLinux, isWindows} from 'vs/base/common/platform'; import URI from 'vs/base/common/uri'; import {join} from 'vs/base/common/paths'; import {validateFileName} from 'vs/workbench/parts/files/browser/fileActions'; -import {LocalFileChangeEvent} from 'vs/workbench/parts/files/common/files'; +import {LocalFileChangeEvent} from 'vs/workbench/services/textfile/common/textfiles'; import {FileStat} from 'vs/workbench/parts/files/common/explorerViewModel'; function createStat(path, name, isFolder, hasChildren, size, mtime) { diff --git a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts index 778c9702b2c..18d92905eee 100644 --- a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts +++ b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts @@ -13,8 +13,7 @@ import {workbenchInstantiationService, TestTextFileService} from 'vs/test/utils/ import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {EncodingMode} from 'vs/workbench/common/editor'; import {IEventService} from 'vs/platform/event/common/event'; -import {ITextFileEditorModel} from 'vs/workbench/parts/files/common/files'; -import {ITextFileService, LocalFileChangeEvent} from 'vs/workbench/parts/files/common/files'; +import {ITextFileEditorModel, ITextFileService, LocalFileChangeEvent} from 'vs/workbench/services/textfile/common/textfiles'; import {FileOperationResult, IFileOperationResult, FileChangesEvent, FileChangeType, EventType} from 'vs/platform/files/common/files'; function toResource(path) { diff --git a/src/vs/workbench/parts/files/test/browser/fileEvents.test.ts b/src/vs/workbench/parts/files/test/browser/fileEvents.test.ts index c645c0eb359..bd17803b93e 100644 --- a/src/vs/workbench/parts/files/test/browser/fileEvents.test.ts +++ b/src/vs/workbench/parts/files/test/browser/fileEvents.test.ts @@ -6,7 +6,7 @@ 'use strict'; import * as assert from 'assert'; -import {LocalFileChangeEvent} from 'vs/workbench/parts/files/common/files'; +import {LocalFileChangeEvent} from 'vs/workbench/services/textfile/common/textfiles'; import {FileImportedEvent} from 'vs/workbench/parts/files/browser/fileActions'; suite('Files - Events', () => { diff --git a/src/vs/workbench/parts/git/browser/gitServices.ts b/src/vs/workbench/parts/git/browser/gitServices.ts index 0de067a7db3..5b9ac5a66a0 100644 --- a/src/vs/workbench/parts/git/browser/gitServices.ts +++ b/src/vs/workbench/parts/git/browser/gitServices.ts @@ -20,7 +20,7 @@ import { IFileStatus, IGitServiceError, GitErrorCodes, Status, StatusType, AutoF import { Model } from 'vs/workbench/parts/git/common/gitModel'; import { NativeGitIndexStringEditorInput, GitIndexDiffEditorInput, GitWorkingTreeDiffEditorInput, GitDiffEditorInput } from 'vs/workbench/parts/git/browser/gitEditorInputs'; import { GitOperation } from 'vs/workbench/parts/git/browser/gitOperations'; -import { TextFileModelChangeEvent, ITextFileService } from 'vs/workbench/parts/files/common/files'; +import { TextFileModelChangeEvent, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IFileService, EventType as FileEventType, FileChangesEvent, FileChangeType } from 'vs/platform/files/common/files'; import { ThrottledDelayer, PeriodThrottledDelayer } from 'vs/base/common/async'; import severity from 'vs/base/common/severity'; diff --git a/src/vs/workbench/parts/git/electron-browser/electronGitService.ts b/src/vs/workbench/parts/git/electron-browser/electronGitService.ts index 9e5b068b503..acae7fed98d 100644 --- a/src/vs/workbench/parts/git/electron-browser/electronGitService.ts +++ b/src/vs/workbench/parts/git/electron-browser/electronGitService.ts @@ -8,7 +8,7 @@ import { IRawGitService, RawServiceState, IGitConfiguration } from 'vs/workbench import { NoOpGitService } from 'vs/workbench/parts/git/common/noopGitService'; import { GitService } from 'vs/workbench/parts/git/browser/gitServices'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { ITextFileService } from 'vs/workbench/parts/files/common/files'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IOutputService } from 'vs/workbench/parts/output/common/output'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index 05d43600e1f..5ff78e9a6c2 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -57,7 +57,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { ITextFileService } from 'vs/workbench/parts/files/common/files'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IOutputService, IOutputChannelRegistry, Extensions as OutputExt, IOutputChannel } from 'vs/workbench/parts/output/common/output'; import { ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, TaskConfiguration, TaskDescription, TaskSystemEvents } from 'vs/workbench/parts/tasks/common/taskSystem'; diff --git a/src/vs/workbench/parts/files/common/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts similarity index 99% rename from src/vs/workbench/parts/files/common/textFileService.ts rename to src/vs/workbench/services/textfile/browser/textFileService.ts index 50d0f21f1aa..5ba8665a653 100644 --- a/src/vs/workbench/parts/files/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -11,7 +11,7 @@ import DOM = require('vs/base/browser/dom'); import errors = require('vs/base/common/errors'); import objects = require('vs/base/common/objects'); import Event, {Emitter} from 'vs/base/common/event'; -import {IResult, ITextFileOperationResult, ITextFileService, IRawTextContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ISaveOptions} from 'vs/workbench/parts/files/common/files'; +import {IResult, ITextFileOperationResult, ITextFileService, IRawTextContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ISaveOptions} from 'vs/workbench/services/textfile/common/textfiles'; import {ConfirmResult} from 'vs/workbench/common/editor'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; @@ -24,7 +24,7 @@ import {IEditorGroupService} from 'vs/workbench/services/group/common/groupServi import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService'; import {UntitledEditorModel} from 'vs/workbench/common/editor/untitledEditorModel'; import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; -import {TextFileEditorModelManager} from 'vs/workbench/parts/files/common/editors/textFileEditorModelManager'; +import {TextFileEditorModelManager} from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; /** diff --git a/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts similarity index 99% rename from src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts rename to src/vs/workbench/services/textfile/common/textFileEditorModel.ts index c40fdd64f28..29d66b65e93 100644 --- a/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -19,7 +19,7 @@ import types = require('vs/base/common/types'); import {IModelContentChangedEvent} from 'vs/editor/common/editorCommon'; import {IMode} from 'vs/editor/common/modes'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; -import {ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, IModelSaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, IModelSaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason} from 'vs/workbench/services/textfile/common/textfiles'; import {EncodingMode, EditorModel} from 'vs/workbench/common/editor'; import {BaseTextEditorModel} from 'vs/workbench/common/editor/textEditorModel'; import {IFileService, IFileStat, IFileOperationResult, FileOperationResult} from 'vs/platform/files/common/files'; diff --git a/src/vs/workbench/parts/files/test/browser/textFileEditorModelManager.test.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.test.ts similarity index 97% rename from src/vs/workbench/parts/files/test/browser/textFileEditorModelManager.test.ts rename to src/vs/workbench/services/textfile/common/textFileEditorModelManager.test.ts index a9d909ad739..ee4a33aa2b3 100644 --- a/src/vs/workbench/parts/files/test/browser/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.test.ts @@ -8,15 +8,15 @@ import * as assert from 'assert'; import URI from 'vs/base/common/uri'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; -import {TextFileEditorModelManager} from 'vs/workbench/parts/files/common/editors/textFileEditorModelManager'; +import {TextFileEditorModelManager} from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; import {EditorModel} from 'vs/workbench/common/editor'; import {join, basename} from 'vs/base/common/paths'; import {workbenchInstantiationService, TestEditorGroupService} from 'vs/test/utils/servicesTestUtils'; import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService'; import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; -import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; +import {TextFileEditorModel} from 'vs/workbench/services/textfile/common/textFileEditorModel'; import {IEventService} from 'vs/platform/event/common/event'; -import {LocalFileChangeEvent} from 'vs/workbench/parts/files/common/files'; +import {LocalFileChangeEvent} from 'vs/workbench/services/textfile/common/textfiles'; import {FileChangesEvent, EventType as CommonFileEventType, FileChangeType} from 'vs/platform/files/common/files'; class ServiceAccessor { diff --git a/src/vs/workbench/parts/files/common/editors/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts similarity index 98% rename from src/vs/workbench/parts/files/common/editors/textFileEditorModelManager.ts rename to src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index 6a91400c223..5f126eaf103 100644 --- a/src/vs/workbench/parts/files/common/editors/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -7,10 +7,10 @@ import Event, {Emitter} from 'vs/base/common/event'; import {TPromise} from 'vs/base/common/winjs.base'; import URI from 'vs/base/common/uri'; -import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; +import {TextFileEditorModel} from 'vs/workbench/services/textfile/common/textFileEditorModel'; import {dispose, IDisposable} from 'vs/base/common/lifecycle'; import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService'; -import {ModelState, ITextFileEditorModel, LocalFileChangeEvent, ITextFileEditorModelManager, TextFileModelChangeEvent, StateChange} from 'vs/workbench/parts/files/common/files'; +import {ModelState, ITextFileEditorModel, LocalFileChangeEvent, ITextFileEditorModelManager, TextFileModelChangeEvent, StateChange} from 'vs/workbench/services/textfile/common/textfiles'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; import {IEventService} from 'vs/platform/event/common/event'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts new file mode 100644 index 00000000000..185ee86c30c --- /dev/null +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -0,0 +1,330 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import {TPromise} from 'vs/base/common/winjs.base'; +import URI from 'vs/base/common/uri'; +import Event from 'vs/base/common/event'; +import {IRawText} from 'vs/editor/common/editorCommon'; +import {IDisposable} from 'vs/base/common/lifecycle'; +import {IEncodingSupport, ConfirmResult} from 'vs/workbench/common/editor'; +import {IFileStat, IBaseStat, IResolveContentOptions} from 'vs/platform/files/common/files'; +import {createDecorator} from 'vs/platform/instantiation/common/instantiation'; +import {ITextEditorModel} from 'vs/platform/editor/common/editor'; +import {Event as BaseEvent, PropertyChangeEvent} from 'vs/base/common/events'; + + +/** + * The save error handler can be installed on the text text file editor model to install code that executes when save errors occur. + */ +export interface ISaveErrorHandler { + + /** + * Called whenever a save fails. + */ + onSaveError(error: any, model: ITextFileEditorModel): void; +} + +export interface ISaveParticipant { + + /** + * Participate in a save of a model. Allows to change the model before it is being saved to disk. + */ + participate(model: ITextFileEditorModel, env: { reason: SaveReason }): TPromise; +} + +/** + * States the text text file editor model can be in. + */ +export enum ModelState { + SAVED, + DIRTY, + PENDING_SAVE, + CONFLICT, + ERROR +} + +/** + * Local file change events are being emitted when a file is added, removed, moved or its contents got updated. These events + * are being emitted from within the workbench and are not reflecting the truth on the disk file system. For that, please + * use FileChangesEvent instead. + */ +export class LocalFileChangeEvent extends PropertyChangeEvent { + + constructor(before?: IFileStat, after?: IFileStat, originalEvent?: BaseEvent) { + super(null, before, after, originalEvent); + } + + /** + * Returns the meta information of the file before the event occurred or null if the file is new. + */ + public getBefore(): IFileStat { + return this.oldValue; + } + + /** + * Returns the meta information of the file after the event occurred or null if the file got deleted. + */ + public getAfter(): IFileStat { + return this.newValue; + } + + /** + * Indicates if the file was added as a new file. + */ + public gotAdded(): boolean { + return !this.oldValue && !!this.newValue; + } + + /** + * Indicates if the file was moved to a different path. + */ + public gotMoved(): boolean { + return !!this.oldValue && !!this.newValue && this.oldValue.resource.toString() !== this.newValue.resource.toString(); + } + + /** + * Indicates if the files metadata was updated. + */ + public gotUpdated(): boolean { + return !!this.oldValue && !!this.newValue && !this.gotMoved() && this.oldValue !== this.newValue; + } + + /** + * Indicates if the file was deleted. + */ + public gotDeleted(): boolean { + return !!this.oldValue && !this.newValue; + } +} + +export enum StateChange { + DIRTY, + SAVING, + SAVE_ERROR, + SAVED, + REVERTED, + ENCODING +} + +export class TextFileModelChangeEvent { + private _resource: URI; + private _kind: StateChange; + + constructor(model: ITextFileEditorModel, kind: StateChange) { + this._resource = model.getResource(); + this._kind = kind; + } + + public get resource(): URI { + return this._resource; + } + + public get kind(): StateChange { + return this._kind; + } +} + +export const TEXT_FILE_SERVICE_ID = 'textFileService'; + +export interface ITextFileOperationResult { + results: IResult[]; +} + +export interface IResult { + source: URI; + target?: URI; + success?: boolean; +} + +export interface IAutoSaveConfiguration { + autoSaveDelay: number; + autoSaveFocusChange: boolean; + autoSaveApplicationChange: boolean; +} + +export enum AutoSaveMode { + OFF, + AFTER_SHORT_DELAY, + AFTER_LONG_DELAY, + ON_FOCUS_CHANGE, + ON_WINDOW_CHANGE +} + +export enum SaveReason { + EXPLICIT = 1, + AUTO = 2, + FOCUS_CHANGE = 3, + WINDOW_CHANGE = 4 +} + +export const ITextFileService = createDecorator(TEXT_FILE_SERVICE_ID); + +export interface IRawTextContent extends IBaseStat { + + /** + * The line grouped content of a text file. + */ + value: IRawText; + + /** + * The line grouped logical hash of a text file. + */ + valueLogicalHash: string; + + /** + * The encoding of the content if known. + */ + encoding: string; +} + +export interface ITextFileEditorModelManager { + + onModelDirty: Event; + onModelSaveError: Event; + onModelSaved: Event; + onModelReverted: Event; + onModelEncodingChanged: Event; + + get(resource: URI): ITextFileEditorModel; + + getAll(resource?: URI): ITextFileEditorModel[]; + + loadOrCreate(resource: URI, preferredEncoding: string, refresh?: boolean): TPromise; +} + +export interface IModelSaveOptions { + reason?: SaveReason; + overwriteReadonly?: boolean; + overwriteEncoding?: boolean; +} + +export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport { + + onDidStateChange: Event; + + getResource(): URI; + + getLastSaveAttemptTime(): number; + + getLastModifiedTime(): number; + + getState(): ModelState; + + updatePreferredEncoding(encoding: string): void; + + save(options?: IModelSaveOptions): TPromise; + + revert(): TPromise; + + setConflictResolutionMode(); + + getValue(): string; + + isDirty(): boolean; + + isResolved(): boolean; + + isDisposed(): boolean; +} + +export interface ISaveOptions { + + /** + * Save the file on disk even if not dirty. If the file is not dirty, it will be touched + * so that mtime and atime are updated. This helps to trigger external file watchers. + */ + force: boolean; +} + +export interface ITextFileService extends IDisposable { + _serviceBrand: any; + onAutoSaveConfigurationChange: Event; + onFilesAssociationChange: Event; + + /** + * Access to the manager of text file editor models providing further methods to work with them. + */ + models: ITextFileEditorModelManager; + + /** + * Resolve the contents of a file identified by the resource. + */ + resolveTextContent(resource: URI, options?: IResolveContentOptions): TPromise; + + /** + * A resource is dirty if it has unsaved changes or is an untitled file not yet saved. + * + * @param resource the resource to check for being dirty. If it is not specified, will check for + * all dirty resources. + */ + isDirty(resource?: URI): boolean; + + /** + * Returns all resources that are currently dirty matching the provided resources or all dirty resources. + * + * @param resources the resources to check for being dirty. If it is not specified, will check for + * all dirty resources. + */ + getDirty(resources?: URI[]): URI[]; + + /** + * Saves the resource. + * + * @param resource the resource to save + * @return true iff the resource was saved. + */ + save(resource: URI, options?: ISaveOptions): TPromise; + + /** + * Saves the provided resource asking the user for a file name. + * + * @param resource the resource to save as. + * @return true iff the file was saved. + */ + saveAs(resource: URI, targetResource?: URI): TPromise; + + /** + * Saves the set of resources and returns a promise with the operation result. + * + * @param resources can be null to save all. + * @param includeUntitled to save all resources and optionally exclude untitled ones. + */ + saveAll(includeUntitled?: boolean): TPromise; + saveAll(resources: URI[]): TPromise; + + /** + * Reverts the provided resource. + * + * @param resource the resource of the file to revert. + * @param force to force revert even when the file is not dirty + */ + revert(resource: URI, force?: boolean): TPromise; + + /** + * Reverts all the provided resources and returns a promise with the operation result. + * + * @param force to force revert even when the file is not dirty + */ + revertAll(resources?: URI[], force?: boolean): TPromise; + + /** + * Brings up the confirm dialog to either save, don't save or cancel. + * + * @param resources the resources of the files to ask for confirmation or null if + * confirming for all dirty resources. + */ + confirmSave(resources?: URI[]): ConfirmResult; + + /** + * Convinient fast access to the current auto save mode. + */ + getAutoSaveMode(): AutoSaveMode; + + /** + * Convinient fast access to the raw configured auto save settings. + */ + getAutoSaveConfiguration(): IAutoSaveConfiguration; +} \ No newline at end of file diff --git a/src/vs/workbench/parts/files/electron-browser/textFileService.ts b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts similarity index 98% rename from src/vs/workbench/parts/files/electron-browser/textFileService.ts rename to src/vs/workbench/services/textfile/electron-browser/textFileService.ts index cba7157bd68..5464b18da75 100644 --- a/src/vs/workbench/parts/files/electron-browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts @@ -12,8 +12,8 @@ import strings = require('vs/base/common/strings'); import {isWindows, isLinux} from 'vs/base/common/platform'; import URI from 'vs/base/common/uri'; import {ConfirmResult} from 'vs/workbench/common/editor'; -import {TextFileService as AbstractTextFileService} from 'vs/workbench/parts/files/common/textFileService'; -import {IRawTextContent} from 'vs/workbench/parts/files/common/files'; +import {TextFileService as AbstractTextFileService} from 'vs/workbench/services/textfile/browser/textFileService'; +import {IRawTextContent} from 'vs/workbench/services/textfile/common/textfiles'; import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService'; import {IFileService, IResolveContentOptions} from 'vs/platform/files/common/files'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; diff --git a/src/vs/workbench/parts/files/test/browser/fileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts similarity index 97% rename from src/vs/workbench/parts/files/test/browser/fileEditorModel.test.ts rename to src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts index 9752c86157b..d9a243673b1 100644 --- a/src/vs/workbench/parts/files/test/browser/fileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts @@ -12,11 +12,11 @@ import URI from 'vs/base/common/uri'; import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import paths = require('vs/base/common/paths'); import {EncodingMode} from 'vs/workbench/common/editor'; -import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; +import {TextFileEditorModel} from 'vs/workbench/services/textfile/common/textFileEditorModel'; import {IEventService} from 'vs/platform/event/common/event'; -import {ITextFileService, ModelState, StateChange} from 'vs/workbench/parts/files/common/files'; +import {ITextFileService, ModelState, StateChange} from 'vs/workbench/services/textfile/common/textfiles'; import {workbenchInstantiationService, TestTextFileService} from 'vs/test/utils/servicesTestUtils'; -import {TextFileEditorModelManager} from 'vs/workbench/parts/files/common/editors/textFileEditorModelManager'; +import {TextFileEditorModelManager} from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; import {FileOperationResult, IFileOperationResult} from 'vs/platform/files/common/files'; function toResource(path) { diff --git a/src/vs/workbench/parts/files/test/browser/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts similarity index 95% rename from src/vs/workbench/parts/files/test/browser/textFileService.test.ts rename to src/vs/workbench/services/textfile/test/textFileService.test.ts index 24dfd64e2f1..21d0a3e35ae 100644 --- a/src/vs/workbench/parts/files/test/browser/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -11,12 +11,12 @@ import paths = require('vs/base/common/paths'); import {ILifecycleService, ShutdownEvent} from 'vs/platform/lifecycle/common/lifecycle'; import {workbenchInstantiationService, TestLifecycleService, TestTextFileService} from 'vs/test/utils/servicesTestUtils'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; -import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; -import {ITextFileService} from 'vs/workbench/parts/files/common/files'; +import {TextFileEditorModel} from 'vs/workbench/services/textfile/common/textFileEditorModel'; +import {ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; import {ConfirmResult} from 'vs/workbench/common/editor'; import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService'; import {UntitledEditorModel} from 'vs/workbench/common/editor/untitledEditorModel'; -import {TextFileEditorModelManager} from 'vs/workbench/parts/files/common/editors/textFileEditorModelManager'; +import {TextFileEditorModelManager} from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; function toResource(path) { return URI.file(paths.join('C:\\', path)); diff --git a/src/vs/workbench/test/browser/services.test.ts b/src/vs/workbench/test/browser/services.test.ts index 64e1260235c..4eebc8e0994 100644 --- a/src/vs/workbench/test/browser/services.test.ts +++ b/src/vs/workbench/test/browser/services.test.ts @@ -16,7 +16,7 @@ import {EditorInput, EditorOptions, TextEditorOptions} from 'vs/workbench/common import {StringEditorInput} from 'vs/workbench/common/editor/stringEditorInput'; import {StringEditorModel} from 'vs/workbench/common/editor/stringEditorModel'; import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; -import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; +import {TextFileEditorModel} from 'vs/workbench/services/textfile/common/textFileEditorModel'; import {workbenchInstantiationService} from 'vs/test/utils/servicesTestUtils'; import {Viewlet} from 'vs/workbench/browser/viewlet'; import {IPanel} from 'vs/workbench/common/panel'; diff --git a/src/vs/workbench/test/node/api/extHostDocumentSaveParticipant.test.ts b/src/vs/workbench/test/node/api/extHostDocumentSaveParticipant.test.ts index eaa69d4fca9..8e3aa07b591 100644 --- a/src/vs/workbench/test/node/api/extHostDocumentSaveParticipant.test.ts +++ b/src/vs/workbench/test/node/api/extHostDocumentSaveParticipant.test.ts @@ -14,7 +14,7 @@ import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDoc import { OneGetThreadService } from './testThreadService'; import * as EditorCommon from 'vs/editor/common/editorCommon'; import { IResourceEdit } from 'vs/editor/common/services/bulkEdit'; -import { SaveReason } from 'vs/workbench/parts/files/common/files'; +import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; suite('ExtHostDocumentSaveParticipant', () => { From b61ae53c647a82bf5c2cd99e9cdb21d278955483 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 15:24:25 +0200 Subject: [PATCH 066/163] fix tests --- src/vs/test/utils/servicesTestUtils.ts | 5 +++++ .../services/textfile/test/textFileEditorModel.test.ts | 7 +++---- .../{common => test}/textFileEditorModelManager.test.ts | 5 ++--- 3 files changed, 10 insertions(+), 7 deletions(-) rename src/vs/workbench/services/textfile/{common => test}/textFileEditorModelManager.test.ts (97%) diff --git a/src/vs/test/utils/servicesTestUtils.ts b/src/vs/test/utils/servicesTestUtils.ts index 60173af928e..61bebb26e11 100644 --- a/src/vs/test/utils/servicesTestUtils.ts +++ b/src/vs/test/utils/servicesTestUtils.ts @@ -6,6 +6,7 @@ 'use strict'; import 'vs/workbench/parts/files/browser/files.contribution'; // load our contribution into the test +import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import {Promise, TPromise} from 'vs/base/common/winjs.base'; import {TestInstantiationService} from 'vs/test/utils/instantiationTestUtils'; import {EventEmitter} from 'vs/base/common/eventEmitter'; @@ -49,6 +50,10 @@ export const TestWorkspace: IWorkspace = { uid: Date.now() }; +export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { + return instantiationService.createInstance(FileEditorInput, resource, void 0); +} + export const TestEnvironmentService = new EnvironmentService(parseArgs(process.argv), process.execPath); export class TestContextService implements IWorkspaceContextService { diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts index d9a243673b1..fb26e7c328c 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts @@ -9,13 +9,12 @@ import * as assert from 'assert'; import {TPromise} from 'vs/base/common/winjs.base'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import URI from 'vs/base/common/uri'; -import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import paths = require('vs/base/common/paths'); import {EncodingMode} from 'vs/workbench/common/editor'; import {TextFileEditorModel} from 'vs/workbench/services/textfile/common/textFileEditorModel'; import {IEventService} from 'vs/platform/event/common/event'; import {ITextFileService, ModelState, StateChange} from 'vs/workbench/services/textfile/common/textfiles'; -import {workbenchInstantiationService, TestTextFileService} from 'vs/test/utils/servicesTestUtils'; +import {workbenchInstantiationService, TestTextFileService, createFileInput} from 'vs/test/utils/servicesTestUtils'; import {TextFileEditorModelManager} from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; import {FileOperationResult, IFileOperationResult} from 'vs/platform/files/common/files'; @@ -238,8 +237,8 @@ suite('Files - TextFileEditorModel', () => { }); test('save() and isDirty() - proper with check for mtimes', function (done) { - const input1 = instantiationService.createInstance(FileEditorInput, toResource('/path/index_async2.txt'), 'utf8'); - const input2 = instantiationService.createInstance(FileEditorInput, toResource('/path/index_async.txt'), 'utf8'); + const input1 = createFileInput(instantiationService, toResource('/path/index_async2.txt')); + const input2 = createFileInput(instantiationService, toResource('/path/index_async.txt')); input1.resolve().then((model1: TextFileEditorModel) => { input2.resolve().then((model2: TextFileEditorModel) => { diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts similarity index 97% rename from src/vs/workbench/services/textfile/common/textFileEditorModelManager.test.ts rename to src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts index ee4a33aa2b3..433bf428166 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts @@ -11,9 +11,8 @@ import {IInstantiationService} from 'vs/platform/instantiation/common/instantiat import {TextFileEditorModelManager} from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; import {EditorModel} from 'vs/workbench/common/editor'; import {join, basename} from 'vs/base/common/paths'; -import {workbenchInstantiationService, TestEditorGroupService} from 'vs/test/utils/servicesTestUtils'; +import {workbenchInstantiationService, TestEditorGroupService, createFileInput} from 'vs/test/utils/servicesTestUtils'; import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService'; -import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import {TextFileEditorModel} from 'vs/workbench/services/textfile/common/textFileEditorModel'; import {IEventService} from 'vs/platform/event/common/event'; import {LocalFileChangeEvent} from 'vs/workbench/services/textfile/common/textfiles'; @@ -145,7 +144,7 @@ suite('Files - TextFileEditorModelManager', () => { const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, resource, 'utf8'); manager.add(resource, model); - const input = instantiationService.createInstance(FileEditorInput, resource, void 0); + const input = createFileInput(instantiationService, resource); const stacks = accessor.editorGroupService.getStacksModel(); const group = stacks.openGroup('group', true); From 0d096feddd43598d07405b306a7e02f8fdb7f276 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 15:28:54 +0200 Subject: [PATCH 067/163] avoid input creation for checking for dirty state --- .../workbench/electron-browser/workbench.ts | 6 +-- .../node/configurationEditingService.ts | 46 +++++++++---------- .../node/configurationEditingService.test.ts | 45 +++++++++++------- 3 files changed, 54 insertions(+), 43 deletions(-) diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 10b851046f0..6832aa0ba59 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -389,6 +389,9 @@ export class Workbench implements IPartService { // History serviceCollection.set(IHistoryService, this.instantiationService.createInstance(HistoryService)); + // Text File Service + serviceCollection.set(ITextFileService, this.instantiationService.createInstance(TextFileService)); + // Configuration Editing serviceCollection.set(IConfigurationEditingService, this.instantiationService.createInstance(ConfigurationEditingService)); @@ -403,9 +406,6 @@ export class Workbench implements IPartService { this.toShutdown.push(this.quickOpen); serviceCollection.set(IQuickOpenService, this.quickOpen); - // Text File Service - serviceCollection.set(ITextFileService, this.instantiationService.createInstance(TextFileService)); - // Contributed services const contributedServices = getServices(); for (let contributedService of contributedServices) { diff --git a/src/vs/workbench/services/configuration/node/configurationEditingService.ts b/src/vs/workbench/services/configuration/node/configurationEditingService.ts index 507f97aafa7..7f715f73796 100644 --- a/src/vs/workbench/services/configuration/node/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/node/configurationEditingService.ts @@ -12,11 +12,11 @@ import * as json from 'vs/base/common/json'; import * as encoding from 'vs/base/node/encoding'; import strings = require('vs/base/common/strings'); import {getConfigurationKeys} from 'vs/platform/configuration/common/model'; -import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; import {setProperty} from 'vs/base/common/jsonEdit'; import {applyEdits} from 'vs/base/common/jsonFormatter'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IEnvironmentService} from 'vs/platform/environment/common/environment'; +import {ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {WORKSPACE_CONFIG_DEFAULT_PATH} from 'vs/workbench/services/configuration/common/configuration'; import {IFileService} from 'vs/platform/files/common/files'; @@ -47,7 +47,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService @IWorkspaceContextService private contextService: IWorkspaceContextService, @IEnvironmentService private environmentService: IEnvironmentService, @IFileService private fileService: IFileService, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService + @ITextFileService private textFileService: ITextFileService ) { } @@ -160,33 +160,31 @@ export class ConfigurationEditingService implements IConfigurationEditingService // Target cannot be dirty const resource = operation.target; - return this.editorService.createInput({ resource }).then(typedInput => { - if (typedInput.isDirty()) { - return { error: ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY }; + if (this.textFileService.isDirty(resource)) { + return TPromise.as({ error: ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY }); + } + + return this.fileService.existsFile(resource).then(exists => { + if (!exists) { + return { exists }; } - return this.fileService.existsFile(resource).then(exists => { - if (!exists) { - return { exists }; + return this.fileService.resolveContent(resource, { acceptTextOnly: true, encoding: encoding.UTF8 }).then(content => { + + // If we write to a workspace standalone file and replace the entire contents (no key provided) + // we can return here because any parse errors can safely be ignored since all contents are replaced + if (operation.isWorkspaceStandalone && !operation.key) { + return { exists, contents: content.value }; } - return this.fileService.resolveContent(resource, { acceptTextOnly: true, encoding: encoding.UTF8 }).then(content => { + // Target cannot contain JSON errors + const parseErrors = []; + json.parse(content.value, parseErrors); + if (parseErrors.length > 0) { + return { error: ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION }; + } - // If we write to a workspace standalone file and replace the entire contents (no key provided) - // we can return here because any parse errors can safely be ignored since all contents are replaced - if (operation.isWorkspaceStandalone && !operation.key) { - return { exists, contents: content.value }; - } - - // Target cannot contain JSON errors - const parseErrors = []; - json.parse(content.value, parseErrors); - if (parseErrors.length > 0) { - return { error: ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION }; - } - - return { exists, contents: content.value }; - }); + return { exists, contents: content.value }; }); }); } diff --git a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts index 9377af88a1a..6eb2c2e326d 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts @@ -13,10 +13,10 @@ import * as json from 'vs/base/common/json'; import {TPromise} from 'vs/base/common/winjs.base'; import {Registry} from 'vs/platform/platform'; import {ParsedArgs, parseArgs} from 'vs/platform/environment/node/argv'; -import {WorkspaceContextService} from 'vs/platform/workspace/common/workspace'; +import {WorkspaceContextService, IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {EnvironmentService} from 'vs/platform/environment/node/environmentService'; import extfs = require('vs/base/node/extfs'); -import {TestEventService, TestEditorService} from 'vs/test/utils/servicesTestUtils'; +import {TestEventService, workbenchInstantiationService, TestTextFileService} from 'vs/test/utils/servicesTestUtils'; import uuid = require('vs/base/common/uuid'); import {IConfigurationRegistry, Extensions as ConfigurationExtensions} from 'vs/platform/configuration/common/configurationRegistry'; import {WorkspaceConfigurationService} from 'vs/workbench/services/configuration/node/configurationService'; @@ -25,7 +25,14 @@ import utils = require('vs/workbench/services/files/test/node/utils'); import {FileService} from 'vs/workbench/services/files/node/fileService'; import {ConfigurationEditingService, WORKSPACE_STANDALONE_CONFIGURATIONS} from 'vs/workbench/services/configuration/node/configurationEditingService'; import {ConfigurationTarget, IConfigurationEditingError, ConfigurationEditingErrorCode} from 'vs/workbench/services/configuration/common/configurationEditing'; -import {IResourceInput} from 'vs/platform/editor/common/editor'; +import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService'; +import {IFileService} from 'vs/platform/files/common/files'; +import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; +import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; +import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; +import {IUntitledEditorService} from 'vs/workbench/services/untitled/common/untitledEditorService'; +import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; +import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; class SettingsTestEnvironmentService extends EnvironmentService { @@ -36,19 +43,25 @@ class SettingsTestEnvironmentService extends EnvironmentService { get appSettingsPath(): string { return this.customAppSettingsHome; } } -class TestWorkbenchEditorService extends TestEditorService { +class TestDirtyTextFileService extends TestTextFileService { - constructor(private dirty: boolean) { - super(); + constructor( + private dirty: boolean, + @ILifecycleService lifecycleService: ILifecycleService, + @IWorkspaceContextService contextService: IWorkspaceContextService, + @IConfigurationService configurationService: IConfigurationService, + @ITelemetryService telemetryService: ITelemetryService, + @IWorkbenchEditorService editorService: IWorkbenchEditorService, + @IEditorGroupService editorGroupService: IEditorGroupService, + @IFileService fileService: IFileService, + @IUntitledEditorService untitledEditorService: IUntitledEditorService, + @IInstantiationService instantiationService: IInstantiationService + ) { + super(lifecycleService, contextService, configurationService, telemetryService, editorService, editorGroupService, fileService, untitledEditorService, instantiationService); } - public createInput(input: IResourceInput): TPromise { - return TPromise.as({ - getName: () => 'name', - getDescription: () => 'description', - isDirty: () => this.dirty, - matches: () => false - }); + public isDirty(resource?: URI): boolean { + return this.dirty; } } @@ -70,14 +83,14 @@ suite('WorkspaceConfigurationEditingService - Node', () => { const workspaceContextService = new WorkspaceContextService(noWorkspace ? null : { resource: URI.file(workspaceDir) }); const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile); const configurationService = new WorkspaceConfigurationService(workspaceContextService, new TestEventService(), environmentService); - const editorService = new TestWorkbenchEditorService(dirty); + const textFileService = workbenchInstantiationService().createInstance(TestDirtyTextFileService, dirty); const events = new utils.TestEventService(); const fileService = new FileService(noWorkspace ? null : workspaceDir, { disableWatcher: true }, events); return configurationService.initialize().then(() => { return { - configurationEditingService: new ConfigurationEditingService(configurationService, workspaceContextService, environmentService, fileService, editorService), - configurationService: configurationService + configurationEditingService: new ConfigurationEditingService(configurationService, workspaceContextService, environmentService, fileService, textFileService), + configurationService }; }); } From 1d7389c79c03dd59207ffdd267e2a8d44e7f2d1d Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 5 Oct 2016 11:54:53 +0200 Subject: [PATCH 068/163] fix typo --- src/vs/workbench/parts/files/browser/views/explorerViewer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index 87104902766..59509c0a25b 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -172,7 +172,7 @@ export class FileActionProvider extends ContributableActionProvider { return super.getSecondaryActions(tree, stat); } - public runAction(tree: ITree, stat: FileStat, action: IAction, ontext?: any): TPromise; + public runAction(tree: ITree, stat: FileStat, action: IAction, context?: any): TPromise; public runAction(tree: ITree, stat: FileStat, actionID: string, context?: any): TPromise; public runAction(tree: ITree, stat: FileStat, arg: any, context: any = {}): TPromise { context = objects.mixin({ From 44b84f7f43002df67b91cdf8e7393bbb756c9e11 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 5 Oct 2016 12:14:53 +0200 Subject: [PATCH 069/163] fix #13115 --- .../markers/browser/markersActionProvider.ts | 87 ------------------- .../parts/markers/browser/markersPanel.ts | 6 +- .../markers/browser/markersTreeController.ts | 87 ++++++++++++++++++- .../markers/browser/markersTreeViewer.ts | 4 +- .../browser/markersWorkbenchContributions.ts | 6 +- .../parts/markers/common/constants.ts | 3 +- .../markersElectronContributions.ts | 68 +++++++++++++++ .../parts/markers/markers.contribution.ts | 4 +- 8 files changed, 167 insertions(+), 98 deletions(-) delete mode 100644 src/vs/workbench/parts/markers/browser/markersActionProvider.ts create mode 100644 src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts diff --git a/src/vs/workbench/parts/markers/browser/markersActionProvider.ts b/src/vs/workbench/parts/markers/browser/markersActionProvider.ts deleted file mode 100644 index 0e9d2c18932..00000000000 --- a/src/vs/workbench/parts/markers/browser/markersActionProvider.ts +++ /dev/null @@ -1,87 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import * as nls from 'vs/nls'; -import winjs = require('vs/base/common/winjs.base'); -import lifecycle = require('vs/base/common/lifecycle'); -import actions = require('vs/base/common/actions'); -import actionbar = require('vs/base/browser/ui/actionbar/actionbar'); -import actionsrenderer = require('vs/base/parts/tree/browser/actionsRenderer'); -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import tree = require('vs/base/parts/tree/browser/tree'); -import { Resource } from 'vs/workbench/parts/markers/common/markersModel'; - -class RemoveResourceAction extends actions.Action { - constructor() { - super('remove', nls.localize('RemoveAction.label', "Remove"), 'action-remove'); - } - - public run(context?: any): winjs.TPromise { - return (context['tree']).refresh(); - } -} - -export class ActionContainer implements lifecycle.IDisposable { - - private cache: { [actionId:string]:actions.IAction; }; - private instantiationService: IInstantiationService; - - constructor(instantiationService: IInstantiationService) { - this.cache = {}; - this.instantiationService = instantiationService; - } - - protected getAction(ctor: any, ...args: any[]): any { - var action = this.cache[ctor.ID]; - - if (!action) { - args.unshift(ctor); - action = this.cache[ctor.ID] = this.instantiationService.createInstance.apply(this.instantiationService, args); - } - - return action; - } - - public dispose(): void { - Object.keys(this.cache).forEach(k => { - this.cache[k].dispose(); - }); - - this.cache = null; - } -} - - -export class ActionProvider extends ActionContainer implements actionsrenderer.IActionProvider { - - constructor(@IInstantiationService instantiationService: IInstantiationService) { - super(instantiationService); - } - - public hasActions(tree: tree.ITree, element: any): boolean { - return element instanceof Resource; - } - - public getActions(tree: tree.ITree, element: any): winjs.TPromise { - return winjs.TPromise.as(this.getActionsForResource()); - } - - public getActionsForResource(): actions.IAction[] { - return [new RemoveResourceAction()]; - } - - public hasSecondaryActions(tree: tree.ITree, element: any): boolean { - return false; - } - - public getSecondaryActions(tree: tree.ITree, element: any): winjs.TPromise { - return winjs.TPromise.as([]); - } - - public getActionItem(tree: tree.ITree, element: any, action: actions.IAction): actionbar.IActionItem { - return null; - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/markers/browser/markersPanel.ts b/src/vs/workbench/parts/markers/browser/markersPanel.ts index f70322a2893..7a280eee158 100644 --- a/src/vs/workbench/parts/markers/browser/markersPanel.ts +++ b/src/vs/workbench/parts/markers/browser/markersPanel.ts @@ -30,11 +30,11 @@ import Tree = require('vs/base/parts/tree/browser/tree'); import TreeImpl = require('vs/base/parts/tree/browser/treeImpl'); import * as Viewer from 'vs/workbench/parts/markers/browser/markersTreeViewer'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ActionProvider } from 'vs/workbench/parts/markers/browser/markersActionProvider'; import { CollapseAllAction, FilterAction, FilterInputBoxActionItem } from 'vs/workbench/parts/markers/browser/markersPanelActions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import Messages from 'vs/workbench/parts/markers/common/messages'; import { RangeHighlightDecorations } from 'vs/workbench/common/editor/rangeDecorations'; +import { ContributableActionProvider } from 'vs/workbench/browser/actionBarRegistry'; export class MarkersPanel extends Panel { @@ -169,9 +169,9 @@ export class MarkersPanel extends Panel { private createTree(parent: HTMLElement): void { this.treeContainer = dom.append(parent, dom.$('.tree-container')); dom.addClass(this.treeContainer, 'show-file-icons'); - var actionProvider = this.instantiationService.createInstance(ActionProvider); + var actionProvider = this.instantiationService.createInstance(ContributableActionProvider); var renderer = this.instantiationService.createInstance(Viewer.Renderer, this.getActionRunner(), actionProvider); - let controller = this.instantiationService.createInstance(Controller, this.rangeHighlightDecorations); + let controller = this.instantiationService.createInstance(Controller, this.rangeHighlightDecorations, actionProvider); this.tree = new TreeImpl.Tree(this.treeContainer, { dataSource: new Viewer.DataSource(), renderer, diff --git a/src/vs/workbench/parts/markers/browser/markersTreeController.ts b/src/vs/workbench/parts/markers/browser/markersTreeController.ts index 973824bd0be..05b79d9a4a1 100644 --- a/src/vs/workbench/parts/markers/browser/markersTreeController.ts +++ b/src/vs/workbench/parts/markers/browser/markersTreeController.ts @@ -10,15 +10,31 @@ import keyboard = require('vs/base/browser/keyboardEvent'); import tree = require('vs/base/parts/tree/browser/tree'); import treedefaults = require('vs/base/parts/tree/browser/treeDefaults'); import { MarkersModel, Marker } from 'vs/workbench/parts/markers/common/markersModel'; +import Constants from 'vs/workbench/parts/markers/common/constants'; import { RangeHighlightDecorations } from 'vs/workbench/common/editor/rangeDecorations'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IMenuService, IMenu, MenuId } from 'vs/platform/actions/common/actions'; +import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; +import { Keybinding } from 'vs/base/common/keybinding'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { IActionProvider } from 'vs/base/parts/tree/browser/actionsRenderer'; export class Controller extends treedefaults.DefaultController { - constructor(private rangeHighlightDecorations: RangeHighlightDecorations, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, + private contributedContextMenu: IMenu; + + constructor(private rangeHighlightDecorations: RangeHighlightDecorations, private actionProvider: IActionProvider, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, + @IContextMenuService private contextMenuService: IContextMenuService, + @IMenuService menuService: IMenuService, + @IContextKeyService contextKeyService: IContextKeyService, @ITelemetryService private telemetryService: ITelemetryService) { super(); + + this.contributedContextMenu = menuService.createMenu(MenuId.ExplorerContext, contextKeyService); + this.downKeyBindingDispatcher.set(Controller.getKeybindingForCopyAction(), (tree: tree.ITree, event: any) => this.onCopy(tree, event)); } protected onLeftClick(tree: tree.ITree, element: any, event: mouse.IMouseEvent): boolean { @@ -57,6 +73,38 @@ export class Controller extends treedefaults.DefaultController { return super.onSpace(tree, event); } + public onContextMenu(tree: tree.ITree, element: any, event: tree.ContextMenuEvent): boolean { + if (!this.actionProvider.hasSecondaryActions(tree, element)) { + return true; + } + + const anchor = { x: event.posx + 1, y: event.posy }; + this.contextMenuService.showContextMenu({ + getAnchor: () => anchor, + getActions: () => { + return this.actionProvider.getSecondaryActions(tree, element).then(actions => { + fillInActions(this.contributedContextMenu, actions); + return actions; + }); + }, + getActionItem: this.actionProvider.getActionItem.bind(this.actionProvider, tree, element), + getKeyBinding: (a): Keybinding => Controller.keybindingForAction(a.id), + getActionsContext: (event) => { + return { + element, + event + }; + }, + onHide: (wasCancelled?: boolean) => { + if (wasCancelled) { + tree.DOMFocus(); + } + } + }); + + return true; + } + private openFileAtElement(element: any, preserveFocus: boolean, sideByside: boolean, pinned: boolean): boolean { if (element instanceof Marker) { const marker: Marker = element; @@ -82,4 +130,41 @@ export class Controller extends treedefaults.DefaultController { } return false; } + + private onCopy(tree: tree.ITree, event: any): boolean { + return this.runAction(tree, Constants.MARKER_COPY_ACTION_ID); + } + + private runAction(tree: tree.ITree, id: string): boolean { + const element = tree.getFocus(); + if (!element) { + return false; + } + + if (!this.actionProvider.hasSecondaryActions(tree, element)) { + return false; + } + + this.actionProvider.getSecondaryActions(tree, element) + .then(actions => { + for (const action of actions) { + if (action.id === id && action.enabled) { + action.run({ element }); + return; + } + } + }); + + return true; + } + + private static keybindingForAction(id: string): Keybinding { + if (Constants.MARKER_COPY_ACTION_ID === id) { + return new Keybinding(Controller.getKeybindingForCopyAction()); + } + } + + private static getKeybindingForCopyAction(): number { + return KeyMod.CtrlCmd | KeyCode.KEY_C; + } } \ No newline at end of file diff --git a/src/vs/workbench/parts/markers/browser/markersTreeViewer.ts b/src/vs/workbench/parts/markers/browser/markersTreeViewer.ts index 97c8b482681..ce6cd763357 100644 --- a/src/vs/workbench/parts/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/parts/markers/browser/markersTreeViewer.ts @@ -10,7 +10,7 @@ import {IDataSource, ITree, IRenderer, IAccessibilityProvider, ISorter } from 'v import { IActionRunner } from 'vs/base/common/actions'; import Severity from 'vs/base/common/severity'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; -import { ActionProvider } from 'vs/workbench/parts/markers/browser/markersActionProvider'; +import { IActionProvider } from 'vs/base/parts/tree/browser/actionsRenderer'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { FileLabel } from 'vs/workbench/browser/labels'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; @@ -70,7 +70,7 @@ export class Renderer implements IRenderer { private static MARKER_TEMPLATE_ID= 'marker-template'; constructor(private actionRunner: IActionRunner, - private actionProvider:ActionProvider, + private actionProvider: IActionProvider, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IInstantiationService private instantiationService: IInstantiationService ) { diff --git a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts index 96a05562b79..f6148763ac8 100644 --- a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts +++ b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import {localize} from 'vs/nls'; -import lifecycle = require('vs/base/common/lifecycle'); +import { localize } from 'vs/nls'; +import * as lifecycle from 'vs/base/common/lifecycle'; import Messages from 'vs/workbench/parts/markers/common/messages'; import Constants from 'vs/workbench/parts/markers/common/constants'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; @@ -93,4 +93,4 @@ export function registerContributions(): void { (platform.Registry.as(WorkbenchExtensions.Workbench)).registerWorkbenchContribution( StatusUpdater ); -} +} \ No newline at end of file diff --git a/src/vs/workbench/parts/markers/common/constants.ts b/src/vs/workbench/parts/markers/common/constants.ts index 931d324cb56..7af42eb6b9f 100644 --- a/src/vs/workbench/parts/markers/common/constants.ts +++ b/src/vs/workbench/parts/markers/common/constants.ts @@ -5,5 +5,6 @@ 'use strict'; export default { - MARKERS_PANEL_ID: 'workbench.panel.markers' + MARKERS_PANEL_ID: 'workbench.panel.markers', + MARKER_COPY_ACTION_ID: 'workbench.action.marker.copy' }; diff --git a/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts b/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts new file mode 100644 index 00000000000..abbaf6daaf1 --- /dev/null +++ b/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { TPromise } from 'vs/base/common/winjs.base'; +import { Registry } from 'vs/platform/platform'; +import { IAction, Action } from 'vs/base/common/actions'; +import { localize } from 'vs/nls'; +import { clipboard } from 'electron'; +import { Marker } from 'vs/workbench/parts/markers/common/markersModel'; +import Constants from 'vs/workbench/parts/markers/common/constants'; +import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actionBarRegistry'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import Severity from 'vs/base/common/severity'; + + +class CopyMarker extends Action { + + public static ID = Constants.MARKER_COPY_ACTION_ID; + + constructor(@IWorkspaceContextService private contextService: IWorkspaceContextService,) { + super(CopyMarker.ID, localize('copyMarker', "Copy")); + } + + public run(context): TPromise { + if (context.element) { + const marker = context.element; + clipboard.writeText(`${this.printFormat(marker)}`); + } + return TPromise.as(true); + } + + private printFormat(marker: Marker): string { + return [`file: '${marker.marker.resource}'`, + `severity: '${Severity.toString(marker.marker.severity)}'`, + `message: '${marker.marker.message}'`, + `at: '${marker.marker.startLineNumber},${marker.marker.startColumn}'`, + `source: '${marker.marker.source ? marker.marker.source : ''}'`].join('\n'); + } +} + +class MarkersViewerActionContributor extends ActionBarContributor { + + constructor(@IInstantiationService private instantiationService: IInstantiationService) { + super(); + } + + public hasSecondaryActions(context: any): boolean { + const element = context.element; + return element instanceof Marker; + } + + public getSecondaryActions(context: any): IAction[] { + const actions: IAction[] = []; + if (this.hasSecondaryActions(context)) { + actions.push(this.instantiationService.createInstance(CopyMarker)); + } + + return actions; + } +} + +export function registerContributions(): void { + const actionsRegistry = Registry.as(ActionBarExtensions.Actionbar); + actionsRegistry.registerActionBarContributor(Scope.VIEWER, MarkersViewerActionContributor); +} \ No newline at end of file diff --git a/src/vs/workbench/parts/markers/markers.contribution.ts b/src/vs/workbench/parts/markers/markers.contribution.ts index c189abe82ca..8e93a5abe41 100644 --- a/src/vs/workbench/parts/markers/markers.contribution.ts +++ b/src/vs/workbench/parts/markers/markers.contribution.ts @@ -3,5 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { registerContributions } from 'vs/workbench/parts/markers/browser/markersWorkbenchContributions'; +import { registerContributions as registerElectronContributions } from 'vs/workbench/parts/markers/electron-browser/markersElectronContributions'; -registerContributions(); \ No newline at end of file +registerContributions(); +registerElectronContributions(); \ No newline at end of file From 5f98e9427f8eda22364a90f6f6b418a0e3db76e8 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 5 Oct 2016 15:46:16 +0200 Subject: [PATCH 070/163] implement menu in new approach --- src/vs/platform/actions/common/actions.ts | 3 +- src/vs/workbench/common/component.ts | 8 +- .../parts/markers/browser/markersPanel.ts | 16 ++ .../markers/browser/markersTreeController.ts | 93 +++++------ .../parts/markers/common/constants.ts | 7 +- .../parts/markers/common/markersModel.ts | 9 ++ .../markersElectronContributions.ts | 149 +++++++++++------- 7 files changed, 172 insertions(+), 113 deletions(-) diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 5e517209238..1474cd8a0a8 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -40,7 +40,8 @@ export enum MenuId { EditorTitle = 1, EditorContext = 2, ExplorerContext = 3, - EditorTabContext = 4 + EditorTabContext = 4, + ProblemsPanelContext = 5 } export const IMenuService = createDecorator('menuService'); diff --git a/src/vs/workbench/common/component.ts b/src/vs/workbench/common/component.ts index 3a5eb71e533..960d723573a 100644 --- a/src/vs/workbench/common/component.ts +++ b/src/vs/workbench/common/component.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {IDisposable, dispose} from 'vs/base/common/lifecycle'; +import {IDisposable, dispose, Disposable} from 'vs/base/common/lifecycle'; import {Scope, Memento} from 'vs/workbench/common/memento'; -import {IStorageService} from 'vs/platform/storage/common/storage'; +import { IStorageService } from 'vs/platform/storage/common/storage'; /** * Base class of any core/ui component in the workbench. Examples include services, extensions, parts, viewlets and quick open. @@ -54,12 +54,13 @@ export interface IWorkbenchComponent extends IDisposable { dispose(): void; } -export class WorkbenchComponent implements IWorkbenchComponent { +export class WorkbenchComponent extends Disposable implements IWorkbenchComponent { private _toUnbind: IDisposable[]; private id: string; private componentMemento: Memento; constructor(id: string) { + super(); this._toUnbind = []; this.id = id; this.componentMemento = new Memento(this.id); @@ -89,5 +90,6 @@ export class WorkbenchComponent implements IWorkbenchComponent { public dispose(): void { this._toUnbind = dispose(this._toUnbind); + super.dispose(); } } \ No newline at end of file diff --git a/src/vs/workbench/parts/markers/browser/markersPanel.ts b/src/vs/workbench/parts/markers/browser/markersPanel.ts index 7a280eee158..8a4e7645d1e 100644 --- a/src/vs/workbench/parts/markers/browser/markersPanel.ts +++ b/src/vs/workbench/parts/markers/browser/markersPanel.ts @@ -35,6 +35,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import Messages from 'vs/workbench/parts/markers/common/messages'; import { RangeHighlightDecorations } from 'vs/workbench/common/editor/rangeDecorations'; import { ContributableActionProvider } from 'vs/workbench/browser/actionBarRegistry'; +import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; export class MarkersPanel extends Panel { @@ -59,6 +60,8 @@ export class MarkersPanel extends Panel { private messageBoxContainer: HTMLElement; private messageBox: HTMLElement; + private markerFocusContextKey: IContextKey; + constructor( @IInstantiationService private instantiationService: IInstantiationService, @IMarkerService private markerService: IMarkerService, @@ -66,12 +69,14 @@ export class MarkersPanel extends Panel { @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEventService private eventService: IEventService, @IConfigurationService private configurationService: IConfigurationService, + @IContextKeyService private contextKeyService: IContextKeyService, @ITelemetryService telemetryService: ITelemetryService ) { super(Constants.MARKERS_PANEL_ID, telemetryService); this.toDispose = []; this.delayedRefresh = new Delayer(500); this.autoExpanded = new Set.ArraySet(); + this.markerFocusContextKey = Constants.MarkerFocusContextKey.bindTo(contextKeyService); } public create(parent: builder.Builder): TPromise { @@ -183,6 +188,13 @@ export class MarkersPanel extends Panel { twistiePixels: 20, ariaLabel: Messages.MARKERS_PANEL_ARIA_LABEL_PROBLEMS_TREE }); + this._register(this.tree.addListener2('focus', (e: { focus: any }) => { + this.markerFocusContextKey.set(e.focus instanceof Marker); + })); + const focusTracker = this._register(dom.trackFocus(this.tree.getHTMLElement())); + focusTracker.addBlurListener(() => { + this.markerFocusContextKey.set(false); + }); } private createActions(): void { @@ -339,6 +351,10 @@ export class MarkersPanel extends Panel { return super.getActionItem(action); } + public getFocusElement(): Resource | Marker { + return this.tree.getFocus(); + } + public dispose(): void { this.delayedRefresh.cancel(); this.toDispose = lifecycle.dispose(this.toDispose); diff --git a/src/vs/workbench/parts/markers/browser/markersTreeController.ts b/src/vs/workbench/parts/markers/browser/markersTreeController.ts index 05b79d9a4a1..6b246e37528 100644 --- a/src/vs/workbench/parts/markers/browser/markersTreeController.ts +++ b/src/vs/workbench/parts/markers/browser/markersTreeController.ts @@ -5,36 +5,37 @@ 'use strict'; import * as errors from 'vs/base/common/errors'; -import mouse = require('vs/base/browser/mouseEvent'); +import { TPromise } from 'vs/base/common/winjs.base'; +import * as mouse from 'vs/base/browser/mouseEvent'; import keyboard = require('vs/base/browser/keyboardEvent'); import tree = require('vs/base/parts/tree/browser/tree'); import treedefaults = require('vs/base/parts/tree/browser/treeDefaults'); import { MarkersModel, Marker } from 'vs/workbench/parts/markers/common/markersModel'; -import Constants from 'vs/workbench/parts/markers/common/constants'; import { RangeHighlightDecorations } from 'vs/workbench/common/editor/rangeDecorations'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IMenuService, IMenu, MenuId } from 'vs/platform/actions/common/actions'; -import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; +import { IAction } from 'vs/base/common/actions'; import { Keybinding } from 'vs/base/common/keybinding'; -import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { IActionProvider } from 'vs/base/parts/tree/browser/actionsRenderer'; +import { ActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; export class Controller extends treedefaults.DefaultController { - private contributedContextMenu: IMenu; + private contextMenu: IMenu; constructor(private rangeHighlightDecorations: RangeHighlightDecorations, private actionProvider: IActionProvider, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IContextMenuService private contextMenuService: IContextMenuService, @IMenuService menuService: IMenuService, @IContextKeyService contextKeyService: IContextKeyService, + @IKeybindingService private _keybindingService: IKeybindingService, @ITelemetryService private telemetryService: ITelemetryService) { super(); - this.contributedContextMenu = menuService.createMenu(MenuId.ExplorerContext, contextKeyService); - this.downKeyBindingDispatcher.set(Controller.getKeybindingForCopyAction(), (tree: tree.ITree, event: any) => this.onCopy(tree, event)); + this.contextMenu = menuService.createMenu(MenuId.ProblemsPanelContext, contextKeyService); } protected onLeftClick(tree: tree.ITree, element: any, event: mouse.IMouseEvent): boolean { @@ -74,27 +75,31 @@ export class Controller extends treedefaults.DefaultController { } public onContextMenu(tree: tree.ITree, element: any, event: tree.ContextMenuEvent): boolean { - if (!this.actionProvider.hasSecondaryActions(tree, element)) { + tree.setFocus(element); + const actions = this._getMenuActions(); + if (!actions.length) { return true; } - const anchor = { x: event.posx + 1, y: event.posy }; this.contextMenuService.showContextMenu({ getAnchor: () => anchor, + getActions: () => { - return this.actionProvider.getSecondaryActions(tree, element).then(actions => { - fillInActions(this.contributedContextMenu, actions); - return actions; - }); + return TPromise.as(actions); }, - getActionItem: this.actionProvider.getActionItem.bind(this.actionProvider, tree, element), - getKeyBinding: (a): Keybinding => Controller.keybindingForAction(a.id), - getActionsContext: (event) => { - return { - element, - event - }; + + getActionItem: (action) => { + const keybinding = this._keybindingFor(action); + if (keybinding) { + return new ActionItem(action, action, { label: true, keybinding: this._keybindingService.getLabelFor(keybinding) }); + } + return null; }, + + getKeyBinding: (action): Keybinding => { + return this._keybindingFor(action); + }, + onHide: (wasCancelled?: boolean) => { if (wasCancelled) { tree.DOMFocus(); @@ -131,40 +136,24 @@ export class Controller extends treedefaults.DefaultController { return false; } - private onCopy(tree: tree.ITree, event: any): boolean { - return this.runAction(tree, Constants.MARKER_COPY_ACTION_ID); + private _getMenuActions(): IAction[] { + const result: IAction[] = []; + const groups = this.contextMenu.getActions(); + + for (let group of groups) { + const [, actions] = group; + result.push(...actions); + result.push(new Separator()); + } + result.pop(); // remove last separator + return result; } - private runAction(tree: tree.ITree, id: string): boolean { - const element = tree.getFocus(); - if (!element) { - return false; + private _keybindingFor(action: IAction): Keybinding { + var opts = this._keybindingService.lookupKeybindings(action.id); + if (opts.length > 0) { + return opts[0]; // only take the first one } - - if (!this.actionProvider.hasSecondaryActions(tree, element)) { - return false; - } - - this.actionProvider.getSecondaryActions(tree, element) - .then(actions => { - for (const action of actions) { - if (action.id === id && action.enabled) { - action.run({ element }); - return; - } - } - }); - - return true; - } - - private static keybindingForAction(id: string): Keybinding { - if (Constants.MARKER_COPY_ACTION_ID === id) { - return new Keybinding(Controller.getKeybindingForCopyAction()); - } - } - - private static getKeybindingForCopyAction(): number { - return KeyMod.CtrlCmd | KeyCode.KEY_C; + return null; } } \ No newline at end of file diff --git a/src/vs/workbench/parts/markers/common/constants.ts b/src/vs/workbench/parts/markers/common/constants.ts index 7af42eb6b9f..d3f122c3856 100644 --- a/src/vs/workbench/parts/markers/common/constants.ts +++ b/src/vs/workbench/parts/markers/common/constants.ts @@ -2,9 +2,12 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; + +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export default { MARKERS_PANEL_ID: 'workbench.panel.markers', - MARKER_COPY_ACTION_ID: 'workbench.action.marker.copy' + MARKER_COPY_ACTION_ID: 'problems.action.copy', + + MarkerFocusContextKey: new RawContextKey('problemFocus', false) }; diff --git a/src/vs/workbench/parts/markers/common/markersModel.ts b/src/vs/workbench/parts/markers/common/markersModel.ts index 52dc0b4edb4..6671a020d28 100644 --- a/src/vs/workbench/parts/markers/common/markersModel.ts +++ b/src/vs/workbench/parts/markers/common/markersModel.ts @@ -57,6 +57,15 @@ export class Marker { public get range(): IRange { return this.marker; } + + public toString(): string { + return [`file: '${this.marker.resource}'`, + `severity: '${Severity.toString(this.marker.severity)}'`, + `message: '${this.marker.message}'`, + `at: '${this.marker.startLineNumber},${this.marker.startColumn}'`, + `source: '${this.marker.source ? this.marker.source : ''}'`].join('\n'); + } + } export class FilterOptions { diff --git a/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts b/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts index abbaf6daaf1..e71ca0fa057 100644 --- a/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts +++ b/src/vs/workbench/parts/markers/electron-browser/markersElectronContributions.ts @@ -3,66 +3,105 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { TPromise } from 'vs/base/common/winjs.base'; -import { Registry } from 'vs/platform/platform'; -import { IAction, Action } from 'vs/base/common/actions'; import { localize } from 'vs/nls'; import { clipboard } from 'electron'; import { Marker } from 'vs/workbench/parts/markers/common/markersModel'; import Constants from 'vs/workbench/parts/markers/common/constants'; -import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions, ActionBarContributor } from 'vs/workbench/browser/actionBarRegistry'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import Severity from 'vs/base/common/severity'; +import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands'; +import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; +import {ContextKeyExpr} from 'vs/platform/contextkey/common/contextkey'; +import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { IKeybindings } from 'vs/platform/keybinding/common/keybinding'; +import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { MarkersPanel } from 'vs/workbench/parts/markers/browser/markersPanel'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -class CopyMarker extends Action { - - public static ID = Constants.MARKER_COPY_ACTION_ID; - - constructor(@IWorkspaceContextService private contextService: IWorkspaceContextService,) { - super(CopyMarker.ID, localize('copyMarker', "Copy")); - } - - public run(context): TPromise { - if (context.element) { - const marker = context.element; - clipboard.writeText(`${this.printFormat(marker)}`); - } - return TPromise.as(true); - } - - private printFormat(marker: Marker): string { - return [`file: '${marker.marker.resource}'`, - `severity: '${Severity.toString(marker.marker.severity)}'`, - `message: '${marker.marker.message}'`, - `at: '${marker.marker.startLineNumber},${marker.marker.startColumn}'`, - `source: '${marker.marker.source ? marker.marker.source : ''}'`].join('\n'); - } -} - -class MarkersViewerActionContributor extends ActionBarContributor { - - constructor(@IInstantiationService private instantiationService: IInstantiationService) { - super(); - } - - public hasSecondaryActions(context: any): boolean { - const element = context.element; - return element instanceof Marker; - } - - public getSecondaryActions(context: any): IAction[] { - const actions: IAction[] = []; - if (this.hasSecondaryActions(context)) { - actions.push(this.instantiationService.createInstance(CopyMarker)); - } - - return actions; - } -} - export function registerContributions(): void { - const actionsRegistry = Registry.as(ActionBarExtensions.Actionbar); - actionsRegistry.registerActionBarContributor(Scope.VIEWER, MarkersViewerActionContributor); + registerAction({ + id: Constants.MARKER_COPY_ACTION_ID, + title: localize('copyMarker', "Copy"), + handler(accessor) { + copyMarker(accessor.get(IPanelService)); + }, + menu: { + menuId: MenuId.ProblemsPanelContext, + when: Constants.MarkerFocusContextKey + }, + keybinding: { + keys: { + primary: KeyMod.CtrlCmd | KeyCode.KEY_C + }, + when: Constants.MarkerFocusContextKey + } + }); +} + +function copyMarker(panelService: IPanelService) { + const activePanel = panelService.getActivePanel(); + if (activePanel instanceof MarkersPanel) { + const element = (activePanel).getFocusElement(); + if (element instanceof Marker) { + clipboard.writeText(`${element}`); + } + } +} + +interface IActionDescriptor { + id: string; + handler: ICommandHandler; + + // ICommandUI + title: string; + category?: string; + iconClass?: string; + f1?: boolean; + + // + menu?: { + menuId: MenuId, + when?: ContextKeyExpr; + group?: string; + }; + + // + keybinding?: { + when?: ContextKeyExpr; + weight?: number; + keys: IKeybindings; + }; +} + +function registerAction(desc: IActionDescriptor) { + + const {id, handler, title, category, iconClass, menu, keybinding} = desc; + + // 1) register as command + CommandsRegistry.registerCommand(id, handler); + + // 2) menus + let command = { id, title, iconClass, category }; + if (menu) { + let {menuId, when, group} = menu; + MenuRegistry.appendMenuItem(menuId, { + command, + when, + group + }); + } + + // 3) keybindings + if (keybinding) { + let {when, weight, keys} = keybinding; + KeybindingsRegistry.registerKeybindingRule({ + id, + when, + weight, + primary: keys.primary, + secondary: keys.secondary, + linux: keys.linux, + mac: keys.mac, + win: keys.win + }); + } } \ No newline at end of file From 321bed74e2a86bafbea83fe2aa7c65da721c1f76 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 5 Oct 2016 15:55:35 +0200 Subject: [PATCH 071/163] tests #13115 --- .../markers/test/common/markersModel.test.ts | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/parts/markers/test/common/markersModel.test.ts b/src/vs/workbench/parts/markers/test/common/markersModel.test.ts index e4be9d7b25a..6ea1c12e361 100644 --- a/src/vs/workbench/parts/markers/test/common/markersModel.test.ts +++ b/src/vs/workbench/parts/markers/test/common/markersModel.test.ts @@ -120,6 +120,13 @@ suite('MarkersModel Test', () => { assert.equal(actuals[14].marker, marker4); }); + test('toString()', function () { + assert.equal(`file: 'file:///a/res1'\nseverity: 'Error'\nmessage: 'some message'\nat: '10,5'\nsource: 'tslint'`, new Marker('', aMarker('a/res1')).toString()); + assert.equal(`file: 'file:///a/res2'\nseverity: 'Warning'\nmessage: 'some message'\nat: '10,5'\nsource: 'tslint'`, new Marker('', aMarker('a/res2', Severity.Warning)).toString()); + assert.equal(`file: 'file:///a/res2'\nseverity: 'Info'\nmessage: 'Info'\nat: '1,2'\nsource: ''`, new Marker('', aMarker('a/res2', Severity.Info, 1, 2, 1, 8, 'Info', '')).toString()); + assert.equal(`file: 'file:///a/res2'\nseverity: ''\nmessage: 'Ignore message'\nat: '1,2'\nsource: 'Ignore'`, new Marker('', aMarker('a/res2', Severity.Ignore, 1, 2, 1, 8, 'Ignore message', 'Ignore')).toString()); + }); + function hasMarker(markers:Marker[], marker:IMarker):boolean { return markers.filter((m):boolean => { return m.marker === marker; @@ -172,17 +179,19 @@ suite('MarkersModel Test', () => { startColumn:number=5, endLineNumber:number= startLineNumber + 1, endColumn:number=startColumn + 5, - message:string='some message' + message: string = 'some message', + source: string = 'tslint' ):IMarker { return { owner: 'someOwner', resource: URI.file(resource), - severity: severity, - message: message, - startLineNumber: startLineNumber, - startColumn: startColumn, - endLineNumber: endLineNumber, - endColumn: endColumn + severity, + message, + startLineNumber, + startColumn, + endLineNumber, + endColumn, + source }; } }); \ No newline at end of file From b9513f5dec5d4224578eb569aba99dc56572c805 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 16:03:42 +0200 Subject: [PATCH 072/163] fix flaky tests --- .../textfile/test/textFileEditorModel.test.ts | 8 +++++++- .../test/textFileEditorModelManager.test.ts | 20 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts index fb26e7c328c..7bef48631c7 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts @@ -17,13 +17,14 @@ import {ITextFileService, ModelState, StateChange} from 'vs/workbench/services/t import {workbenchInstantiationService, TestTextFileService, createFileInput} from 'vs/test/utils/servicesTestUtils'; import {TextFileEditorModelManager} from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; import {FileOperationResult, IFileOperationResult} from 'vs/platform/files/common/files'; +import {IModelService} from 'vs/editor/common/services/modelService'; function toResource(path) { return URI.file(paths.join('C:\\', path)); } class ServiceAccessor { - constructor( @IEventService public eventService: IEventService, @ITextFileService public textFileService: TestTextFileService) { + constructor( @IEventService public eventService: IEventService, @ITextFileService public textFileService: TestTextFileService, @IModelService public modelService: IModelService) { } } @@ -54,6 +55,7 @@ suite('Files - TextFileEditorModel', () => { assert.ok(!model.isDirty()); model.dispose(); + assert.ok(!accessor.modelService.getModel(model.getResource())); done(); }); @@ -112,6 +114,8 @@ suite('Files - TextFileEditorModel', () => { model.dispose(); + assert.ok(!accessor.modelService.getModel(model.getResource())); + done(); }); }); @@ -231,6 +235,8 @@ suite('Files - TextFileEditorModel', () => { model.dispose(); + assert.ok(!accessor.modelService.getModel(model.getResource())); + done(); }); }); diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts index 433bf428166..43ec9b89b61 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts @@ -17,11 +17,13 @@ import {TextFileEditorModel} from 'vs/workbench/services/textfile/common/textFil import {IEventService} from 'vs/platform/event/common/event'; import {LocalFileChangeEvent} from 'vs/workbench/services/textfile/common/textfiles'; import {FileChangesEvent, EventType as CommonFileEventType, FileChangeType} from 'vs/platform/files/common/files'; +import {IModelService} from 'vs/editor/common/services/modelService'; class ServiceAccessor { constructor( @IEditorGroupService public editorGroupService: TestEditorGroupService, - @IEventService public eventService: IEventService + @IEventService public eventService: IEventService, + @IModelService public modelService: IModelService ) { } } @@ -159,6 +161,8 @@ suite('Files - TextFileEditorModelManager', () => { assert.ok(model.isDisposed()); model.dispose(); + assert.ok(!accessor.modelService.getModel(model.getResource())); + manager.dispose(); }); @@ -178,6 +182,7 @@ suite('Files - TextFileEditorModelManager', () => { assert.ok(model.isDisposed()); model.dispose(); + assert.ok(!accessor.modelService.getModel(model.getResource())); manager.dispose(); }); @@ -196,6 +201,7 @@ suite('Files - TextFileEditorModelManager', () => { accessor.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(toStat(resource), toStat(toResource('/path/index_moved.txt')))); assert.ok(model.isDisposed()); + assert.ok(!accessor.modelService.getModel(model.getResource())); manager.dispose(); }); @@ -214,6 +220,7 @@ suite('Files - TextFileEditorModelManager', () => { accessor.eventService.emit(CommonFileEventType.FILE_CHANGES, new FileChangesEvent([{ resource, type: FileChangeType.DELETED }])); assert.ok(model.isDisposed()); + assert.ok(!accessor.modelService.getModel(model.getResource())); manager.dispose(); }); @@ -232,6 +239,7 @@ suite('Files - TextFileEditorModelManager', () => { accessor.eventService.emit(CommonFileEventType.FILE_CHANGES, new FileChangesEvent([{ resource, type: FileChangeType.UPDATED }])); assert.ok(model.isDisposed()); + assert.ok(!accessor.modelService.getModel(model.getResource())); manager.dispose(); }); @@ -256,6 +264,8 @@ suite('Files - TextFileEditorModelManager', () => { assert.ok(!model.isDisposed()); model.dispose(); + assert.ok(!accessor.modelService.getModel(model.getResource())); + manager.dispose(); done(); }); @@ -311,6 +321,12 @@ suite('Files - TextFileEditorModelManager', () => { assert.equal(savedCounter, 1); assert.equal(encodingCounter, 2); + model1.dispose(); + model2.dispose(); + + assert.ok(!accessor.modelService.getModel(resource1)); + assert.ok(!accessor.modelService.getModel(resource2)); + done(); }); }); @@ -328,6 +344,8 @@ suite('Files - TextFileEditorModelManager', () => { model.dispose(); assert.ok(!manager.get(resource)); + assert.ok(!accessor.modelService.getModel(model.getResource())); + manager.dispose(); done(); }); From 20a41366eb9f99387eeea5eb2968e96b520eb33f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Wed, 5 Oct 2016 16:14:46 +0200 Subject: [PATCH 073/163] Use register from dispose class --- .../terminal/electron-browser/terminalPanel.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts index 2a1a9853f3d..c1285be607a 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalPanel.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import DOM = require('vs/base/browser/dom'); -import lifecycle = require('vs/base/common/lifecycle'); import nls = require('vs/nls'); import platform = require('vs/base/common/platform'); import { Action, IAction } from 'vs/base/common/actions'; @@ -35,7 +34,6 @@ export class TerminalPanel extends Panel { private _parentDomElement: HTMLElement; private _terminalContainer: HTMLElement; private _themeStyleElement: HTMLElement; - private _toDispose: lifecycle.IDisposable[]; constructor( @IConfigurationService private _configurationService: IConfigurationService, @@ -47,8 +45,6 @@ export class TerminalPanel extends Panel { @ITelemetryService telemetryService: ITelemetryService ) { super(TERMINAL_PANEL_ID, telemetryService); - - this._toDispose = []; } public create(parent: Builder): TPromise { @@ -68,8 +64,8 @@ export class TerminalPanel extends Panel { this._terminalService.setContainers(this.getContainer(), this._terminalContainer); - this._toDispose.push(this._themeService.onDidColorThemeChange(this._updateTheme.bind(this))); - this._toDispose.push(this._configurationService.onDidUpdateConfiguration(this._updateConfig.bind(this))); + this._register(this._themeService.onDidColorThemeChange(this._updateTheme.bind(this))); + this._register(this._configurationService.onDidUpdateConfiguration(this._updateConfig.bind(this))); this._updateTheme(); this._updateConfig(); @@ -111,7 +107,7 @@ export class TerminalPanel extends Panel { this._instantiationService.createInstance(KillTerminalAction, KillTerminalAction.ID, KillTerminalAction.PANEL_LABEL) ]; this._actions.forEach(a => { - this._toDispose.push(a); + this._register(a); }); } return this._actions; @@ -126,7 +122,7 @@ export class TerminalPanel extends Panel { this._instantiationService.createInstance(TerminalPasteAction, TerminalPasteAction.ID, nls.localize('paste', "Paste")) ]; this._contextMenuActions.forEach(a => { - this._toDispose.push(a); + this._register(a); }); } return this._contextMenuActions; @@ -145,7 +141,7 @@ export class TerminalPanel extends Panel { } private _attachEventListeners(): void { - this._toDispose.push(DOM.addDisposableListener(this._parentDomElement, 'mousedown', (event: MouseEvent) => { + this._register(DOM.addDisposableListener(this._parentDomElement, 'mousedown', (event: MouseEvent) => { if (this._terminalService.terminalInstances.length === 0) { return; } @@ -176,7 +172,7 @@ export class TerminalPanel extends Panel { }); } })); - this._toDispose.push(DOM.addDisposableListener(this._parentDomElement, 'click', (event) => { + this._register(DOM.addDisposableListener(this._parentDomElement, 'click', (event) => { if (this._terminalService.terminalInstances.length === 0) { return; } @@ -185,7 +181,7 @@ export class TerminalPanel extends Panel { this._terminalService.getActiveInstance().focus(); } })); - this._toDispose.push(DOM.addDisposableListener(this._parentDomElement, 'keyup', (event: KeyboardEvent) => { + this._register(DOM.addDisposableListener(this._parentDomElement, 'keyup', (event: KeyboardEvent) => { if (event.keyCode === 27) { // Keep terminal open on escape event.stopPropagation(); From 809cef10e5e0125213feb0ed7be099c04cdb1e47 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Wed, 5 Oct 2016 17:31:21 +0200 Subject: [PATCH 074/163] Fixes #11417: Adopt native-keymap@0.3.0 --- npm-shrinkwrap.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 76aace80bf5..0b3fd12858e 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -288,9 +288,9 @@ "resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz" }, "native-keymap": { - "version": "0.2.0", - "from": "native-keymap@0.2.0", - "resolved": "https://registry.npmjs.org/native-keymap/-/native-keymap-0.2.0.tgz" + "version": "0.3.0", + "from": "native-keymap@0.3.0", + "resolved": "https://registry.npmjs.org/native-keymap/-/native-keymap-0.3.0.tgz" }, "normalize-path": { "version": "2.0.1", diff --git a/package.json b/package.json index 7771417ae5d..8ad3c9f600f 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "https-proxy-agent": "0.3.6", "iconv-lite": "0.4.13", "minimist": "1.2.0", - "native-keymap": "0.2.0", + "native-keymap": "0.3.0", "pty.js": "https://github.com/Tyriar/pty.js/tarball/fffbf86eb9e8051b5b2be4ba9c7b07faa018ce8d", "semver": "4.3.6", "vscode-debugprotocol": "1.13.0", From 742fb52847702adeff0d6f1603d32c02c90b1ba7 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Tue, 4 Oct 2016 08:35:15 -0700 Subject: [PATCH 075/163] Fit watermark into code org (fixes #13069) --- src/vs/test/utils/servicesTestUtils.ts | 4 + .../workbench/electron-browser/workbench.ts | 13 ++- .../watermark/{ => browser}/watermark.css | 0 .../parts/watermark/browser/watermark.ts | 101 ++++++++++++++++++ src/vs/workbench/parts/watermark/watermark.ts | 62 ----------- .../services/part/common/partService.ts | 5 + src/vs/workbench/workbench.main.ts | 2 + 7 files changed, 118 insertions(+), 69 deletions(-) rename src/vs/workbench/parts/watermark/{ => browser}/watermark.css (100%) create mode 100644 src/vs/workbench/parts/watermark/browser/watermark.ts delete mode 100644 src/vs/workbench/parts/watermark/watermark.ts diff --git a/src/vs/test/utils/servicesTestUtils.ts b/src/vs/test/utils/servicesTestUtils.ts index 61bebb26e11..b39619fe14e 100644 --- a/src/vs/test/utils/servicesTestUtils.ts +++ b/src/vs/test/utils/servicesTestUtils.ts @@ -230,6 +230,10 @@ export class TestPartService implements IPartService { return true; } + public getContainer(part): HTMLElement { + return null; + } + public isStatusBarHidden(): boolean { return false; } diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 6832aa0ba59..312f5568829 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -74,7 +74,6 @@ import {MenuService} from 'vs/platform/actions/common/menuService'; import {IContextMenuService} from 'vs/platform/contextview/browser/contextView'; import {IEnvironmentService} from 'vs/platform/environment/common/environment'; import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; -import * as watermark from 'vs/workbench/parts/watermark/watermark'; export const MessagesVisibleContext = new RawContextKey('globalMessageVisible', false); export const EditorsVisibleContext = new RawContextKey('editorIsOpen', false); @@ -470,6 +469,11 @@ export class Workbench implements IPartService { return false; } + const container = this.getContainer(part); + return DOM.isAncestor(activeElement, container); + } + + public getContainer(part: Parts): HTMLElement { let container: Builder = null; switch (part) { case Parts.ACTIVITYBAR_PART: @@ -488,8 +492,7 @@ export class Workbench implements IPartService { container = this.statusbarPart.getContainer(); break; } - - return DOM.isAncestor(activeElement, container.getHTMLElement()); + return container && container.getHTMLElement(); } public isVisible(part: Parts): boolean { @@ -783,10 +786,6 @@ export class Workbench implements IPartService { role: 'main' }); - if (this.telemetryService.getExperiments().showCommandsWatermark) { - this.toDispose.push(watermark.create(editorContainer, this.keybindingService)); - } - this.editorPart.create(editorContainer); } diff --git a/src/vs/workbench/parts/watermark/watermark.css b/src/vs/workbench/parts/watermark/browser/watermark.css similarity index 100% rename from src/vs/workbench/parts/watermark/watermark.css rename to src/vs/workbench/parts/watermark/browser/watermark.css diff --git a/src/vs/workbench/parts/watermark/browser/watermark.ts b/src/vs/workbench/parts/watermark/browser/watermark.ts new file mode 100644 index 00000000000..337dea4b52d --- /dev/null +++ b/src/vs/workbench/parts/watermark/browser/watermark.ts @@ -0,0 +1,101 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import 'vs/css!./watermark'; +import { $ } from 'vs/base/browser/builder'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import * as nls from 'vs/nls'; +import { Parts, IPartService } from 'vs/workbench/services/part/common/partService'; +import { Registry } from 'vs/platform/platform'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; + +const entries = [ + { + text: nls.localize('watermark.showCommands', "Command Palette"), + ids: ['workbench.action.showCommands'] + }, + { + text: nls.localize('watermark.quickOpen', "Go to File"), + ids: ['workbench.action.quickOpen'] + }, + { + text: nls.localize('watermark.moveLines', "Move Lines Up/Down"), + ids: ['editor.action.moveLinesUpAction', 'editor.action.moveLinesDownAction'] + }, + { + text: nls.localize('watermark.addCursor', "Add Cursors Above/Below"), + ids: ['editor.action.insertCursorAbove', 'editor.action.insertCursorBelow'] + }, + { + text: nls.localize('watermark.toggleTerminal', "Toggle Terminal"), + ids: ['workbench.action.terminal.toggleTerminal'] + }, +]; + +const UNBOUND = nls.localize('watermark.unboundCommand', "unbound"); + +export class WatermarkContribution implements IWorkbenchContribution { + + private toDispose: IDisposable[] = []; + + constructor( + @ILifecycleService lifecycleService: ILifecycleService, + @IPartService private partService: IPartService, + @IKeybindingService private keybindingService: IKeybindingService, + @ITelemetryService telemetryService: ITelemetryService + ) { + if (telemetryService.getExperiments().showCommandsWatermark) { + lifecycleService.onShutdown(this.dispose, this); + this.partService.joinCreation().then(() => { + this.create(); + }); + } + } + + public getId() { + return 'vs.watermark'; + } + + private create(): void { + const container = this.partService.getContainer(Parts.EDITOR_PART); + const watermark = $() + .div({ 'class': 'watermark' }); + const box = $(watermark) + .div({ 'class': 'watermark-box' }); + const update = () => { + const builder = $(box); + builder.clearChildren(); + entries.map(entry => { + builder.element('dl', {}, dl => { + dl.element('dt', {}, dt => dt.text(entry.text)); + dl.element('dd', {}, dd => dd.innerHtml( + entry.ids + .map(id => this.keybindingService.lookupKeybindings(id).slice(0, 1) + .map(k => `${this.keybindingService.getLabelFor(k)}`) + .join('') || UNBOUND) + .join(' / ') + )); + }); + }); + }; + update(); + watermark.build(container, 0); + $(container) + .addClass('has-watermark'); + this.toDispose.push(this.keybindingService.onDidUpdateKeybindings(update)); + } + + public dispose(): void { + this.toDispose = dispose(this.toDispose); + } +} + +Registry.as(WorkbenchExtensions.Workbench) + .registerWorkbenchContribution(WatermarkContribution); diff --git a/src/vs/workbench/parts/watermark/watermark.ts b/src/vs/workbench/parts/watermark/watermark.ts deleted file mode 100644 index 3edbb99419c..00000000000 --- a/src/vs/workbench/parts/watermark/watermark.ts +++ /dev/null @@ -1,62 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import 'vs/css!./watermark'; -import {Builder, $} from 'vs/base/browser/builder'; -import {IDisposable} from 'vs/base/common/lifecycle'; -import {IKeybindingService} from 'vs/platform/keybinding/common/keybinding'; -import * as nls from 'vs/nls'; - -const entries = [ - { - text: nls.localize('watermark.showCommands', "Command Palette"), - ids: ['workbench.action.showCommands'] - }, - { - text: nls.localize('watermark.quickOpen', "Go to File"), - ids: ['workbench.action.quickOpen'] - }, - { - text: nls.localize('watermark.moveLines', "Move Lines Up/Down"), - ids: ['editor.action.moveLinesUpAction', 'editor.action.moveLinesDownAction'] - }, - { - text: nls.localize('watermark.addCursor', "Add Cursors Above/Below"), - ids: ['editor.action.insertCursorAbove', 'editor.action.insertCursorBelow'] - }, - { - text: nls.localize('watermark.toggleTerminal', "Toggle Terminal"), - ids: ['workbench.action.terminal.toggleTerminal'] - }, -]; - -const UNBOUND = nls.localize('watermark.unboundCommand', "unbound"); - -export function create(container: Builder, keybindingService: IKeybindingService): IDisposable { - const watermark = $(container) - .addClass('has-watermark') - .div({ 'class': 'watermark' }); - const box = $(watermark) - .div({ 'class': 'watermark-box' }); - function update() { - const builder = $(box); - builder.clearChildren(); - entries.map(entry => { - builder.element('dl', {}, dl => { - dl.element('dt', {}, dt => dt.text(entry.text)); - dl.element('dd', {}, dd => dd.innerHtml( - entry.ids - .map(id => keybindingService.lookupKeybindings(id).slice(0, 1) - .map(k => `${keybindingService.getLabelFor(k)}`) - .join('') || UNBOUND) - .join(' / ') - )); - }); - }); - } - update(); - return keybindingService.onDidUpdateKeybindings(update); -} diff --git a/src/vs/workbench/services/part/common/partService.ts b/src/vs/workbench/services/part/common/partService.ts index aacd8950c57..4c935db776c 100644 --- a/src/vs/workbench/services/part/common/partService.ts +++ b/src/vs/workbench/services/part/common/partService.ts @@ -45,6 +45,11 @@ export interface IPartService { */ hasFocus(part: Parts): boolean; + /** + * Returns the parts HTML element, if there is one. + */ + getContainer(part: Parts): HTMLElement; + /** * Returns iff the part is visible. */ diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index b7198436d14..8c5d2b08734 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -93,3 +93,5 @@ import 'vs/workbench/electron-browser/main.contribution'; import 'vs/workbench/electron-browser/main'; import 'vs/workbench/parts/themes/test/electron-browser/themes.test.contribution'; + +import 'vs/workbench/parts/watermark/browser/watermark'; \ No newline at end of file From 61328fd66c7bff7aad4e61f37e18373569c19768 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 5 Oct 2016 19:28:16 +0200 Subject: [PATCH 076/163] =?UTF-8?q?=F0=9F=92=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/vs/platform/editor/common/editor.ts | 3 ++- src/vs/workbench/api/node/mainThreadDocuments.ts | 4 ++++ .../workbench/parts/files/browser/editors/textFileEditor.ts | 6 ++---- src/vs/workbench/services/editor/browser/editorService.ts | 3 ++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index 9b7cc2e9f5e..389538ef883 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -8,6 +8,7 @@ import URI from 'vs/base/common/uri'; import {TPromise} from 'vs/base/common/winjs.base'; import {createDecorator} from 'vs/platform/instantiation/common/instantiation'; import Event from 'vs/base/common/event'; +import {IDisposable} from 'vs/base/common/lifecycle'; export const IEditorService = createDecorator('editorService'); @@ -127,7 +128,7 @@ export enum Direction { RIGHT } -export interface IEditorInput { +export interface IEditorInput extends IDisposable { onDispose: Event; diff --git a/src/vs/workbench/api/node/mainThreadDocuments.ts b/src/vs/workbench/api/node/mainThreadDocuments.ts index c106c5e4073..ecd9ee3ebf0 100644 --- a/src/vs/workbench/api/node/mainThreadDocuments.ts +++ b/src/vs/workbench/api/node/mainThreadDocuments.ts @@ -252,6 +252,10 @@ export class MainThreadDocuments extends MainThreadDocumentsShape { if (!this._editorService.isVisible(input, true)) { toBeDisposed.push(resource); } + + if (input) { + input.dispose(); + } }); })).then(() => { for (let resource of toBeDisposed) { diff --git a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts index d4faecd8ab5..d111e897e38 100644 --- a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts @@ -199,10 +199,8 @@ export class TextFileEditor extends BaseTextEditor { } private openAsBinary(input: FileEditorInput, options: EditorOptions): void { - const fileInputBinary = this.instantiationService.createInstance(FileEditorInput, input.getResource(), void 0); - fileInputBinary.setForceOpenAsBinary(); - - this.editorService.openEditor(fileInputBinary, options, this.position).done(null, errors.onUnexpectedError); + input.setForceOpenAsBinary(); + this.editorService.openEditor(input, options, this.position).done(null, errors.onUnexpectedError); } private openAsFolder(input: FileEditorInput): boolean { diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index bfbbbeaaa1c..37021f28a3d 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -69,7 +69,7 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { return false; } - return this.getVisibleEditors().some((editor) => { + return this.getVisibleEditors().some(editor => { if (!editor.input) { return false; } @@ -107,6 +107,7 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { const schema = resourceInput.resource.scheme; if (schema === network.Schemas.http || schema === network.Schemas.https) { window.open(resourceInput.resource.toString(true)); + return TPromise.as(null); } } From 600f599f66fb68aedfb4033db9886025a1b64b39 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Wed, 5 Oct 2016 15:48:58 -0700 Subject: [PATCH 077/163] Prevent cached promise from being canceled (fixes #11181) --- .../services/search/node/rawSearchService.ts | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index 67b74010cfa..ab5eb0ffd3e 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -95,7 +95,7 @@ export class SearchService implements IRawSearchService { private doSortedSearch(engine: ISearchEngine, config: IRawSearch): PPromise<[ISerializedSearchComplete, IRawFileMatch[]], IProgress> { let searchPromise: PPromise>; - const allResultsPromise = new PPromise<[ISerializedSearchComplete, IRawFileMatch[]], IProgress>((c, e, p) => { + let allResultsPromise = new PPromise<[ISerializedSearchComplete, IRawFileMatch[]], IProgress>((c, e, p) => { let results: IRawFileMatch[] = []; searchPromise = this.doSearch(engine, -1) .then(result => { @@ -108,9 +108,7 @@ export class SearchService implements IRawSearchService { } }); }, () => { - if (!config.cacheKey) { // preserve cached promise - searchPromise.cancel(); - } + searchPromise.cancel(); }); let cache: Cache; @@ -120,6 +118,7 @@ export class SearchService implements IRawSearchService { allResultsPromise.then(null, err => { delete cache.resultsToSearchCache[config.filePattern]; }); + allResultsPromise = this.preventCancellation(allResultsPromise); } return new PPromise<[ISerializedSearchComplete, IRawFileMatch[]], IProgress>((c, e, p) => { @@ -227,7 +226,7 @@ export class SearchService implements IRawSearchService { continue; // since a path character widens the search for potential more matches, require it in previous search too } - cached = cache.resultsToSearchCache[previousSearch]; + cached = this.preventCancellation(cache.resultsToSearchCache[previousSearch]); break; } } @@ -303,6 +302,17 @@ export class SearchService implements IRawSearchService { delete this.caches[cacheKey]; return TPromise.as(undefined); } + + private preventCancellation(promise: PPromise): PPromise { + return new PPromise((c, e, p) => { + // Allow for piled up cancellations to come through first. + process.nextTick(() => { + promise.then(c, e, p); + }); + }, () => { + // Do not propagate. + }); + } } class Cache { From 760b880ee486359ef1aa0e398d5056c6055d87f0 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 5 Oct 2016 15:59:55 -0700 Subject: [PATCH 078/163] Fix indentation in commands namespace API --- src/vs/vscode.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index b9d953a9f0c..f015f8be8db 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -3285,7 +3285,7 @@ declare namespace vscode { * ```json * { * "contributes": { - * "commands": [{ + * "commands": [{ * "command": "extension.sayHello", * "title": "Hello World" * }] From beeb7f20238cee1ed26e3fff3a0af838c0fe074b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 6 Oct 2016 08:18:17 +0200 Subject: [PATCH 079/163] less use of IEnvService --- .../code/electron-main/auto-updater.linux.ts | 5 +- .../code/electron-main/auto-updater.win32.ts | 7 ++- src/vs/code/electron-main/env.ts | 9 +--- src/vs/code/electron-main/main.ts | 7 +-- src/vs/code/electron-main/menus.ts | 48 +++++++++---------- src/vs/code/electron-main/update-manager.ts | 9 ++-- src/vs/code/electron-main/window.ts | 3 +- src/vs/code/electron-main/windows.ts | 7 +-- 8 files changed, 44 insertions(+), 51 deletions(-) diff --git a/src/vs/code/electron-main/auto-updater.linux.ts b/src/vs/code/electron-main/auto-updater.linux.ts index 2683601c524..240c303bbfb 100644 --- a/src/vs/code/electron-main/auto-updater.linux.ts +++ b/src/vs/code/electron-main/auto-updater.linux.ts @@ -9,8 +9,8 @@ import { EventEmitter } from 'events'; import { isString } from 'vs/base/common/types'; import { Promise } from 'vs/base/common/winjs.base'; import { asJson } from 'vs/base/node/request'; -import { IEnvService } from 'vs/code/electron-main/env'; import { IRequestService } from 'vs/platform/request/common/request'; +import product from 'vs/platform/product'; export interface IUpdate { url: string; @@ -25,7 +25,6 @@ export class LinuxAutoUpdaterImpl extends EventEmitter { private currentRequest: Promise; constructor( - @IEnvService private envService: IEnvService, @IRequestService private requestService: IRequestService ) { super(); @@ -55,7 +54,7 @@ export class LinuxAutoUpdaterImpl extends EventEmitter { if (!update || !update.url || !update.version) { this.emit('update-not-available'); } else { - this.emit('update-available', null, this.envService.product.downloadUrl, update.version); + this.emit('update-available', null, product.downloadUrl, update.version); } }) .then(null, e => { diff --git a/src/vs/code/electron-main/auto-updater.win32.ts b/src/vs/code/electron-main/auto-updater.win32.ts index a32e78e0504..6eb5933565e 100644 --- a/src/vs/code/electron-main/auto-updater.win32.ts +++ b/src/vs/code/electron-main/auto-updater.win32.ts @@ -16,8 +16,8 @@ import { isString } from 'vs/base/common/types'; import { Promise, TPromise } from 'vs/base/common/winjs.base'; import { download, asJson } from 'vs/base/node/request'; import { ILifecycleService } from 'vs/code/electron-main/lifecycle'; -import { IEnvService } from 'vs/code/electron-main/env'; import { IRequestService } from 'vs/platform/request/common/request'; +import product from 'vs/platform/product'; export interface IUpdate { url: string; @@ -34,7 +34,6 @@ export class Win32AutoUpdaterImpl extends EventEmitter { constructor( @ILifecycleService private lifecycleService: ILifecycleService, - @IEnvService private envService: IEnvService, @IRequestService private requestService: IRequestService ) { super(); @@ -114,7 +113,7 @@ export class Win32AutoUpdaterImpl extends EventEmitter { } private getUpdatePackagePath(version: string): TPromise { - return this.cachePath.then(cachePath => path.join(cachePath, `CodeSetup-${this.envService.quality}-${version}.exe`)); + return this.cachePath.then(cachePath => path.join(cachePath, `CodeSetup-${product.quality}-${version}.exe`)); } private quitAndUpdate(updatePackagePath: string): void { @@ -131,7 +130,7 @@ export class Win32AutoUpdaterImpl extends EventEmitter { } private cleanup(exceptVersion: string = null): Promise { - const filter = exceptVersion ? one => !(new RegExp(`${this.envService.quality}-${exceptVersion}\\.exe$`).test(one)) : () => true; + const filter = exceptVersion ? one => !(new RegExp(`${product.quality}-${exceptVersion}\\.exe$`).test(one)) : () => true; return this.cachePath .then(cachePath => pfs.readdir(cachePath) diff --git a/src/vs/code/electron-main/env.ts b/src/vs/code/electron-main/env.ts index 650f23f5246..41c2546ea2f 100644 --- a/src/vs/code/electron-main/env.ts +++ b/src/vs/code/electron-main/env.ts @@ -16,8 +16,8 @@ import * as platform from 'vs/base/common/platform'; import URI from 'vs/base/common/uri'; import * as types from 'vs/base/common/types'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import product, { IProductConfiguration } from 'vs/platform/product'; import { parseArgs, ParsedArgs } from 'vs/platform/environment/node/argv'; +import product from 'vs/platform/product'; export interface IProcessEnvironment { [key: string]: string; @@ -33,9 +33,6 @@ export interface IEnvService { _serviceBrand: any; cliArgs: ICommandLineArguments; isBuilt: boolean; - product: IProductConfiguration; - updateUrl: string; - quality: string; userHome: string; appRoot: string; currentWorkingDirectory: string; @@ -57,10 +54,6 @@ export class EnvService implements IEnvService { get isBuilt(): boolean { return !process.env['VSCODE_DEV']; } - get product(): IProductConfiguration { return product; } - get updateUrl(): string { return product.updateUrl; } - get quality(): string { return product.quality; } - private _userHome: string; get userHome(): string { return this._userHome; } diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index ed962e2cee3..630046fca2e 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -43,6 +43,7 @@ import { getPathLabel } from 'vs/base/common/labels'; import { IURLService } from 'vs/platform/url/common/url'; import { URLChannel } from 'vs/platform/url/common/urlIpc'; import { URLService } from 'vs/platform/url/electron-main/urlService'; +import product from 'vs/platform/product'; import * as fs from 'original-fs'; import * as cp from 'child_process'; @@ -108,7 +109,7 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: IProce let windowsMutex: Mutex = null; try { const Mutex = (require.__$__nodeRequire('windows-mutex')).Mutex; - windowsMutex = new Mutex(envService.product.win32MutexName); + windowsMutex = new Mutex(product.win32MutexName); } catch (e) { // noop } @@ -150,8 +151,8 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: IProce // This will help Windows to associate the running program with // any shortcut that is pinned to the taskbar and prevent showing // two icons in the taskbar for the same app. - if (platform.isWindows && envService.product.win32AppUserModelId) { - app.setAppUserModelId(envService.product.win32AppUserModelId); + if (platform.isWindows && product.win32AppUserModelId) { + app.setAppUserModelId(product.win32AppUserModelId); } function dispose() { diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index aa0d07a1e46..9a342ae550b 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -172,7 +172,7 @@ export class VSCodeMenu { let macApplicationMenuItem: Electron.MenuItem; if (platform.isMacintosh) { const applicationMenu = new Menu(); - macApplicationMenuItem = new MenuItem({ label: this.envService.product.nameShort, submenu: applicationMenu }); + macApplicationMenuItem = new MenuItem({ label: product.nameShort, submenu: applicationMenu }); this.setMacApplicationMenu(applicationMenu); } @@ -239,13 +239,13 @@ export class VSCodeMenu { } private setMacApplicationMenu(macApplicationMenu: Electron.Menu): void { - const about = new MenuItem({ label: nls.localize('mAbout', "About {0}", this.envService.product.nameLong), role: 'about' }); + const about = new MenuItem({ label: nls.localize('mAbout', "About {0}", product.nameLong), role: 'about' }); const checkForUpdates = this.getUpdateMenuItems(); const preferences = this.getPreferencesMenu(); - const hide = new MenuItem({ label: nls.localize('mHide', "Hide {0}", this.envService.product.nameLong), role: 'hide', accelerator: 'Command+H' }); + const hide = new MenuItem({ label: nls.localize('mHide', "Hide {0}", product.nameLong), role: 'hide', accelerator: 'Command+H' }); const hideOthers = new MenuItem({ label: nls.localize('mHideOthers', "Hide Others"), role: 'hideothers', accelerator: 'Command+Alt+H' }); const showAll = new MenuItem({ label: nls.localize('mShowAll', "Show All"), role: 'unhide' }); - const quit = new MenuItem({ label: nls.localize('miQuit', "Quit {0}", this.envService.product.nameLong), click: () => this.quit(), accelerator: 'Command+Q' }); + const quit = new MenuItem({ label: nls.localize('miQuit', "Quit {0}", product.nameLong), click: () => this.quit(), accelerator: 'Command+Q' }); const actions = [about]; actions.push(...checkForUpdates); @@ -632,7 +632,7 @@ export class VSCodeMenu { }); let reportIssuesItem: Electron.MenuItem = null; - if (this.envService.product.reportIssueUrl) { + if (product.reportIssueUrl) { const label = nls.localize({ key: 'miReportIssues', comment: ['&& denotes a mnemonic'] }, "Report &&Issues"); if (this.windowsService.getWindowCount() > 0) { @@ -643,34 +643,34 @@ export class VSCodeMenu { } arrays.coalesce([ - this.envService.product.documentationUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.openUrl(this.envService.product.documentationUrl, 'openDocumentationUrl') }) : null, - this.envService.product.releaseNotesUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'update.showCurrentReleaseNotes') }) : null, - (this.envService.product.documentationUrl || this.envService.product.releaseNotesUrl) ? __separator__() : null, - this.envService.product.twitterUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join us on Twitter")), click: () => this.openUrl(this.envService.product.twitterUrl, 'openTwitterUrl') }) : null, - this.envService.product.requestFeatureUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests")), click: () => this.openUrl(this.envService.product.requestFeatureUrl, 'openUserVoiceUrl') }) : null, + product.documentationUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.openUrl(product.documentationUrl, 'openDocumentationUrl') }) : null, + product.releaseNotesUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.windowsService.sendToFocused('vscode:runAction', 'update.showCurrentReleaseNotes') }) : null, + (product.documentationUrl || product.releaseNotesUrl) ? __separator__() : null, + product.twitterUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join us on Twitter")), click: () => this.openUrl(product.twitterUrl, 'openTwitterUrl') }) : null, + product.requestFeatureUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests")), click: () => this.openUrl(product.requestFeatureUrl, 'openUserVoiceUrl') }) : null, reportIssuesItem, - (this.envService.product.twitterUrl || this.envService.product.requestFeatureUrl || this.envService.product.reportIssueUrl) ? __separator__() : null, - this.envService.product.licenseUrl ? new MenuItem({ + (product.twitterUrl || product.requestFeatureUrl || product.reportIssueUrl) ? __separator__() : null, + product.licenseUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "&&View License")), click: () => { if (platform.language) { - const queryArgChar = this.envService.product.licenseUrl.indexOf('?') > 0 ? '&' : '?'; - this.openUrl(`${this.envService.product.licenseUrl}${queryArgChar}lang=${platform.language}`, 'openLicenseUrl'); + const queryArgChar = product.licenseUrl.indexOf('?') > 0 ? '&' : '?'; + this.openUrl(`${product.licenseUrl}${queryArgChar}lang=${platform.language}`, 'openLicenseUrl'); } else { - this.openUrl(this.envService.product.licenseUrl, 'openLicenseUrl'); + this.openUrl(product.licenseUrl, 'openLicenseUrl'); } } }) : null, - this.envService.product.privacyStatementUrl ? new MenuItem({ + product.privacyStatementUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "&&Privacy Statement")), click: () => { if (platform.language) { - const queryArgChar = this.envService.product.licenseUrl.indexOf('?') > 0 ? '&' : '?'; - this.openUrl(`${this.envService.product.privacyStatementUrl}${queryArgChar}lang=${platform.language}`, 'openPrivacyStatement'); + const queryArgChar = product.licenseUrl.indexOf('?') > 0 ? '&' : '?'; + this.openUrl(`${product.privacyStatementUrl}${queryArgChar}lang=${platform.language}`, 'openPrivacyStatement'); } else { - this.openUrl(this.envService.product.privacyStatementUrl, 'openPrivacyStatement'); + this.openUrl(product.privacyStatementUrl, 'openPrivacyStatement'); } } }) : null, - (this.envService.product.licenseUrl || this.envService.product.privacyStatementUrl) ? __separator__() : null, + (product.licenseUrl || product.privacyStatementUrl) ? __separator__() : null, toggleDevToolsItem, platform.isWindows && product.quality !== 'stable' ? showAccessibilityOptions : null ]).forEach((item) => helpMenu.append(item)); @@ -797,14 +797,14 @@ export class VSCodeMenu { const lastActiveWindow = this.windowsService.getFocusedWindow() || this.windowsService.getLastActiveWindow(); dialog.showMessageBox(lastActiveWindow && lastActiveWindow.win, { - title: this.envService.product.nameLong, + title: product.nameLong, type: 'info', - message: this.envService.product.nameLong, + message: product.nameLong, detail: nls.localize('aboutDetail', "\nVersion {0}\nCommit {1}\nDate {2}\nShell {3}\nRenderer {4}\nNode {5}", app.getVersion(), - this.envService.product.commit || 'Unknown', - this.envService.product.date || 'Unknown', + product.commit || 'Unknown', + product.date || 'Unknown', process.versions['electron'], process.versions['chrome'], process.versions['node'] diff --git a/src/vs/code/electron-main/update-manager.ts b/src/vs/code/electron-main/update-manager.ts index 5763c6561ed..36cb3fa03e7 100644 --- a/src/vs/code/electron-main/update-manager.ts +++ b/src/vs/code/electron-main/update-manager.ts @@ -9,13 +9,13 @@ import * as fs from 'original-fs'; import * as path from 'path'; import * as electron from 'electron'; import { EventEmitter } from 'events'; -import { IEnvService } from 'vs/code/electron-main/env'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Win32AutoUpdaterImpl } from 'vs/code/electron-main/auto-updater.win32'; import { LinuxAutoUpdaterImpl } from 'vs/code/electron-main/auto-updater.linux'; import { ILifecycleService } from 'vs/code/electron-main/lifecycle'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IRequestService } from 'vs/platform/request/common/request'; +import product from 'vs/platform/product'; export enum State { Uninitialized, @@ -71,7 +71,6 @@ export class UpdateManager extends EventEmitter implements IUpdateService { constructor( @IInstantiationService instantiationService: IInstantiationService, @ILifecycleService private lifecycleService: ILifecycleService, - @IEnvService private envService: IEnvService, @IConfigurationService private configurationService: IConfigurationService, @IRequestService requestService: IRequestService ) { @@ -234,7 +233,7 @@ export class UpdateManager extends EventEmitter implements IUpdateService { const config = this.configurationService.getConfiguration<{ channel: string; }>('update'); const channel = config && config.channel; - return channel === 'none' ? null : this.envService.quality; + return channel === 'none' ? null : product.quality; } private getUpdateFeedUrl(channel: string): string { @@ -246,12 +245,12 @@ export class UpdateManager extends EventEmitter implements IUpdateService { return null; } - if (!this.envService.updateUrl || !this.envService.product.commit) { + if (!product.updateUrl || !product.commit) { return null; } const platform = process.platform === 'linux' ? `linux-${process.arch}` : process.platform; - return `${ this.envService.updateUrl }/api/update/${ platform }/${ channel }/${ this.envService.product.commit }`; + return `${ product.updateUrl }/api/update/${ platform }/${ channel }/${ product.commit }`; } } diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 70ac020d5ed..13ccfc249e2 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -15,6 +15,7 @@ import { ICommandLineArguments, IEnvService, IProcessEnvironment } from 'vs/code import { ILogService } from 'vs/code/electron-main/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { parseArgs } from 'vs/platform/environment/node/argv'; +import product from 'vs/platform/product'; export interface IWindowState { width?: number; @@ -165,7 +166,7 @@ export class VSCodeWindow { minWidth: VSCodeWindow.MIN_WIDTH, minHeight: VSCodeWindow.MIN_HEIGHT, show: !isFullscreenOrMaximized, - title: this.envService.product.nameLong, + title: product.nameLong, webPreferences: { 'backgroundThrottling': false // by default if Code is in the background, intervals and timeouts get throttled } diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 8a9a050ed07..5534b35fd91 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -25,6 +25,7 @@ import { ILogService } from 'vs/code/electron-main/log'; import { IWindowEventService } from 'vs/code/common/windows'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import CommonEvent, { Emitter } from 'vs/base/common/event'; +import product from 'vs/platform/product'; const EventTypes = { OPEN: 'open', @@ -561,7 +562,7 @@ export class WindowsManager implements IWindowsService { // Warn if the requested path to open does not exist if (!iPath) { const options: Electron.ShowMessageBoxOptions = { - title: this.envService.product.nameLong, + title: product.nameLong, type: 'info', buttons: [nls.localize('ok', "OK")], message: nls.localize('pathNotExistTitle', "Path does not exist"), @@ -1262,7 +1263,7 @@ export class WindowsManager implements IWindowsService { // Unresponsive if (error === WindowError.UNRESPONSIVE) { dialog.showMessageBox(vscodeWindow.win, { - title: this.envService.product.nameLong, + title: product.nameLong, type: 'warning', buttons: [nls.localize('reopen', "Reopen"), nls.localize('wait', "Keep Waiting"), nls.localize('close', "Close")], message: nls.localize('appStalled', "The window is no longer responding"), @@ -1281,7 +1282,7 @@ export class WindowsManager implements IWindowsService { // Crashed else { dialog.showMessageBox(vscodeWindow.win, { - title: this.envService.product.nameLong, + title: product.nameLong, type: 'warning', buttons: [nls.localize('reopen', "Reopen"), nls.localize('close', "Close")], message: nls.localize('appCrashed', "The window has crashed"), From 05334aeaa32e70f92b2950f1fe18cf5c95dcb38d Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 6 Oct 2016 08:46:53 +0200 Subject: [PATCH 080/163] more use of IEnvironmentService (for #10656) --- src/vs/code/electron-main/env.ts | 53 ++----------------- src/vs/code/electron-main/lifecycle.ts | 6 +-- src/vs/code/electron-main/log.ts | 8 ++- src/vs/code/electron-main/main.ts | 6 +-- src/vs/code/electron-main/storage.ts | 10 ++-- src/vs/code/electron-main/window.ts | 11 ++-- src/vs/code/electron-main/windows.ts | 4 +- .../environment/common/environment.ts | 1 + .../environment/node/environmentService.ts | 1 + 9 files changed, 29 insertions(+), 71 deletions(-) diff --git a/src/vs/code/electron-main/env.ts b/src/vs/code/electron-main/env.ts index 41c2546ea2f..e038bd5c30c 100644 --- a/src/vs/code/electron-main/env.ts +++ b/src/vs/code/electron-main/env.ts @@ -7,17 +7,13 @@ import * as fs from 'original-fs'; import * as path from 'path'; -import * as os from 'os'; -import { app } from 'electron'; import * as arrays from 'vs/base/common/arrays'; import * as strings from 'vs/base/common/strings'; import * as paths from 'vs/base/common/paths'; import * as platform from 'vs/base/common/platform'; -import URI from 'vs/base/common/uri'; import * as types from 'vs/base/common/types'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { parseArgs, ParsedArgs } from 'vs/platform/environment/node/argv'; -import product from 'vs/platform/product'; export interface IProcessEnvironment { [key: string]: string; @@ -32,14 +28,6 @@ export const IEnvService = createDecorator('mainEnvironmentService' export interface IEnvService { _serviceBrand: any; cliArgs: ICommandLineArguments; - isBuilt: boolean; - userHome: string; - appRoot: string; - currentWorkingDirectory: string; - appHome: string; - appSettingsHome: string; - appSettingsPath: string; - appKeybindingsPath: string; } export class EnvService implements IEnvService { @@ -49,45 +37,14 @@ export class EnvService implements IEnvService { private _cliArgs: ICommandLineArguments; get cliArgs(): ICommandLineArguments { return this._cliArgs; } - private _userExtensionsHome: string; - get userExtensionsHome(): string { return this._userExtensionsHome; } - - get isBuilt(): boolean { return !process.env['VSCODE_DEV']; } - - private _userHome: string; - get userHome(): string { return this._userHome; } - - private _appRoot: string; - get appRoot(): string { return this._appRoot; } - - private _currentWorkingDirectory: string; - get currentWorkingDirectory(): string { return this._currentWorkingDirectory; } - - private _appHome: string; - get appHome(): string { return this._appHome; } - - private _appSettingsHome: string; - get appSettingsHome(): string { return this._appSettingsHome; } - - private _appSettingsPath: string; - get appSettingsPath(): string { return this._appSettingsPath; } - - private _appKeybindingsPath: string; - get appKeybindingsPath(): string { return this._appKeybindingsPath; } - constructor() { - this._appRoot = path.dirname(URI.parse(require.toUrl('')).fsPath); - this._currentWorkingDirectory = process.env['VSCODE_CWD'] || process.cwd(); - this._appHome = app.getPath('userData'); - this._appSettingsHome = path.join(this._appHome, 'User'); - this._appSettingsPath = path.join(this._appSettingsHome, 'settings.json'); - this._appKeybindingsPath = path.join(this._appSettingsHome, 'keybindings.json'); // Remove the Electron executable const [, ...args] = process.argv; // If dev, remove the first non-option argument: it's the app location - if (!this.isBuilt) { + const isBuilt = !process.env['VSCODE_DEV']; + if (!isBuilt) { const index = arrays.firstIndex(args, a => !/^-/.test(a)); if (index > -1) { @@ -96,7 +53,8 @@ export class EnvService implements IEnvService { } const argv = parseArgs(args); - const paths = parsePathArguments(this._currentWorkingDirectory, argv._, argv.goto); + const cwd = process.env['VSCODE_CWD'] || process.cwd(); + const paths = parsePathArguments(cwd, argv._, argv.goto); this._cliArgs = Object.freeze({ _: [], @@ -118,9 +76,6 @@ export class EnvService implements IEnvService { locale: argv.locale, wait: argv.wait }); - - this._userHome = path.join(os.homedir(), product.dataFolderName); - this._userExtensionsHome = this.cliArgs.extensionHomePath || path.join(this._userHome, 'extensions'); } } diff --git a/src/vs/code/electron-main/lifecycle.ts b/src/vs/code/electron-main/lifecycle.ts index 66f3e5aae83..ec6bbb74702 100644 --- a/src/vs/code/electron-main/lifecycle.ts +++ b/src/vs/code/electron-main/lifecycle.ts @@ -9,7 +9,7 @@ import { EventEmitter } from 'events'; import { ipcMain as ipc, app } from 'electron'; import { TPromise, TValueCallback } from 'vs/base/common/winjs.base'; import { ReadyState, VSCodeWindow } from 'vs/code/electron-main/window'; -import { IEnvService } from 'vs/code/electron-main/env'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/code/electron-main/log'; import { IStorageService } from 'vs/code/electron-main/storage'; @@ -50,7 +50,7 @@ export class LifecycleService implements ILifecycleService { private _wasUpdated: boolean; constructor( - @IEnvService private envService: IEnvService, + @IEnvironmentService private environmentService: IEnvironmentService, @ILogService private logService: ILogService, @IStorageService private storageService: IStorageService ) { @@ -109,7 +109,7 @@ export class LifecycleService implements ILifecycleService { // Windows/Linux: we quit when all windows have closed // Mac: we only quit when quit was requested // --wait: we quit when all windows are closed - if (this.quitRequested || process.platform !== 'darwin' || this.envService.cliArgs.wait) { + if (this.quitRequested || process.platform !== 'darwin' || this.environmentService.wait) { app.quit(); } }); diff --git a/src/vs/code/electron-main/log.ts b/src/vs/code/electron-main/log.ts index 352363d63ca..27285dccdd3 100644 --- a/src/vs/code/electron-main/log.ts +++ b/src/vs/code/electron-main/log.ts @@ -6,7 +6,7 @@ 'use strict'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IEnvService } from 'vs/code/electron-main/env'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; export const ILogService = createDecorator('logService'); @@ -19,13 +19,11 @@ export class MainLogService implements ILogService { _serviceBrand: any; - constructor(@IEnvService private envService: IEnvService) { + constructor(@IEnvironmentService private environmentService: IEnvironmentService) { } log(...args: any[]): void { - const { verbose } = this.envService.cliArgs; - - if (verbose) { + if (this.environmentService.verbose) { console.log(`\x1b[93m[main ${new Date().toLocaleTimeString()}]\x1b[0m`, ...args); } } diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 630046fca2e..5e4ec501f28 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -102,7 +102,7 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: IProce }); logService.log('Starting VS Code in verbose mode'); - logService.log(`from: ${envService.appRoot}`); + logService.log(`from: ${environmentService.appRoot}`); logService.log('args:', envService.cliArgs); // Setup Windows mutex @@ -134,8 +134,8 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: IProce // Spawn shared process const initData = { args: environmentService.args }; const options = { - allowOutput: !envService.isBuilt || envService.cliArgs.verbose, - debugPort: envService.isBuilt ? null : 5871 + allowOutput: !environmentService.isBuilt || environmentService.verbose, + debugPort: environmentService.isBuilt ? null : 5871 }; let sharedProcessDisposable; diff --git a/src/vs/code/electron-main/storage.ts b/src/vs/code/electron-main/storage.ts index decedc16d3a..3f337a5495d 100644 --- a/src/vs/code/electron-main/storage.ts +++ b/src/vs/code/electron-main/storage.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import * as fs from 'original-fs'; -import { IEnvService } from 'vs/code/electron-main/env'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const IStorageService = createDecorator('storageService'); @@ -26,8 +26,8 @@ export class StorageService implements IStorageService { private dbPath: string; private database: any = null; - constructor(@IEnvService private envService: IEnvService) { - this.dbPath = path.join(envService.appHome, 'storage.json'); + constructor(@IEnvironmentService private environmentService: IEnvironmentService) { + this.dbPath = path.join(environmentService.userDataPath, 'storage.json'); } getItem(key: string, defaultValue?: T): T { @@ -74,7 +74,7 @@ export class StorageService implements IStorageService { try { return JSON.parse(fs.readFileSync(this.dbPath).toString()); // invalid JSON or permission issue can happen here } catch (error) { - if (this.envService.cliArgs.verbose) { + if (this.environmentService.verbose) { console.error(error); } @@ -86,7 +86,7 @@ export class StorageService implements IStorageService { try { fs.writeFileSync(this.dbPath, JSON.stringify(this.database, null, 4)); // permission issue can happen here } catch (error) { - if (this.envService.cliArgs.verbose) { + if (this.environmentService.verbose) { console.error(error); } } diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 13ccfc249e2..843869fb3a2 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -11,7 +11,8 @@ import * as objects from 'vs/base/common/objects'; import { IStorageService } from 'vs/code/electron-main/storage'; import { shell, screen, BrowserWindow } from 'electron'; import { TPromise, TValueCallback } from 'vs/base/common/winjs.base'; -import { ICommandLineArguments, IEnvService, IProcessEnvironment } from 'vs/code/electron-main/env'; +import { ICommandLineArguments, IProcessEnvironment } from 'vs/code/electron-main/env'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/code/electron-main/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { parseArgs } from 'vs/platform/environment/node/argv'; @@ -135,7 +136,7 @@ export class VSCodeWindow { constructor( config: IWindowCreationOptions, @ILogService private logService: ILogService, - @IEnvService private envService: IEnvService, + @IEnvironmentService private environmentService: IEnvironmentService, @IConfigurationService private configurationService: IConfigurationService, @IStorageService private storageService: IStorageService ) { @@ -173,7 +174,7 @@ export class VSCodeWindow { }; if (platform.isLinux) { - options.icon = path.join(this.envService.appRoot, 'resources/linux/code.png'); // Windows and Mac are better off using the embedded icon(s) + options.icon = path.join(this.environmentService.appRoot, 'resources/linux/code.png'); // Windows and Mac are better off using the embedded icon(s) } // Create the browser window. @@ -340,7 +341,7 @@ export class VSCodeWindow { // Prevent any kind of navigation triggered by the user! // But do not touch this in dev version because it will prevent "Reload" from dev tools - if (this.envService.isBuilt) { + if (this.environmentService.isBuilt) { this._win.webContents.on('will-navigate', (event: Event) => { if (event) { event.preventDefault(); @@ -375,7 +376,7 @@ export class VSCodeWindow { this._win.loadURL(this.getUrl(config)); // Make window visible if it did not open in N seconds because this indicates an error - if (!this.envService.isBuilt) { + if (!this.environmentService.isBuilt) { this.showTimeoutHandle = setTimeout(() => { if (this._win && !this._win.isVisible() && !this._win.isMinimized()) { this._win.show(); diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 5534b35fd91..a6438697c3d 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -14,6 +14,7 @@ import * as types from 'vs/base/common/types'; import * as arrays from 'vs/base/common/arrays'; import { assign, mixin } from 'vs/base/common/objects'; import { EventEmitter } from 'events'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IStorageService } from 'vs/code/electron-main/storage'; import { IPath, VSCodeWindow, ReadyState, IWindowConfiguration, IWindowState as ISingleWindowState, defaultWindowState, IWindowSettings } from 'vs/code/electron-main/window'; import { ipcMain as ipc, app, screen, crashReporter, BrowserWindow, dialog } from 'electron'; @@ -162,6 +163,7 @@ export class WindowsManager implements IWindowsService { @ILogService private logService: ILogService, @IStorageService private storageService: IStorageService, @IEnvService private envService: IEnvService, + @IEnvironmentService private environmentService: IEnvironmentService, @ILifecycleService private lifecycleService: ILifecycleService, @IUpdateService private updateService: IUpdateService, @IConfigurationService private configurationService: IConfigurationService @@ -843,7 +845,7 @@ export class WindowsManager implements IWindowsService { private toConfiguration(userEnv: IProcessEnvironment, cli: ICommandLineArguments, workspacePath?: string, filesToOpen?: IPath[], filesToCreate?: IPath[], filesToDiff?: IPath[]): IWindowConfiguration { const configuration: IWindowConfiguration = mixin({}, cli); // inherit all properties from CLI - configuration.appRoot = this.envService.appRoot; + configuration.appRoot = this.environmentService.appRoot; configuration.execPath = process.execPath; configuration.userEnv = userEnv; configuration.workspacePath = workspacePath; diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 57d50f59025..3a54ba179b7 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -34,6 +34,7 @@ export interface IEnvironmentService { isBuilt: boolean; verbose: boolean; + wait: boolean; performance: boolean; mainIPCHandle: string; diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 830231abab4..f3bb9a38948 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -89,6 +89,7 @@ export class EnvironmentService implements IEnvironmentService { get isBuilt(): boolean { return !process.env['VSCODE_DEV']; } get verbose(): boolean { return this._args.verbose; } + get wait(): boolean { return this._args.wait; } get performance(): boolean { return this._args.performance; } get logExtensionHostCommunication(): boolean { return this._args.logExtensionHostCommunication; } From 26b36f39144cb2dcb24c82fb443563cddc7fffae Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 6 Oct 2016 09:09:27 +0200 Subject: [PATCH 081/163] more reuse with other env --- src/vs/code/electron-main/env.ts | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/vs/code/electron-main/env.ts b/src/vs/code/electron-main/env.ts index e038bd5c30c..5ae83d4b98e 100644 --- a/src/vs/code/electron-main/env.ts +++ b/src/vs/code/electron-main/env.ts @@ -13,7 +13,7 @@ import * as paths from 'vs/base/common/paths'; import * as platform from 'vs/base/common/platform'; import * as types from 'vs/base/common/types'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { parseArgs, ParsedArgs } from 'vs/platform/environment/node/argv'; +import { parseMainProcessArgv, ParsedArgs } from 'vs/platform/environment/node/argv'; export interface IProcessEnvironment { [key: string]: string; @@ -38,23 +38,8 @@ export class EnvService implements IEnvService { get cliArgs(): ICommandLineArguments { return this._cliArgs; } constructor() { - - // Remove the Electron executable - const [, ...args] = process.argv; - - // If dev, remove the first non-option argument: it's the app location - const isBuilt = !process.env['VSCODE_DEV']; - if (!isBuilt) { - const index = arrays.firstIndex(args, a => !/^-/.test(a)); - - if (index > -1) { - args.splice(index, 1); - } - } - - const argv = parseArgs(args); - const cwd = process.env['VSCODE_CWD'] || process.cwd(); - const paths = parsePathArguments(cwd, argv._, argv.goto); + const argv = parseMainProcessArgv(process.argv); + const paths = parsePathArguments(argv._, argv.goto); this._cliArgs = Object.freeze({ _: [], @@ -79,7 +64,8 @@ export class EnvService implements IEnvService { } } -function parsePathArguments(cwd: string, args: string[], gotoLineMode?: boolean): string[] { +function parsePathArguments(args: string[], gotoLineMode?: boolean): string[] { + const cwd = process.env['VSCODE_CWD'] || process.cwd(); const result = args.map(arg => { let pathCandidate = String(arg); From 2fa4a93506ad70a735de2e01aeb4b74adcc25512 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 6 Oct 2016 09:06:54 +0200 Subject: [PATCH 082/163] fixes #13264 --- .../electron-browser/releaseNotesEditor.ts | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts index 21f41aadea2..4ee582ad2d9 100644 --- a/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts +++ b/src/vs/workbench/parts/update/electron-browser/releaseNotesEditor.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { marked } from 'vs/base/common/marked/marked'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { Builder } from 'vs/base/browser/builder'; import { append, $ } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; @@ -39,9 +39,9 @@ export class ReleaseNotesEditor extends BaseEditor { static ID: string = 'workbench.editor.releaseNotes'; private content: HTMLElement; + private webview: WebView; private contentDisposables: IDisposable[] = []; - private disposables: IDisposable[]; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -53,7 +53,6 @@ export class ReleaseNotesEditor extends BaseEditor { @IModeService private modeService: IModeService ) { super(ReleaseNotesEditor.ID, telemetryService); - this.disposables = []; } createEditor(parent: Builder): void { @@ -64,6 +63,7 @@ export class ReleaseNotesEditor extends BaseEditor { setInput(input: ReleaseNotesInput, options: EditorOptions): TPromise { const { text } = input; + this.contentDisposables = dispose(this.contentDisposables); this.content.innerHTML = ''; return super.setInput(input, options) @@ -89,18 +89,19 @@ export class ReleaseNotesEditor extends BaseEditor { }) .then(renderBody) .then(body => { - const webview = new WebView( + this.webview = new WebView( this.content, document.querySelector('.monaco-editor-background') ); - webview.baseUrl = `https://code.visualstudio.com/raw/`; - webview.style(this.themeService.getColorTheme()); - webview.contents = [body]; + this.webview.baseUrl = `https://code.visualstudio.com/raw/`; + this.webview.style(this.themeService.getColorTheme()); + this.webview.contents = [body]; - webview.onDidClickLink(link => this.openerService.open(link), null, this.contentDisposables); - this.themeService.onDidColorThemeChange(themeId => webview.style(themeId), null, this.contentDisposables); - this.contentDisposables.push(webview); + this.webview.onDidClickLink(link => this.openerService.open(link), null, this.contentDisposables); + this.themeService.onDidColorThemeChange(themeId => this.webview.style(themeId), null, this.contentDisposables); + this.contentDisposables.push(this.webview); + this.contentDisposables.push(toDisposable(() => this.webview = null)); }); } @@ -108,8 +109,16 @@ export class ReleaseNotesEditor extends BaseEditor { // noop } + focus(): void { + if (!this.webview) { + return; + } + + this.webview.focus(); + } + dispose(): void { - this.disposables = dispose(this.disposables); + this.contentDisposables = dispose(this.contentDisposables); super.dispose(); } } From 8fedf4674bb4ebae1be84eefecf53a02717810ec Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Wed, 5 Oct 2016 17:06:57 +0200 Subject: [PATCH 083/163] fix exact content widget layout when overflowing --- .../viewParts/contentWidgets/contentWidgets.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index dec9e55164f..a56a553745a 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -304,6 +304,12 @@ export class ViewContentWidgets extends ViewPart { }; } + private _prepareRenderWidgetAtExactPositionOverflowing(position: Position, ctx: IRenderingContext): IMyWidgetRenderData { + let r = this._prepareRenderWidgetAtExactPosition(position, ctx); + r.left += this._contentLeft; + return r; + } + private _prepareRenderWidget(widgetData:IWidgetData, ctx:IRenderingContext): IMyWidgetRenderData { if (!widgetData.position || !widgetData.preference) { return null; @@ -362,7 +368,11 @@ export class ViewContentWidgets extends ViewPart { }; } } else { - return this._prepareRenderWidgetAtExactPosition(position, ctx); + if (widgetData.allowEditorOverflow) { + return this._prepareRenderWidgetAtExactPositionOverflowing(position, ctx); + } else { + return this._prepareRenderWidgetAtExactPosition(position, ctx); + } } } } From d7b8a9c9d94ff8c2dbe3bc7a8d566e41ca9d298b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 6 Oct 2016 09:39:09 +0200 Subject: [PATCH 084/163] move light bulb to gutter, use context menu to show code actions, fixes #11400 --- .../{quickFix.css => lightBulbWidget.css} | 26 -- .../quickFix/browser/lightBulbWidget.ts | 75 ++++-- .../contrib/quickFix/browser/quickFix.ts | 176 +++---------- .../quickFix/browser/quickFixWidget.ts | 235 +++--------------- 4 files changed, 125 insertions(+), 387 deletions(-) rename src/vs/editor/contrib/quickFix/browser/{quickFix.css => lightBulbWidget.css} (61%) diff --git a/src/vs/editor/contrib/quickFix/browser/quickFix.css b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.css similarity index 61% rename from src/vs/editor/contrib/quickFix/browser/quickFix.css rename to src/vs/editor/contrib/quickFix/browser/lightBulbWidget.css index 29f984b2111..457499a7e36 100644 --- a/src/vs/editor/contrib/quickFix/browser/quickFix.css +++ b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.css @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -/* light bulp */ .monaco-editor .lightbulb-glyph { display: flex; @@ -26,28 +25,3 @@ height: 16px; width: 16px; } - - -/* quick fix suggestion dialog */ - -.monaco-editor .quickfix-widget { - background-color: #F3F3F3; - border: 1px solid rgb(200, 200, 200); - z-index: 40; -} - -.monaco-editor .quickfix-widget .quickfix-entry { - padding: 2px 2px 2px 2px; -} - -/* Dark theme */ -.monaco-editor.vs-dark .quickfix-widget { - background-color: #2D2D30; - border: 1px solid rgb(69, 69, 69); -} - -/* High Contrast Theming */ -.monaco-editor.hc-black .quickfix-widget { - background-color: #0C141F; - border: 2px solid #6FC3DF; -} diff --git a/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts index dc629d14e3a..d348c449c3b 100644 --- a/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts +++ b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts @@ -4,33 +4,42 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import 'vs/css!./lightBulbWidget'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import Event, { Emitter } from 'vs/base/common/event'; import * as dom from 'vs/base/browser/dom'; import { IPosition } from 'vs/editor/common/editorCommon'; import { Position } from 'vs/editor/common/core/position'; -import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { QuickFixComputeEvent } from './quickFixModel'; -export class LightBulbWidget implements IContentWidget, IDisposable { + +export class LightBulbWidget implements IOverlayWidget, IDisposable { private _editor: ICodeEditor; private _position: IPosition; private _domNode: HTMLElement; private _visible: boolean; - private _onClick = new Emitter(); + private _onClick = new Emitter<{ x: number, y: number }>(); + private _model: QuickFixComputeEvent; private _toDispose: IDisposable[] = []; constructor(editor: ICodeEditor) { this._editor = editor; - this._editor.addContentWidget(this); + this._editor.addOverlayWidget(this); + this._toDispose.push(this._editor.onDidScrollChange(() => { + if (this._visible) { + this._layout(); + } + })); } public dispose(): void { - this._editor.removeContentWidget(this); + this._editor.removeOverlayWidget(this); this._toDispose = dispose(this._toDispose); } - get onClick(): Event { + get onClick(): Event<{ x: number, y: number }> { return this._onClick.event; } @@ -38,44 +47,64 @@ export class LightBulbWidget implements IContentWidget, IDisposable { return '__lightBulbWidget'; } - // Editor.IContentWidget.allowEditorOverflow - get allowEditorOverflow() { - return true; - } - getDomNode(): HTMLElement { if (!this._domNode) { this._domNode = document.createElement('div'); this._domNode.style.width = '20px'; this._domNode.style.height = '20px'; - this._domNode.className = 'lightbulb-glyph'; + this._domNode.className = 'lightbulb-glyph hidden'; this._toDispose.push(dom.addDisposableListener(this._domNode, 'mousedown', (e: MouseEvent) => { e.preventDefault(); - this._onClick.fire(this._position); + this._onClick.fire({ x: e.clientX, y: e.clientY }); })); } return this._domNode; } - getPosition(): IContentWidgetPosition { - return this._visible - ? { position: this._position, preference: [ContentWidgetPositionPreference.BELOW, ContentWidgetPositionPreference.ABOVE] } - : null; + getPosition(): IOverlayWidgetPosition { + return null; + } + + set model(e: QuickFixComputeEvent) { + this._model = e; + this.hide(); + const modelNow = this._model; + e.fixes.done(fixes => { + if (modelNow === this._model && fixes && fixes.length > 0) { + this.show(e.position); + } else { + this.hide(); + } + }, err => { + this.hide(); + }); + } + + get model(): QuickFixComputeEvent { + return this._model; } show(where: IPosition): void { - if (this._visible && Position.equals(this._position, where)) { - return; + if (!this._visible || !Position.equals(this._position, where)) { + this._position = where; + this._visible = true; + this._layout(); } - this._position = where; - this._visible = true; - this._editor.layoutContentWidget(this); + } + + private _layout(): void { + const topForLineNumber = this._editor.getTopForLineNumber(this._position.lineNumber); + const editorScrollTop = this._editor.getScrollTop(); + const top = topForLineNumber - editorScrollTop; + this._domNode.style.top = `${top}px`; + this._domNode.style.left = `${0}px`; + this._domNode.classList.remove('hidden'); } hide(): void { if (this._visible) { this._visible = false; - this._editor.layoutContentWidget(this); + this._domNode.classList.add('hidden'); } } } diff --git a/src/vs/editor/contrib/quickFix/browser/quickFix.ts b/src/vs/editor/contrib/quickFix/browser/quickFix.ts index 79601f1523a..867f4fc5680 100644 --- a/src/vs/editor/contrib/quickFix/browser/quickFix.ts +++ b/src/vs/editor/contrib/quickFix/browser/quickFix.ts @@ -5,19 +5,18 @@ 'use strict'; import * as nls from 'vs/nls'; -import { onUnexpectedError } from 'vs/base/common/errors'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { ContextKeyExpr, RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { Selection } from 'vs/editor/common/core/selection'; -import { IPosition, ICommonCodeEditor, EditorContextKeys, ModeContextKeys, IEditorContribution } from 'vs/editor/common/editorCommon'; -import { editorAction, ServicesAccessor, EditorAction, EditorCommand, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; +import { ICommonCodeEditor, EditorContextKeys, ModeContextKeys, IEditorContribution } from 'vs/editor/common/editorCommon'; +import { editorAction, ServicesAccessor, EditorAction } from 'vs/editor/common/editorCommonExtensions'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; -import { IQuickFix2 } from '../common/quickFix'; -import { QuickFixContentWidget } from './quickFixWidget'; +import { QuickFixContextMenu } from './quickFixWidget'; import { LightBulbWidget } from './lightBulbWidget'; import { QuickFixModel, QuickFixComputeEvent } from './quickFixModel'; @@ -32,35 +31,32 @@ export class QuickFixController implements IEditorContribution { private _editor: ICodeEditor; private _model: QuickFixModel; - private _quickFixWidgetVisible: IContextKey; - private _quickFixWidget: QuickFixContentWidget; + private _quickFixContextMenu: QuickFixContextMenu; private _lightBulbWidget: LightBulbWidget; - private _disposables: IDisposable[] = []; constructor(editor: ICodeEditor, @IMarkerService markerService: IMarkerService, @IContextKeyService contextKeyService: IContextKeyService, - @ICommandService private _commandService: ICommandService + @ICommandService commandService: ICommandService, + @IContextMenuService contextMenuService: IContextMenuService, + @IKeybindingService private _keybindingService: IKeybindingService ) { this._editor = editor; this._model = new QuickFixModel(this._editor, markerService); - - this._quickFixWidgetVisible = CONTEXT_QUICK_FIX_WIDGET_VISIBLE.bindTo(contextKeyService); - this._quickFixWidget = new QuickFixContentWidget(editor); + this._quickFixContextMenu = new QuickFixContextMenu(editor, contextMenuService, commandService); this._lightBulbWidget = new LightBulbWidget(editor); + this._updateLightBulbTitle(); + this._disposables.push( - this._quickFixWidget.list.onDidSelectQuickFix(this._handleQuickFixSelect, this), this._lightBulbWidget.onClick(this._handleLightBulbSelect, this), this._model.onDidChangeFixes(e => this._onQuickFixEvent(e)), - this._editor.onDidChangeCursorSelection(() => this.closeWidget()), - // this._editor.onDidBlurEditorText(() => this.closeWidget()) + this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitle, this) ); } public dispose(): void { - this._quickFixWidget.dispose(); this._model.dispose(); dispose(this._disposables); } @@ -68,25 +64,16 @@ export class QuickFixController implements IEditorContribution { private _onQuickFixEvent(e: QuickFixComputeEvent): void { if (e.type === 'manual') { this._lightBulbWidget.hide(); - this._quickFixWidgetVisible.set(true); - this._quickFixWidget.show(e.fixes, e.position); + this._quickFixContextMenu.show(e.fixes, e.position); } else if (e.fixes) { // auto magically triggered // * update an existing list of code actions // * manage light bulb - if (this._quickFixWidget.isVisible()) { - this._quickFixWidget.show(e.fixes, e.position); + if (this._quickFixContextMenu.isVisible) { + this._quickFixContextMenu.show(e.fixes, e.position); } else { - e.fixes.then(fixes => { - if (fixes && fixes.length > 0) { - this._lightBulbWidget.show(e.position); - } else { - this._lightBulbWidget.hide(); - } - }, err => { - this._lightBulbWidget.hide(); - }); + this._lightBulbWidget.model = e; } } else { this._lightBulbWidget.hide(); @@ -97,64 +84,35 @@ export class QuickFixController implements IEditorContribution { return QuickFixController.ID; } - private _handleQuickFixSelect({command}: IQuickFix2): void { - this.closeWidget(); - this._editor.focus(); - return this._commandService.executeCommand(command.id, ...command.arguments).done(void 0, onUnexpectedError); - } - - private _handleLightBulbSelect(pos: IPosition): void { - const selection = new Selection(pos.lineNumber, pos.column, pos.lineNumber, pos.column); - this._model.triggerManual(selection); + private _handleLightBulbSelect(coords: { x: number, y: number }): void { + this._lightBulbWidget.hide(); + this._quickFixContextMenu.show(this._lightBulbWidget.model.fixes, coords); } public triggerFromEditorSelection(): void { this._model.triggerManual(this._editor.getSelection()); } - public acceptSelectedSuggestion(): void { - if (this._quickFixWidget.isListVisible()) { - this._quickFixWidget.list.select(); - } - } - - public closeWidget(): void { - this._lightBulbWidget.hide(); - this._quickFixWidget.hide(); - this._quickFixWidgetVisible.reset(); - } - - public selectNextSuggestion(): void { - if (this._quickFixWidget.isListVisible()) { - this._quickFixWidget.list.focusNext(); - } - } - - public selectNextPageSuggestion(): void { - if (this._quickFixWidget.isListVisible()) { - this._quickFixWidget.list.focusNextPage(); - } - } - - public selectPrevSuggestion(): void { - if (this._quickFixWidget.isListVisible()) { - this._quickFixWidget.list.focusPrevious(); - } - } - - public selectPrevPageSuggestion(): void { - if (this._quickFixWidget.isListVisible()) { - this._quickFixWidget.list.focusPreviousPage(); + private _updateLightBulbTitle(): void { + const [kb] = this._keybindingService.lookupKeybindings(QuickFixAction.Id); + let title: string; + if (kb) { + title = nls.localize('quickFixWithKb', "Show Fixes ({0})", this._keybindingService.getLabelFor(kb)); + } else { + title = nls.localize('quickFix', "Show Fixes", this._keybindingService.getLabelFor(kb)); } + this._lightBulbWidget.getDomNode().title = title; } } @editorAction export class QuickFixAction extends EditorAction { + static Id = 'editor.action.quickFix'; + constructor() { super({ - id: 'editor.action.quickFix', + id: QuickFixAction.Id, label: nls.localize('quickfix.trigger.label', "Quick Fix"), alias: 'Quick Fix', precondition: ContextKeyExpr.and(EditorContextKeys.Writable, ModeContextKeys.hasCodeActionsProvider), @@ -172,73 +130,3 @@ export class QuickFixAction extends EditorAction { } } } - -const CONTEXT_QUICK_FIX_WIDGET_VISIBLE = new RawContextKey('quickFixWidgetVisible', false); - -const QuickFixCommand = EditorCommand.bindToContribution(QuickFixController.get); - -// register action -CommonEditorRegistry.registerEditorCommand(new QuickFixCommand({ - id: 'acceptQuickFixSuggestion', - precondition: CONTEXT_QUICK_FIX_WIDGET_VISIBLE, - handler: x => x.acceptSelectedSuggestion(), - kbOpts: { - weight: CommonEditorRegistry.commandWeight(80), - kbExpr: EditorContextKeys.Focus, - primary: KeyCode.Enter, - secondary: [KeyCode.Tab] - } -})); -CommonEditorRegistry.registerEditorCommand(new QuickFixCommand({ - id: 'closeQuickFixWidget', - precondition: CONTEXT_QUICK_FIX_WIDGET_VISIBLE, - handler: x => x.closeWidget(), - kbOpts: { - weight: CommonEditorRegistry.commandWeight(80), - kbExpr: EditorContextKeys.Focus, - primary: KeyCode.Escape, - secondary: [KeyMod.Shift | KeyCode.Escape] - } -})); -CommonEditorRegistry.registerEditorCommand(new QuickFixCommand({ - id: 'selectNextQuickFix', - precondition: CONTEXT_QUICK_FIX_WIDGET_VISIBLE, - handler: x => x.selectNextSuggestion(), - kbOpts: { - weight: CommonEditorRegistry.commandWeight(80), - kbExpr: EditorContextKeys.Focus, - primary: KeyCode.DownArrow, - mac: { primary: KeyCode.DownArrow, secondary: [KeyMod.WinCtrl | KeyCode.KEY_N] } - } -})); -CommonEditorRegistry.registerEditorCommand(new QuickFixCommand({ - id: 'selectNextPageQuickFix', - precondition: CONTEXT_QUICK_FIX_WIDGET_VISIBLE, - handler: x => x.selectNextPageSuggestion(), - kbOpts: { - weight: CommonEditorRegistry.commandWeight(80), - kbExpr: EditorContextKeys.Focus, - primary: KeyCode.PageDown - } -})); -CommonEditorRegistry.registerEditorCommand(new QuickFixCommand({ - id: 'selectPrevQuickFix', - precondition: CONTEXT_QUICK_FIX_WIDGET_VISIBLE, - handler: x => x.selectPrevSuggestion(), - kbOpts: { - weight: CommonEditorRegistry.commandWeight(80), - kbExpr: EditorContextKeys.Focus, - primary: KeyCode.UpArrow, - mac: { primary: KeyCode.UpArrow, secondary: [KeyMod.WinCtrl | KeyCode.KEY_P] } - } -})); -CommonEditorRegistry.registerEditorCommand(new QuickFixCommand({ - id: 'selectPrevPageQuickFix', - precondition: CONTEXT_QUICK_FIX_WIDGET_VISIBLE, - handler: x => x.selectPrevPageSuggestion(), - kbOpts: { - weight: CommonEditorRegistry.commandWeight(80), - kbExpr: EditorContextKeys.Focus, - primary: KeyCode.PageUp - } -})); diff --git a/src/vs/editor/contrib/quickFix/browser/quickFixWidget.ts b/src/vs/editor/contrib/quickFix/browser/quickFixWidget.ts index c92126d046c..5e82b1543fc 100644 --- a/src/vs/editor/contrib/quickFix/browser/quickFixWidget.ts +++ b/src/vs/editor/contrib/quickFix/browser/quickFixWidget.ts @@ -5,219 +5,66 @@ 'use strict'; -import 'vs/css!./quickFix'; -import Event, { Emitter } from 'vs/base/common/event'; -import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { hide, show } from 'vs/base/browser/dom'; -import { IDisposable } from 'vs/base/common/lifecycle'; -import { IDelegate, IRenderer } from 'vs/base/browser/ui/list/list'; -import { List } from 'vs/base/browser/ui/list/listWidget'; +import { getDomNodePagePosition } from 'vs/base/browser/dom'; +import { Position } from 'vs/editor/common/core/position'; import { IPosition } from 'vs/editor/common/editorCommon'; -import { ICodeEditor, IContentWidget, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; -import { alert } from 'vs/base/browser/ui/aria/aria'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { IQuickFix2 } from '../common/quickFix'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { Action } from 'vs/base/common/actions'; -const quickFixRenderer = new class implements IRenderer { - - templateId = 'command'; - - renderTemplate(container: HTMLElement): HTMLElement { - container.classList.add('quickfix-entry'); - return container; - } - - renderElement(element: IQuickFix2, index: number, templateData: HTMLElement): void { - templateData.innerText = element.command.title; - } - - disposeTemplate(templateData: HTMLElement): void { - - } -}; - -export class QuickFixList { - - domNode: HTMLDivElement; +export class QuickFixContextMenu { private _editor: ICodeEditor; - private _onDidSelect = new Emitter(); - private _widget: List; - private _widgetSubscription: IDisposable; + private _contextMenuService: IContextMenuService; + private _commandService: ICommandService; + private _visible: boolean; - constructor(editor: ICodeEditor) { + constructor(editor: ICodeEditor, contextMenuService: IContextMenuService, commandService: ICommandService) { this._editor = editor; - this.createElements(); + this._contextMenuService = contextMenuService; + this._commandService = commandService; } - dispose(): void { - this._widgetSubscription.dispose(); - } + show(fixes: TPromise, at: { x: number; y: number } | IPosition) { - protected createElements() { + const actions = fixes.then(value => { + return value.map(({command}) => { + return new Action(command.id, command.title, undefined, true, () => { + return this._commandService.executeCommand(command.id, ...command.arguments); + }); + }); + }); - this.domNode = document.createElement('div'); - - const delegate = >{ - getHeight: () => this._editor.getConfiguration().lineHeight, - getTemplateId: () => 'command' - }; - - this._widget = new List(this.domNode, delegate, [quickFixRenderer], { useShadows: false }); - this._widgetSubscription = this._widget.onSelectionChange(event => { - const [first] = event.elements; - if (first) { - alert(localize('quickFixAccepted', "{0}, accepted", first.command.title)); - this._onDidSelect.fire(first); - } + this._contextMenuService.showContextMenu({ + getAnchor: () => { + if (Position.isIPosition(at)) { + at = this._toCoords(at); + } + return at; + }, + getActions: () => actions, + onHide: () => { this._visible = false; } }); } - get onDidSelectQuickFix(): Event { - return this._onDidSelect.event; + get isVisible(): boolean { + return this._visible; } - setInput(fixes: IQuickFix2[]): void { - this._widget.splice(0, this._widget.length, ...fixes); - this._widget.layout(Math.min(5, fixes.length) * this._editor.getConfiguration().lineHeight); - } + private _toCoords(position: IPosition): { x: number, y: number } { - focusNext(): void { - this._widget.focusNext(); - } + this._editor.revealPosition(position); + this._editor.render(); - focusPrevious(): void { - this._widget.focusPrevious(); - } + // Translate to absolute editor position + const cursorCoords = this._editor.getScrolledVisiblePosition(this._editor.getPosition()); + const editorCoords = getDomNodePagePosition(this._editor.getDomNode()); + const x = editorCoords.left + cursorCoords.left; + const y = editorCoords.top + cursorCoords.top + cursorCoords.height; - focusNextPage(): void { - this._widget.focusNextPage(); - } - - focusPreviousPage(): void { - this._widget.focusPreviousPage(); - } - - select(): void { - const [first] = this._widget.getFocus(); - if (typeof first === 'number') { - this._widget.setSelection(first); - } - } -} - -export class Message { - - static Loading = localize('QuickFixSelectionWidget.loading', "Loading..."); - static NoFixes = localize('QuickFixSelectionWidget.noSuggestions', "No fix suggestions."); - - domNode: HTMLDivElement; - - constructor(editor: ICodeEditor) { - this.domNode = document.createElement('div'); - this.domNode.style.height = editor.getConfiguration().lineHeight + 'px'; - } - - set value(value: string) { - this.domNode.innerText = value; - } -} - -export class QuickFixContentWidget implements IContentWidget { - - domNode: HTMLDivElement; - message: Message; - list: QuickFixList; - - private _editor: ICodeEditor; - private _position: IPosition; - - constructor(editor: ICodeEditor) { - this._editor = editor; - this._editor.addContentWidget(this); - - this.message = new Message(this._editor); - this.list = new QuickFixList(this._editor); - - hide(this.message.domNode); - hide(this.list.domNode); - - this.domNode = document.createElement('div'); - this.domNode.classList.add('quickfix-widget'); - this.domNode.appendChild(this.message.domNode); - this.domNode.appendChild(this.list.domNode); - } - - dispose(): void { - this._editor.removeContentWidget(this); - } - - getId(): string { - return 'QuickFixContentWidget'; - } - - getDomNode(): HTMLElement { - return this.domNode; - } - - show(fixes: TPromise, position: IPosition): void { - - this._position = position; - - hide(this.list.domNode); - show(this.message.domNode); - - this.message.value = Message.Loading; - this._layout(); - - fixes.then(values => { - if (values.length > 0) { - hide(this.message.domNode); - show(this.list.domNode); - this._layout(Math.min(5, values.length)); - this.list.setInput(values); - } else { - this.message.value = Message.NoFixes; - } - }, err => { - this.hide(); - }); - } - - private _layout(heightInLines: number = 1): void { - - const {lineHeight} = this._editor.getConfiguration(); - const width = 18 * lineHeight + 'px'; - const height = heightInLines * lineHeight + 'px'; - - this.domNode.style.width = width; - this.domNode.style.height = height; - - this._editor.layoutContentWidget(this); - } - - hide(): void { - this._position = undefined; - this._layout(); - } - - isVisible(): boolean { - return !!this._position; - } - - isListVisible(): boolean { - return this.isVisible() && this.list.domNode.style.display !== 'none'; - } - - isMessageVisible(): boolean { - return this.isVisible() && this.message.domNode.style.display !== 'none'; - } - - getPosition(): IContentWidgetPosition { - if (this._position) { - return { position: this._position, preference: [ContentWidgetPositionPreference.BELOW] }; - } else { - return null; - } + return { x, y }; } } From 5a9efd8aa8255edc4287754b46a34216867e956d Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 6 Oct 2016 09:49:14 +0200 Subject: [PATCH 085/163] better y-position when clicking light bulb, #11400 --- .../editor/contrib/quickFix/browser/lightBulbWidget.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts index d348c449c3b..54eb2ce5f25 100644 --- a/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts +++ b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts @@ -55,7 +55,15 @@ export class LightBulbWidget implements IOverlayWidget, IDisposable { this._domNode.className = 'lightbulb-glyph hidden'; this._toDispose.push(dom.addDisposableListener(this._domNode, 'mousedown', (e: MouseEvent) => { e.preventDefault(); - this._onClick.fire({ x: e.clientX, y: e.clientY }); + + // a bit of extra work to make sure the menu + // doesn't cover the line-text + const {top, height} = dom.getDomNodePagePosition(this._domNode); + const {lineHeight} = this._editor.getConfiguration(); + this._onClick.fire({ + x: e.clientX, + y: top + height + Math.floor(lineHeight / 3) + }); })); } return this._domNode; From 26433f86b2717fd3247f790683f30c510c166274 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 6 Oct 2016 10:40:29 +0200 Subject: [PATCH 086/163] don't show (or hide) lightbulb when there is something in the glyph margin, #11400 --- .../quickFix/browser/lightBulbWidget.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts index 54eb2ce5f25..e7aaa711bae 100644 --- a/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts +++ b/src/vs/editor/contrib/quickFix/browser/lightBulbWidget.ts @@ -32,6 +32,12 @@ export class LightBulbWidget implements IOverlayWidget, IDisposable { this._layout(); } })); + this._toDispose.push(this._editor.onDidChangeModelDecorations(() => { + // hide when something has been added to glyph margin + if (this._visible && !this._hasSpaceInGlyphMargin(this._position.lineNumber)) { + this.hide(); + } + })); } public dispose(): void { @@ -93,6 +99,9 @@ export class LightBulbWidget implements IOverlayWidget, IDisposable { } show(where: IPosition): void { + if (!this._hasSpaceInGlyphMargin(where.lineNumber)) { + return; + } if (!this._visible || !Position.equals(this._position, where)) { this._position = where; this._visible = true; @@ -100,6 +109,15 @@ export class LightBulbWidget implements IOverlayWidget, IDisposable { } } + private _hasSpaceInGlyphMargin(line: number): boolean { + for (const {options} of this._editor.getLineDecorations(line)) { + if (options.glyphMarginClassName) { + return false; + } + } + return true; + } + private _layout(): void { const topForLineNumber = this._editor.getTopForLineNumber(this._position.lineNumber); const editorScrollTop = this._editor.getScrollTop(); From 805458786dda0fb86b0beb437a0503609029990c Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 6 Oct 2016 10:59:58 +0200 Subject: [PATCH 087/163] more more code actions in F8, fixes #13287 --- .../contrib/gotoError/browser/gotoError.css | 28 +-- .../contrib/gotoError/browser/gotoError.ts | 172 +++--------------- .../gotoError/browser/lightbulp-dark.svg | 1 - .../contrib/gotoError/browser/lightbulp.svg | 1 - 4 files changed, 22 insertions(+), 180 deletions(-) delete mode 100644 src/vs/editor/contrib/gotoError/browser/lightbulp-dark.svg delete mode 100644 src/vs/editor/contrib/gotoError/browser/lightbulp.svg diff --git a/src/vs/editor/contrib/gotoError/browser/gotoError.css b/src/vs/editor/contrib/gotoError/browser/gotoError.css index 6fc9d0d102c..df43c3ebdd9 100644 --- a/src/vs/editor/contrib/gotoError/browser/gotoError.css +++ b/src/vs/editor/contrib/gotoError/browser/gotoError.css @@ -5,7 +5,7 @@ /* marker zone */ .monaco-editor .marker-widget { - padding-left: 20px; + padding-left: 2px; background-color: white; overflow: hidden; text-overflow: ellipsis; @@ -38,29 +38,3 @@ .monaco-editor .marker-widget .descriptioncontainer { white-space: pre-wrap; } - - -.monaco-editor .marker-widget .fixes .quickfixhead { - background-image: url('lightbulp.svg'); - background-repeat: no-repeat; - padding-left: 20px; -} - -.monaco-editor.vs-dark .marker-widget .fixes .quickfixhead, -.monaco-editor.hc-black .marker-widget .fixes .quickfixhead { - background-image: url('lightbulp-dark.svg'); -} - -.monaco-editor .marker-widget .fixes .quickfixentry { - text-decoration: underline; -} - -.monaco-editor .marker-widget .fixes .quickfixentry:hover { - cursor: pointer; - color: blue; -} - -.monaco-editor.vs-dark .marker-widget .fixes .quickfixentry:hover, -.monaco-editor.hc-black .marker-widget .fixes .quickfixentry:hover { - color: lightblue; -} diff --git a/src/vs/editor/contrib/gotoError/browser/gotoError.ts b/src/vs/editor/contrib/gotoError/browser/gotoError.ts index b92472925bf..5ac18c20422 100644 --- a/src/vs/editor/contrib/gotoError/browser/gotoError.ts +++ b/src/vs/editor/contrib/gotoError/browser/gotoError.ts @@ -7,26 +7,23 @@ import 'vs/css!./gotoError'; import * as nls from 'vs/nls'; -import {onUnexpectedError} from 'vs/base/common/errors'; -import {Emitter} from 'vs/base/common/event'; -import {KeyCode, KeyMod} from 'vs/base/common/keyCodes'; -import {IDisposable, dispose} from 'vs/base/common/lifecycle'; +import { Emitter } from 'vs/base/common/event'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import Severity from 'vs/base/common/severity'; import URI from 'vs/base/common/uri'; -import {TPromise} from 'vs/base/common/winjs.base'; import * as dom from 'vs/base/browser/dom'; -import {ICommandService} from 'vs/platform/commands/common/commands'; -import {RawContextKey, IContextKey, IContextKeyService} from 'vs/platform/contextkey/common/contextkey'; -import {IMarker, IMarkerService} from 'vs/platform/markers/common/markers'; -import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; -import {Position} from 'vs/editor/common/core/position'; -import {Range} from 'vs/editor/common/core/range'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IMarker, IMarkerService } from 'vs/platform/markers/common/markers'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { Position } from 'vs/editor/common/core/position'; +import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import {editorAction, ServicesAccessor, IActionOptions, EditorAction, EditorCommand, CommonEditorRegistry} from 'vs/editor/common/editorCommonExtensions'; -import {ICodeEditor} from 'vs/editor/browser/editorBrowser'; -import {editorContribution} from 'vs/editor/browser/editorBrowserExtensions'; -import {ZoneWidget} from 'vs/editor/contrib/zoneWidget/browser/zoneWidget'; -import {getCodeActions, IQuickFix2} from 'vs/editor/contrib/quickFix/common/quickFix'; +import { editorAction, ServicesAccessor, IActionOptions, EditorAction, EditorCommand, CommonEditorRegistry } from 'vs/editor/common/editorCommonExtensions'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; +import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget'; import EditorContextKeys = editorCommon.EditorContextKeys; @@ -190,124 +187,10 @@ class MarkerModel { } } -class FixesWidget { - - domNode: HTMLDivElement; - - private _disposeOnUpdate: IDisposable[] = []; - private _listener: IDisposable; - - constructor( - container: HTMLElement, - private _markerWidget: MarkerNavigationWidget, - @ICommandService private _commandService: ICommandService - ) { - this.domNode = document.createElement('div'); - container.appendChild(this.domNode); - - this._listener = dom.addStandardDisposableListener(container, 'keydown', (e) => { - switch (e.asKeybinding()) { - case KeyCode.LeftArrow: - this._move(true); - e.preventDefault(); - e.stopPropagation(); - break; - case KeyCode.RightArrow: - this._move(false); - e.preventDefault(); - e.stopPropagation(); - break; - } - }); - } - - dispose(): void { - this._disposeOnUpdate = dispose(this._disposeOnUpdate); - this._listener = dispose(this._listener); - } - - update(marker: IMarker): TPromise { - this._disposeOnUpdate = dispose(this._disposeOnUpdate); - this.domNode.style.display = 'none'; - if (marker) { - const fixes = getCodeActions(this._markerWidget.editor.getModel(), Range.lift(marker)); - return fixes.then(fixes => this._doUpdate(fixes), onUnexpectedError); - } - } - - private _doUpdate(fixes: IQuickFix2[]): void { - - dom.clearNode(this.domNode); - - if (!fixes || fixes.length === 0) { - return; - } - - // light bulb and label - let quickfixhead = document.createElement('span'); - quickfixhead.className = 'quickfixhead'; - quickfixhead.appendChild(document.createTextNode(fixes.length > 1 - ? nls.localize('quickfix.multiple.label', 'Suggested fixes: ') - : nls.localize('quickfix.single.label', 'Suggested fix: '))); - this.domNode.appendChild(quickfixhead); - - // each fix as entry - const container = document.createElement('span'); - container.className = 'quickfixcontainer'; - - fixes.forEach((fix, idx, arr) => { - - if (idx > 0) { - let separator = document.createElement('span'); - separator.appendChild(document.createTextNode(', ')); - container.appendChild(separator); - } - - let entry = document.createElement('a'); - entry.tabIndex = 0; - entry.className = `quickfixentry`; - entry.dataset['idx'] = String(idx); - entry.dataset['next'] = String(idx < arr.length - 1 ? idx + 1 : 0); - entry.dataset['prev'] = String(idx > 0 ? idx - 1 : arr.length - 1); - entry.appendChild(document.createTextNode(fix.command.title)); - this._disposeOnUpdate.push(dom.addDisposableListener(entry, dom.EventType.CLICK, (e) => { - this._commandService.executeCommand(fix.command.id, ...fix.command.arguments); - this._markerWidget.focus(); - e.preventDefault(); - })); - this._disposeOnUpdate.push(dom.addStandardDisposableListener(entry, 'keydown', (e) => { - switch (e.asKeybinding()) { - case KeyCode.Enter: - case KeyCode.Space: - this._commandService.executeCommand(fix.command.id, ...fix.command.arguments); - this._markerWidget.focus(); - e.preventDefault(); - e.stopPropagation(); - } - })); - container.appendChild(entry); - }); - - this.domNode.appendChild(container); - this.domNode.style.display = ''; - } - - private _move(left: boolean): void { - let target: HTMLElement; - if (document.activeElement.classList.contains('quickfixentry')) { - let current = document.activeElement; - let idx = left ? current.dataset['prev'] : current.dataset['next']; - target = this.domNode.querySelector(`a[data-idx='${idx}']`); - } else { - target = this.domNode.querySelector('.quickfixentry'); - } - target.focus(); - } -} - class MessageWidget { domNode: HTMLDivElement; + lines: number = 0; constructor(container: HTMLElement) { this.domNode = document.createElement('div'); @@ -318,9 +201,11 @@ class MessageWidget { } update({source, message}: IMarker): void { + this.lines = 1; if (source) { const indent = new Array(source.length + 3 + 1).join(' '); - message = `[${source}] ` + message.replace(/\r\n|\r|\n/g, function () { + message = `[${source}] ` + message.replace(/\r\n|\r|\n/g, () => { + this.lines += 1; return '\n' + indent; }); } @@ -334,7 +219,6 @@ class MarkerNavigationWidget extends ZoneWidget { private _container: HTMLElement; private _title: HTMLElement; private _message: MessageWidget; - private _fixesWidget: FixesWidget; private _callOnDispose: IDisposable[] = []; constructor(editor: ICodeEditor, private _model: MarkerModel, private _commandService: ICommandService) { @@ -367,10 +251,6 @@ class MarkerNavigationWidget extends ZoneWidget { this._message = new MessageWidget(this._container); this.editor.applyFontInfo(this._message.domNode); - - this._fixesWidget = new FixesWidget(this._container, this, this._commandService); - this._fixesWidget.domNode.classList.add('fixes'); - this._callOnDispose.push(this._fixesWidget); } public show(where: editorCommon.IPosition, heightInLines: number): void { @@ -393,11 +273,9 @@ class MarkerNavigationWidget extends ZoneWidget { // update: // * title // * message - // * quick fixes this._container.classList.remove('stale'); this._title.innerHTML = nls.localize('title.wo_source', "({0}/{1})", this._model.indexOf(marker), this._model.total); this._message.update(marker); - this._fixesWidget.update(marker).then(() => this._relayout()); this._model.withoutWatchingEditorPosition(() => { @@ -420,20 +298,14 @@ class MarkerNavigationWidget extends ZoneWidget { } private _onMarkersChanged(): void { - const marker = this._model.findMarkerAtPosition(this.position); - if (marker) { this._container.classList.remove('stale'); this._message.update(marker); - this._relayout(); - this._fixesWidget.update(marker).then(() => this._relayout()); - } else { this._container.classList.add('stale'); - this._fixesWidget.update(marker); - this._relayout(); } + this._relayout(); } protected _relayout(): void { @@ -441,9 +313,7 @@ class MarkerNavigationWidget extends ZoneWidget { } private computeRequiredHeight() { - // minimum one line content, add one line for zone widget decorations - const lineHeight = this.editor.getConfiguration().lineHeight || 12; - return Math.max(1, Math.ceil(this._container.clientHeight / lineHeight)) + 1; + return 1 + this._message.lines; } } @@ -451,12 +321,12 @@ class MarkerNavigationAction extends EditorAction { private _isNext: boolean; - constructor(next: boolean, opts:IActionOptions) { + constructor(next: boolean, opts: IActionOptions) { super(opts); this._isNext = next; } - public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { const telemetryService = accessor.get(ITelemetryService); let controller = MarkerController.get(editor); diff --git a/src/vs/editor/contrib/gotoError/browser/lightbulp-dark.svg b/src/vs/editor/contrib/gotoError/browser/lightbulp-dark.svg deleted file mode 100644 index 520f78f3e55..00000000000 --- a/src/vs/editor/contrib/gotoError/browser/lightbulp-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/browser/lightbulp.svg b/src/vs/editor/contrib/gotoError/browser/lightbulp.svg deleted file mode 100644 index b3596046616..00000000000 --- a/src/vs/editor/contrib/gotoError/browser/lightbulp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 378d4d96f290d07d91a69230fe11b3c2c67b9a49 Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 6 Oct 2016 11:40:10 +0200 Subject: [PATCH 088/163] debug: do not use special line height for the repl input fixes #13067 --- src/vs/workbench/parts/debug/browser/media/repl.css | 5 +++-- src/vs/workbench/parts/debug/electron-browser/repl.ts | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/parts/debug/browser/media/repl.css b/src/vs/workbench/parts/debug/browser/media/repl.css index bf336af2f63..8422141e5cd 100644 --- a/src/vs/workbench/parts/debug/browser/media/repl.css +++ b/src/vs/workbench/parts/debug/browser/media/repl.css @@ -122,17 +122,18 @@ .monaco-workbench.windows .repl .repl-input-wrapper:before { content: '\203A'; /* character does not exist on windows */ font-size: 22px; + line-height: 18px; } .monaco-workbench.linux .repl .repl-input-wrapper:before { content: '\276f'; font-size: 9px; - line-height: 22px; + line-height: 18px; } .monaco-workbench.mac .repl .repl-input-wrapper:before { content: '\276f'; - line-height: 22px; + line-height: 18px; } .monaco-workbench .repl .repl-input { diff --git a/src/vs/workbench/parts/debug/electron-browser/repl.ts b/src/vs/workbench/parts/debug/electron-browser/repl.ts index ac8c36a6801..cef8f9e94b9 100644 --- a/src/vs/workbench/parts/debug/electron-browser/repl.ts +++ b/src/vs/workbench/parts/debug/electron-browser/repl.ts @@ -62,7 +62,7 @@ export class Repl extends Panel implements IPrivateReplService { private static HISTORY: replhistory.ReplHistory; private static REFRESH_DELAY = 500; // delay in ms to refresh the repl for new elements to show - private static REPL_INPUT_INITIAL_HEIGHT = 22; + private static REPL_INPUT_INITIAL_HEIGHT = 19; private static REPL_INPUT_MAX_HEIGHT = 170; private toDispose: lifecycle.IDisposable[]; @@ -276,7 +276,6 @@ export class Repl extends Panel implements IPrivateReplService { }, lineDecorationsWidth: 0, scrollBeyondLastLine: false, - lineHeight: 21, theme: this.themeService.getColorTheme(), renderLineHighlight: false }; From b36b44a3acecd79cac3cd3e05cf1c6684aa9b393 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 6 Oct 2016 11:41:25 +0200 Subject: [PATCH 089/163] use different stickiness when two placeholder occurrences touch, fixes #12506 --- .../snippet/common/snippetController.ts | 51 +++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/src/vs/editor/contrib/snippet/common/snippetController.ts b/src/vs/editor/contrib/snippet/common/snippetController.ts index d9f46df9a64..11b19b7c127 100644 --- a/src/vs/editor/contrib/snippet/common/snippetController.ts +++ b/src/vs/editor/contrib/snippet/common/snippetController.ts @@ -5,16 +5,17 @@ 'use strict'; -import {KeyCode, KeyMod} from 'vs/base/common/keyCodes'; +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import * as strings from 'vs/base/common/strings'; -import {RawContextKey, IContextKey, IContextKeyService} from 'vs/platform/contextkey/common/contextkey'; -import {EditOperation} from 'vs/editor/common/core/editOperation'; -import {Range} from 'vs/editor/common/core/range'; -import {Selection} from 'vs/editor/common/core/selection'; +import { binarySearch } from 'vs/base/common/arrays'; +import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { EditOperation } from 'vs/editor/common/core/editOperation'; +import { Range } from 'vs/editor/common/core/range'; +import { Selection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import {CommonEditorRegistry, commonEditorContribution, EditorCommand} from 'vs/editor/common/editorCommonExtensions'; -import {IDisposable, dispose} from 'vs/base/common/lifecycle'; -import {ICodeSnippet, CodeSnippet} from './snippet'; +import { CommonEditorRegistry, commonEditorContribution, EditorCommand } from 'vs/editor/common/editorCommonExtensions'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { ICodeSnippet, CodeSnippet } from './snippet'; import EditorContextKeys = editorCommon.EditorContextKeys; @@ -57,14 +58,34 @@ export class InsertSnippetController { } private initialize(adaptedSnippet: ICodeSnippet, startLineNumber: number): void { - var i: number, len: number; - for (i = 0, len = adaptedSnippet.placeHolders.length; i < len; i++) { - var placeHolder = adaptedSnippet.placeHolders[i]; + // sorted list of all placeholder occurences for subsequent lockups + const sortedOccurrences: editorCommon.IRange[] = []; + for (const {occurences} of adaptedSnippet.placeHolders) { + for (const range of occurences) { + sortedOccurrences.push(range); + } + } + sortedOccurrences.sort(Range.compareRangesUsingStarts); - var trackedRanges: string[] = []; - for (var j = 0, lenJ = placeHolder.occurences.length; j < lenJ; j++) { - trackedRanges.push(this.model.addTrackedRange(placeHolder.occurences[j], editorCommon.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges)); + // track each occurence + for (const {occurences} of adaptedSnippet.placeHolders) { + const trackedRanges: string[] = []; + + for (const range of occurences) { + let stickiness = editorCommon.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges; + + // Check if the previous range ends exactly where this range starts + // and iff so change the stickiness to avoid conflicts + let idx = binarySearch(sortedOccurrences, range, Range.compareRangesUsingStarts); + if (idx > 0 + && sortedOccurrences[idx - 1].endLineNumber === range.startLineNumber + && sortedOccurrences[idx - 1].endColumn === range.startColumn) { + + stickiness = editorCommon.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter; + } + + trackedRanges.push(this.model.addTrackedRange(range, stickiness)); } this.trackedPlaceHolders.push({ @@ -525,7 +546,7 @@ export class SnippetController { finalCursorOffset = finalCursorPos.column - typeRange.startColumn; } else { finalCursorOffset = finalCursorPos.column - 1; - for (let i = 0, lineNumber = typeRange.startLineNumber; lineNumber < finalCursorPos.lineNumber; i++, lineNumber++) { + for (let i = 0, lineNumber = typeRange.startLineNumber; lineNumber < finalCursorPos.lineNumber; i++ , lineNumber++) { finalCursorOffset += adaptedSnippet.lines[i].length + model.getEOL().length; } } From 6832950cedeae70b122ab7b430a114394f36b294 Mon Sep 17 00:00:00 2001 From: isidor Date: Thu, 6 Oct 2016 12:39:38 +0200 Subject: [PATCH 090/163] find: do not always include current line for find in selection fixes #12820 --- src/vs/editor/contrib/find/browser/findWidget.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vs/editor/contrib/find/browser/findWidget.ts b/src/vs/editor/contrib/find/browser/findWidget.ts index e10e1882de8..24964fb48eb 100644 --- a/src/vs/editor/contrib/find/browser/findWidget.ts +++ b/src/vs/editor/contrib/find/browser/findWidget.ts @@ -145,6 +145,9 @@ export class FindWidget extends Widget implements IOverlayWidget { this._focusTracker.addFocusListener(() => { this._findInputFocussed.set(true); let selection = this._codeEditor.getSelection(); + if (selection.endColumn === 1) { + selection = selection.setEndPosition(selection.endLineNumber - 1, 1); + } let currentMatch = this._state.currentMatch; if (selection.startLineNumber !== selection.endLineNumber) { if (!Range.equalsRange(selection, currentMatch)) { @@ -501,6 +504,9 @@ export class FindWidget extends Widget implements IOverlayWidget { onChange: () => { if (this._toggleSelectionFind.checked) { let selection = this._codeEditor.getSelection(); + if (selection.endColumn === 1) { + selection = selection.setEndPosition(selection.endLineNumber - 1, 1); + } if (!selection.isEmpty()) { this._state.change({ searchScope: selection }, true); } From 685621636d833cbcefba8c0b5763013dc0bb8ffa Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 6 Oct 2016 13:53:32 +0200 Subject: [PATCH 091/163] extract and reuse IProcessEnvironment --- src/vs/base/common/platform.ts | 6 +++++- src/vs/code/electron-main/env.ts | 4 ---- src/vs/code/electron-main/launch.ts | 3 ++- src/vs/code/electron-main/main.ts | 14 +++++--------- src/vs/code/electron-main/window.ts | 4 ++-- src/vs/code/electron-main/windows.ts | 14 +++++++------- .../workbench/parts/execution/common/execution.ts | 3 ++- .../execution/electron-browser/terminalService.ts | 7 ++++--- 8 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index 5caa5c8a418..5771fcbd54a 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -21,9 +21,13 @@ interface NLSConfig { availableLanguages: { [key: string]: string; }; } +export interface IProcessEnvironment { + [key: string]: string; +} + interface INodeProcess { platform: string; - env: { [key: string]: string; }; + env: IProcessEnvironment; getuid(): number; } declare let process: INodeProcess; diff --git a/src/vs/code/electron-main/env.ts b/src/vs/code/electron-main/env.ts index 5ae83d4b98e..6cf0cc84fda 100644 --- a/src/vs/code/electron-main/env.ts +++ b/src/vs/code/electron-main/env.ts @@ -15,10 +15,6 @@ import * as types from 'vs/base/common/types'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { parseMainProcessArgv, ParsedArgs } from 'vs/platform/environment/node/argv'; -export interface IProcessEnvironment { - [key: string]: string; -} - export interface ICommandLineArguments extends ParsedArgs { paths?: string[]; } diff --git a/src/vs/code/electron-main/launch.ts b/src/vs/code/electron-main/launch.ts index ae604e7ab0c..bf874b5b317 100644 --- a/src/vs/code/electron-main/launch.ts +++ b/src/vs/code/electron-main/launch.ts @@ -5,13 +5,14 @@ 'use strict'; -import { ICommandLineArguments, IProcessEnvironment } from 'vs/code/electron-main/env'; +import { ICommandLineArguments } from 'vs/code/electron-main/env'; import { IWindowsService } from 'vs/code/electron-main/windows'; import { VSCodeWindow } from 'vs/code/electron-main/window'; import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { ILogService } from 'vs/code/electron-main/log'; import { IURLService } from 'vs/platform/url/common/url'; +import { IProcessEnvironment } from 'vs/base/common/platform'; export interface IStartArguments { args: ICommandLineArguments; diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 5e4ec501f28..7a1bfdac611 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -11,7 +11,7 @@ import { assign } from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; import { parseMainProcessArgv, ParsedArgs } from 'vs/platform/environment/node/argv'; import { mkdirp } from 'vs/base/node/pfs'; -import { IProcessEnvironment, IEnvService, EnvService } from 'vs/code/electron-main/env'; +import { IEnvService, EnvService } from 'vs/code/electron-main/env'; import { IWindowsService, WindowsManager, WindowEventService } from 'vs/code/electron-main/windows'; import { IWindowEventService } from 'vs/code/common/windows'; import { WindowEventChannel } from 'vs/code/common/windowsIpc'; @@ -69,7 +69,7 @@ function quit(accessor: ServicesAccessor, arg?: any) { process.exit(exitCode); // in main, process.exit === app.exit } -function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: IProcessEnvironment): void { +function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platform.IProcessEnvironment): void { const instantiationService = accessor.get(IInstantiationService); const logService = accessor.get(ILogService); const envService = accessor.get(IEnvService); @@ -329,11 +329,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise { return setup(true); } -interface IEnv { - [key: string]: string; -} - -function getUnixShellEnvironment(): TPromise { +function getUnixShellEnvironment(): TPromise { const promise = new TPromise((c, e) => { const runAsNode = process.env['ELECTRON_RUN_AS_NODE']; const noAttach = process.env['ELECTRON_NO_ATTACH_CONSOLE']; @@ -396,7 +392,7 @@ function getUnixShellEnvironment(): TPromise { * This should only be done when Code itself is not launched * from within a shell. */ -function getShellEnvironment(): TPromise { +function getShellEnvironment(): TPromise { if (process.env['VSCODE_CLI'] === '1') { return TPromise.as({}); } @@ -413,7 +409,7 @@ function getShellEnvironment(): TPromise { * Such environment needs to be propagated to the renderer/shared * processes. */ -function getEnvironment(accessor: ServicesAccessor): TPromise { +function getEnvironment(accessor: ServicesAccessor): TPromise { const environmentService = accessor.get(IEnvironmentService); return getShellEnvironment().then(shellEnv => { diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 843869fb3a2..e95135ba16a 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -11,7 +11,7 @@ import * as objects from 'vs/base/common/objects'; import { IStorageService } from 'vs/code/electron-main/storage'; import { shell, screen, BrowserWindow } from 'electron'; import { TPromise, TValueCallback } from 'vs/base/common/winjs.base'; -import { ICommandLineArguments, IProcessEnvironment } from 'vs/code/electron-main/env'; +import { ICommandLineArguments } from 'vs/code/electron-main/env'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/code/electron-main/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -92,7 +92,7 @@ export interface IWindowConfiguration extends ICommandLineArguments { appRoot: string; execPath: string; - userEnv: IProcessEnvironment; + userEnv: platform.IProcessEnvironment; zoomLevel?: number; diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index a6438697c3d..8df4b73c5b8 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -18,7 +18,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IStorageService } from 'vs/code/electron-main/storage'; import { IPath, VSCodeWindow, ReadyState, IWindowConfiguration, IWindowState as ISingleWindowState, defaultWindowState, IWindowSettings } from 'vs/code/electron-main/window'; import { ipcMain as ipc, app, screen, crashReporter, BrowserWindow, dialog } from 'electron'; -import { ICommandLineArguments, IProcessEnvironment, IEnvService, IParsedPath, parseLineAndColumnAware } from 'vs/code/electron-main/env'; +import { ICommandLineArguments, IEnvService, IParsedPath, parseLineAndColumnAware } from 'vs/code/electron-main/env'; import { ILifecycleService } from 'vs/code/electron-main/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IUpdateService, IUpdate } from 'vs/code/electron-main/update-manager'; @@ -41,7 +41,7 @@ enum WindowError { export interface IOpenConfiguration { cli: ICommandLineArguments; - userEnv?: IProcessEnvironment; + userEnv?: platform.IProcessEnvironment; pathsToOpen?: string[]; preferNewWindow?: boolean; forceNewWindow?: boolean; @@ -98,7 +98,7 @@ export interface IWindowsService { onWindowFocus: CommonEvent; // methods - ready(initialUserEnv: IProcessEnvironment): void; + ready(initialUserEnv: platform.IProcessEnvironment): void; reload(win: VSCodeWindow, cli?: ICommandLineArguments): void; open(openConfig: IOpenConfiguration): VSCodeWindow[]; openPluginDevelopmentHostWindow(openConfig: IOpenConfiguration): void; @@ -149,7 +149,7 @@ export class WindowsManager implements IWindowsService { private static WINDOWS: VSCodeWindow[] = []; private eventEmitter = new EventEmitter(); - private initialUserEnv: IProcessEnvironment; + private initialUserEnv: platform.IProcessEnvironment; private windowsState: IWindowsState; private _onFocus = new Emitter(); @@ -187,7 +187,7 @@ export class WindowsManager implements IWindowsService { return () => this.eventEmitter.removeListener(EventTypes.CLOSE, clb); } - public ready(initialUserEnv: IProcessEnvironment): void { + public ready(initialUserEnv: platform.IProcessEnvironment): void { this.registerListeners(); this.initialUserEnv = initialUserEnv; @@ -806,7 +806,7 @@ export class WindowsManager implements IWindowsService { return { files, folders }; } - private getWindowUserEnv(openConfig: IOpenConfiguration): IProcessEnvironment { + private getWindowUserEnv(openConfig: IOpenConfiguration): platform.IProcessEnvironment { return assign({}, this.initialUserEnv, openConfig.userEnv || {}); } @@ -843,7 +843,7 @@ export class WindowsManager implements IWindowsService { this.open({ cli: openConfig.cli, forceNewWindow: true, forceEmpty: openConfig.cli.paths.length === 0 }); } - private toConfiguration(userEnv: IProcessEnvironment, cli: ICommandLineArguments, workspacePath?: string, filesToOpen?: IPath[], filesToCreate?: IPath[], filesToDiff?: IPath[]): IWindowConfiguration { + private toConfiguration(userEnv: platform.IProcessEnvironment, cli: ICommandLineArguments, workspacePath?: string, filesToOpen?: IPath[], filesToCreate?: IPath[], filesToDiff?: IPath[]): IWindowConfiguration { const configuration: IWindowConfiguration = mixin({}, cli); // inherit all properties from CLI configuration.appRoot = this.environmentService.appRoot; configuration.execPath = process.execPath; diff --git a/src/vs/workbench/parts/execution/common/execution.ts b/src/vs/workbench/parts/execution/common/execution.ts index b10f1b3a668..4e4d8b6e714 100644 --- a/src/vs/workbench/parts/execution/common/execution.ts +++ b/src/vs/workbench/parts/execution/common/execution.ts @@ -6,11 +6,12 @@ import {createDecorator} from 'vs/platform/instantiation/common/instantiation'; import {TPromise} from 'vs/base/common/winjs.base'; +import {IProcessEnvironment} from 'vs/base/common/platform'; export const ITerminalService = createDecorator('nativeTerminalService'); export interface ITerminalService { _serviceBrand: any; openTerminal(path: string): void; - runInTerminal(title: string, cwd: string, args: string[], env: { [key: string]: string; }): TPromise; + runInTerminal(title: string, cwd: string, args: string[], env: IProcessEnvironment): TPromise; } \ No newline at end of file diff --git a/src/vs/workbench/parts/execution/electron-browser/terminalService.ts b/src/vs/workbench/parts/execution/electron-browser/terminalService.ts index 10a4c2b69e8..cb01a1f1a3a 100644 --- a/src/vs/workbench/parts/execution/electron-browser/terminalService.ts +++ b/src/vs/workbench/parts/execution/electron-browser/terminalService.ts @@ -14,6 +14,7 @@ import {ITerminalService} from 'vs/workbench/parts/execution/common/execution'; import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {ITerminalConfiguration, DEFAULT_TERMINAL_WINDOWS, DEFAULT_TERMINAL_LINUX, DEFAULT_TERMINAL_OSX} from 'vs/workbench/parts/execution/electron-browser/terminal'; import uri from 'vs/base/common/uri'; +import {IProcessEnvironment} from 'vs/base/common/platform'; const TERMINAL_TITLE = nls.localize('console.title', "VS Code Console"); @@ -34,7 +35,7 @@ export class WinTerminalService implements ITerminalService { .done(null, errors.onUnexpectedError); } - public runInTerminal(title: string, dir: string, args: string[], envVars: { [key: string]: string; }): TPromise { + public runInTerminal(title: string, dir: string, args: string[], envVars: IProcessEnvironment): TPromise { const configuration = this._configurationService.getConfiguration(); const terminalConfig = configuration.terminal.external; @@ -101,7 +102,7 @@ export class MacTerminalService implements ITerminalService { this.spawnTerminal(cp, configuration, path).done(null, errors.onUnexpectedError); } - public runInTerminal(title: string, dir: string, args: string[], envVars: { [key: string]: string; }): TPromise { + public runInTerminal(title: string, dir: string, args: string[], envVars: IProcessEnvironment): TPromise { const configuration = this._configurationService.getConfiguration(); const terminalConfig = configuration.terminal.external; @@ -188,7 +189,7 @@ export class LinuxTerminalService implements ITerminalService { .done(null, errors.onUnexpectedError); } - public runInTerminal(title: string, dir: string, args: string[], envVars: { [key: string]: string; }): TPromise { + public runInTerminal(title: string, dir: string, args: string[], envVars: IProcessEnvironment): TPromise { const configuration = this._configurationService.getConfiguration(); const terminalConfig = configuration.terminal.external; From 91db8b520f4131e533abe1b6e3e07e921ede7040 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 6 Oct 2016 14:03:47 +0200 Subject: [PATCH 092/163] get rid of ICommandLineArguments --- src/vs/code/electron-main/env.ts | 13 ++++------- src/vs/code/electron-main/launch.ts | 14 +++++------ src/vs/code/electron-main/main.ts | 5 ++-- src/vs/code/electron-main/menus.ts | 18 +++++++------- src/vs/code/electron-main/window.ts | 7 +++--- src/vs/code/electron-main/windows.ts | 35 ++++++++++++++-------------- 6 files changed, 44 insertions(+), 48 deletions(-) diff --git a/src/vs/code/electron-main/env.ts b/src/vs/code/electron-main/env.ts index 6cf0cc84fda..299ba7ce47c 100644 --- a/src/vs/code/electron-main/env.ts +++ b/src/vs/code/electron-main/env.ts @@ -15,31 +15,26 @@ import * as types from 'vs/base/common/types'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { parseMainProcessArgv, ParsedArgs } from 'vs/platform/environment/node/argv'; -export interface ICommandLineArguments extends ParsedArgs { - paths?: string[]; -} - export const IEnvService = createDecorator('mainEnvironmentService'); export interface IEnvService { _serviceBrand: any; - cliArgs: ICommandLineArguments; + cliArgs: ParsedArgs; } export class EnvService implements IEnvService { _serviceBrand: any; - private _cliArgs: ICommandLineArguments; - get cliArgs(): ICommandLineArguments { return this._cliArgs; } + private _cliArgs: ParsedArgs; + get cliArgs(): ParsedArgs { return this._cliArgs; } constructor() { const argv = parseMainProcessArgv(process.argv); const paths = parsePathArguments(argv._, argv.goto); this._cliArgs = Object.freeze({ - _: [], - paths, + _: paths, performance: argv.performance, verbose: argv.verbose, debugPluginHost: argv.debugPluginHost, diff --git a/src/vs/code/electron-main/launch.ts b/src/vs/code/electron-main/launch.ts index bf874b5b317..c708a942011 100644 --- a/src/vs/code/electron-main/launch.ts +++ b/src/vs/code/electron-main/launch.ts @@ -5,7 +5,6 @@ 'use strict'; -import { ICommandLineArguments } from 'vs/code/electron-main/env'; import { IWindowsService } from 'vs/code/electron-main/windows'; import { VSCodeWindow } from 'vs/code/electron-main/window'; import { TPromise } from 'vs/base/common/winjs.base'; @@ -13,14 +12,15 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { ILogService } from 'vs/code/electron-main/log'; import { IURLService } from 'vs/platform/url/common/url'; import { IProcessEnvironment } from 'vs/base/common/platform'; +import { ParsedArgs } from 'vs/platform/environment/node/argv'; export interface IStartArguments { - args: ICommandLineArguments; + args: ParsedArgs; userEnv: IProcessEnvironment; } export interface ILaunchService { - start(args: ICommandLineArguments, userEnv: IProcessEnvironment): TPromise; + start(args: ParsedArgs, userEnv: IProcessEnvironment): TPromise; } export interface ILaunchChannel extends IChannel { @@ -45,7 +45,7 @@ export class LaunchChannelClient implements ILaunchService { constructor(private channel: ILaunchChannel) { } - start(args: ICommandLineArguments, userEnv: IProcessEnvironment): TPromise { + start(args: ParsedArgs, userEnv: IProcessEnvironment): TPromise { return this.channel.call('start', { args, userEnv }); } } @@ -58,7 +58,7 @@ export class LaunchService implements ILaunchService { @IURLService private urlService: IURLService ) {} - start(args: ICommandLineArguments, userEnv: IProcessEnvironment): TPromise { + start(args: ParsedArgs, userEnv: IProcessEnvironment): TPromise { this.logService.log('Received data from other instance: ', args, userEnv); const openUrlArg = args['open-url'] || []; @@ -73,9 +73,9 @@ export class LaunchService implements ILaunchService { let usedWindows: VSCodeWindow[]; if (!!args.extensionDevelopmentPath) { this.windowsService.openPluginDevelopmentHostWindow({ cli: args, userEnv }); - } else if (args.paths.length === 0 && args['new-window']) { + } else if (args._.length === 0 && args['new-window']) { usedWindows = this.windowsService.open({ cli: args, userEnv, forceNewWindow: true, forceEmpty: true }); - } else if (args.paths.length === 0) { + } else if (args._.length === 0) { usedWindows = [this.windowsService.focusLastActive(args)]; } else { usedWindows = this.windowsService.open({ diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 7a1bfdac611..fc66bef8e8c 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -253,9 +253,9 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo updateService.initialize(); // Open our first window - if (envService.cliArgs['new-window'] && envService.cliArgs.paths.length === 0) { + if (envService.cliArgs['new-window'] && envService.cliArgs._.length === 0) { windowsService.open({ cli: envService.cliArgs, forceNewWindow: true, forceEmpty: true }); // new window if "-n" was used without paths - } else if (global.macOpenFiles && global.macOpenFiles.length && (!envService.cliArgs.paths || !envService.cliArgs.paths.length)) { + } else if (global.macOpenFiles && global.macOpenFiles.length && (!envService.cliArgs._ || !envService.cliArgs._.length)) { windowsService.open({ cli: envService.cliArgs, pathsToOpen: global.macOpenFiles }); // mac: open-file event received on startup } else { windowsService.open({ cli: envService.cliArgs, forceNewWindow: envService.cliArgs['new-window'], diffMode: envService.cliArgs.diff }); // default: read paths from cli @@ -426,6 +426,7 @@ function getEnvironment(accessor: ServicesAccessor): TPromise { const paths = [environmentService.appSettingsHome, environmentService.userHome, environmentService.extensionsPath]; + return TPromise.join(paths.map(p => mkdirp(p))) as TPromise; } diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 9a342ae550b..1a05bee2bb0 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -69,11 +69,11 @@ export class VSCodeMenu { }); // Listen to "open" & "close" event from window service - this.windowsService.onOpen((paths) => this.onOpen(paths)); + this.windowsService.onOpen(paths => this.onOpen(paths)); this.windowsService.onClose(_ => this.onClose(this.windowsService.getWindowCount())); // Resolve keybindings when any first workbench is loaded - this.windowsService.onReady((win) => this.resolveKeybindings(win)); + this.windowsService.onReady(win => this.resolveKeybindings(win)); // Listen to resolved keybindings ipc.on('vscode:keybindingsResolved', (event, rawKeybindings) => { @@ -86,7 +86,7 @@ export class VSCodeMenu { // Fill hash map of resolved keybindings let needsMenuUpdate = false; - keybindings.forEach((keybinding) => { + keybindings.forEach(keybinding => { const accelerator = new Keybinding(keybinding.binding)._toElectronAccelerator(); if (accelerator) { this.mapResolvedKeybindingToActionId[keybinding.id] = accelerator; @@ -328,7 +328,7 @@ export class VSCodeMenu { !platform.isMacintosh ? closeWindow : null, !platform.isMacintosh ? __separator__() : null, !platform.isMacintosh ? exit : null - ]).forEach((item) => fileMenu.append(item)); + ]).forEach(item => fileMenu.append(item)); } private getPreferencesMenu(): Electron.MenuItem { @@ -434,8 +434,8 @@ export class VSCodeMenu { let selectAll: Electron.MenuItem; if (platform.isMacintosh) { - undo = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"), 'undo', (devTools) => devTools.undo()); - redo = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"), 'redo', (devTools) => devTools.redo()); + undo = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"), 'undo', devTools => devTools.undo()); + redo = this.createDevToolsAwareMenuItem(nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"), 'redo', devTools => devTools.redo()); cut = this.createRoleMenuItem(nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "&&Cut"), 'editor.action.clipboardCutAction', 'cut'); copy = this.createRoleMenuItem(nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "C&&opy"), 'editor.action.clipboardCopyAction', 'copy'); paste = this.createRoleMenuItem(nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"), 'editor.action.clipboardPasteAction', 'paste'); @@ -531,7 +531,7 @@ export class VSCodeMenu { zoomIn, zoomOut, resetZoom - ]).forEach((item) => viewMenu.append(item)); + ]).forEach(item => viewMenu.append(item)); } private setGotoMenu(gotoMenu: Electron.Menu): void { @@ -673,7 +673,7 @@ export class VSCodeMenu { (product.licenseUrl || product.privacyStatementUrl) ? __separator__() : null, toggleDevToolsItem, platform.isWindows && product.quality !== 'stable' ? showAccessibilityOptions : null - ]).forEach((item) => helpMenu.append(item)); + ]).forEach(item => helpMenu.append(item)); if (!platform.isMacintosh) { const updateMenuItems = this.getUpdateMenuItems(); @@ -811,7 +811,7 @@ export class VSCodeMenu { ), buttons: [nls.localize('okButton', "OK")], noLink: true - }, (result) => null); + }, result => null); this.reportMenuActionTelemetry('showAboutDialog'); } diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index e95135ba16a..1a0d19a57f7 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -11,11 +11,10 @@ import * as objects from 'vs/base/common/objects'; import { IStorageService } from 'vs/code/electron-main/storage'; import { shell, screen, BrowserWindow } from 'electron'; import { TPromise, TValueCallback } from 'vs/base/common/winjs.base'; -import { ICommandLineArguments } from 'vs/code/electron-main/env'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/code/electron-main/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { parseArgs } from 'vs/platform/environment/node/argv'; +import { parseArgs, ParsedArgs } from 'vs/platform/environment/node/argv'; import product from 'vs/platform/product'; export interface IWindowState { @@ -88,7 +87,7 @@ export interface IPath { createFilePath?: boolean; } -export interface IWindowConfiguration extends ICommandLineArguments { +export interface IWindowConfiguration extends ParsedArgs { appRoot: string; execPath: string; @@ -387,7 +386,7 @@ export class VSCodeWindow { } } - public reload(cli?: ICommandLineArguments): void { + public reload(cli?: ParsedArgs): void { // Inherit current properties but overwrite some const configuration: IWindowConfiguration = objects.mixin({}, this.currentConfig); diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 8df4b73c5b8..d2a454dcac8 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -18,7 +18,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IStorageService } from 'vs/code/electron-main/storage'; import { IPath, VSCodeWindow, ReadyState, IWindowConfiguration, IWindowState as ISingleWindowState, defaultWindowState, IWindowSettings } from 'vs/code/electron-main/window'; import { ipcMain as ipc, app, screen, crashReporter, BrowserWindow, dialog } from 'electron'; -import { ICommandLineArguments, IEnvService, IParsedPath, parseLineAndColumnAware } from 'vs/code/electron-main/env'; +import { IEnvService, IParsedPath, parseLineAndColumnAware } from 'vs/code/electron-main/env'; import { ILifecycleService } from 'vs/code/electron-main/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IUpdateService, IUpdate } from 'vs/code/electron-main/update-manager'; @@ -27,6 +27,7 @@ import { IWindowEventService } from 'vs/code/common/windows'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import CommonEvent, { Emitter } from 'vs/base/common/event'; import product from 'vs/platform/product'; +import { ParsedArgs } from 'vs/platform/environment/node/argv'; const EventTypes = { OPEN: 'open', @@ -40,7 +41,7 @@ enum WindowError { } export interface IOpenConfiguration { - cli: ICommandLineArguments; + cli: ParsedArgs; userEnv?: platform.IProcessEnvironment; pathsToOpen?: string[]; preferNewWindow?: boolean; @@ -99,14 +100,14 @@ export interface IWindowsService { // methods ready(initialUserEnv: platform.IProcessEnvironment): void; - reload(win: VSCodeWindow, cli?: ICommandLineArguments): void; + reload(win: VSCodeWindow, cli?: ParsedArgs): void; open(openConfig: IOpenConfiguration): VSCodeWindow[]; openPluginDevelopmentHostWindow(openConfig: IOpenConfiguration): void; openFileFolderPicker(forceNewWindow?: boolean): void; openFilePicker(forceNewWindow?: boolean): void; openFolderPicker(forceNewWindow?: boolean): void; openAccessibilityOptions(): void; - focusLastActive(cli: ICommandLineArguments): VSCodeWindow; + focusLastActive(cli: ParsedArgs): VSCodeWindow; getLastActiveWindow(): VSCodeWindow; findWindow(workspacePath: string, filePath?: string, extensionDevelopmentPath?: string): VSCodeWindow; openNewWindow(): void; @@ -542,7 +543,7 @@ export class WindowsManager implements IWindowsService { } } - public reload(win: VSCodeWindow, cli?: ICommandLineArguments): void { + public reload(win: VSCodeWindow, cli?: ParsedArgs): void { // Only reload when the window has not vetoed this this.lifecycleService.unload(win).done(veto => { @@ -598,7 +599,7 @@ export class WindowsManager implements IWindowsService { // Otherwise infer from command line arguments else { - const ignoreFileNotFound = openConfig.cli.paths.length > 0; // we assume the user wants to create this file from command line + const ignoreFileNotFound = openConfig.cli._.length > 0; // we assume the user wants to create this file from command line iPathsToOpen = this.cliToPaths(openConfig.cli, ignoreFileNotFound); } @@ -824,26 +825,26 @@ export class WindowsManager implements IWindowsService { } // Fill in previously opened workspace unless an explicit path is provided and we are not unit testing - if (openConfig.cli.paths.length === 0 && !openConfig.cli.extensionTestsPath) { + if (openConfig.cli._.length === 0 && !openConfig.cli.extensionTestsPath) { const workspaceToOpen = this.windowsState.lastPluginDevelopmentHostWindow && this.windowsState.lastPluginDevelopmentHostWindow.workspacePath; if (workspaceToOpen) { - openConfig.cli.paths = [workspaceToOpen]; + openConfig.cli._ = [workspaceToOpen]; } } // Make sure we are not asked to open a path that is already opened - if (openConfig.cli.paths.length > 0) { - res = WindowsManager.WINDOWS.filter(w => w.openedWorkspacePath && openConfig.cli.paths.indexOf(w.openedWorkspacePath) >= 0); + if (openConfig.cli._.length > 0) { + res = WindowsManager.WINDOWS.filter(w => w.openedWorkspacePath && openConfig.cli._.indexOf(w.openedWorkspacePath) >= 0); if (res.length) { - openConfig.cli.paths = []; + openConfig.cli._ = []; } } // Open it - this.open({ cli: openConfig.cli, forceNewWindow: true, forceEmpty: openConfig.cli.paths.length === 0 }); + this.open({ cli: openConfig.cli, forceNewWindow: true, forceEmpty: openConfig.cli._.length === 0 }); } - private toConfiguration(userEnv: platform.IProcessEnvironment, cli: ICommandLineArguments, workspacePath?: string, filesToOpen?: IPath[], filesToCreate?: IPath[], filesToDiff?: IPath[]): IWindowConfiguration { + private toConfiguration(userEnv: platform.IProcessEnvironment, cli: ParsedArgs, workspacePath?: string, filesToOpen?: IPath[], filesToCreate?: IPath[], filesToDiff?: IPath[]): IWindowConfiguration { const configuration: IWindowConfiguration = mixin({}, cli); // inherit all properties from CLI configuration.appRoot = this.environmentService.appRoot; configuration.execPath = process.execPath; @@ -888,12 +889,12 @@ export class WindowsManager implements IWindowsService { return null; } - private cliToPaths(cli: ICommandLineArguments, ignoreFileNotFound?: boolean): IPath[] { + private cliToPaths(cli: ParsedArgs, ignoreFileNotFound?: boolean): IPath[] { // Check for pass in candidate or last opened path let candidates: string[] = []; - if (cli.paths.length > 0) { - candidates = cli.paths; + if (cli._.length > 0) { + candidates = cli._; } // No path argument, check settings for what to do now @@ -1139,7 +1140,7 @@ export class WindowsManager implements IWindowsService { }); } - public focusLastActive(cli: ICommandLineArguments): VSCodeWindow { + public focusLastActive(cli: ParsedArgs): VSCodeWindow { const lastActive = this.getLastActiveWindow(); if (lastActive) { lastActive.focus(); From 855bcc50ffa3ae8d6f2e28fc4757d367ca30a665 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 6 Oct 2016 14:19:51 +0200 Subject: [PATCH 093/163] get rid of IEnvService (fixes #10656) --- src/vs/code/electron-main/main.ts | 22 +++--- src/vs/code/electron-main/menus.ts | 6 +- .../code/electron-main/{env.ts => paths.ts} | 75 ++++++------------- src/vs/code/electron-main/windows.ts | 15 ++-- .../environment/node/environmentService.ts | 7 +- 5 files changed, 46 insertions(+), 79 deletions(-) rename src/vs/code/electron-main/{env.ts => paths.ts} (61%) diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index fc66bef8e8c..8a1798c023d 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -11,7 +11,7 @@ import { assign } from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; import { parseMainProcessArgv, ParsedArgs } from 'vs/platform/environment/node/argv'; import { mkdirp } from 'vs/base/node/pfs'; -import { IEnvService, EnvService } from 'vs/code/electron-main/env'; +import { validatePaths } from 'vs/code/electron-main/paths'; import { IWindowsService, WindowsManager, WindowEventService } from 'vs/code/electron-main/windows'; import { IWindowEventService } from 'vs/code/common/windows'; import { WindowEventChannel } from 'vs/code/common/windowsIpc'; @@ -72,7 +72,6 @@ function quit(accessor: ServicesAccessor, arg?: any) { function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platform.IProcessEnvironment): void { const instantiationService = accessor.get(IInstantiationService); const logService = accessor.get(ILogService); - const envService = accessor.get(IEnvService); const environmentService = accessor.get(IEnvironmentService); const windowsService = accessor.get(IWindowsService); const windowEventService = accessor.get(IWindowEventService); @@ -103,7 +102,7 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo logService.log('Starting VS Code in verbose mode'); logService.log(`from: ${environmentService.appRoot}`); - logService.log('args:', envService.cliArgs); + logService.log('args:', environmentService.args); // Setup Windows mutex let windowsMutex: Mutex = null; @@ -253,19 +252,18 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo updateService.initialize(); // Open our first window - if (envService.cliArgs['new-window'] && envService.cliArgs._.length === 0) { - windowsService.open({ cli: envService.cliArgs, forceNewWindow: true, forceEmpty: true }); // new window if "-n" was used without paths - } else if (global.macOpenFiles && global.macOpenFiles.length && (!envService.cliArgs._ || !envService.cliArgs._.length)) { - windowsService.open({ cli: envService.cliArgs, pathsToOpen: global.macOpenFiles }); // mac: open-file event received on startup + if (environmentService.args['new-window'] && environmentService.args._.length === 0) { + windowsService.open({ cli: environmentService.args, forceNewWindow: true, forceEmpty: true }); // new window if "-n" was used without paths + } else if (global.macOpenFiles && global.macOpenFiles.length && (!environmentService.args._ || !environmentService.args._.length)) { + windowsService.open({ cli: environmentService.args, pathsToOpen: global.macOpenFiles }); // mac: open-file event received on startup } else { - windowsService.open({ cli: envService.cliArgs, forceNewWindow: envService.cliArgs['new-window'], diffMode: envService.cliArgs.diff }); // default: read paths from cli + windowsService.open({ cli: environmentService.args, forceNewWindow: environmentService.args['new-window'], diffMode: environmentService.args.diff }); // default: read paths from cli } } function setupIPC(accessor: ServicesAccessor): TPromise { const logService = accessor.get(ILogService); const environmentService = accessor.get(IEnvironmentService); - const envService = accessor.get(IEnvService); function setup(retry: boolean): TPromise { return serve(environmentService.mainIPCHandle).then(server => { @@ -301,7 +299,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise { const channel = client.getChannel('launch'); const service = new LaunchChannelClient(channel); - return service.start(envService.cliArgs, process.env) + return service.start(environmentService.args, process.env) .then(() => client.dispose()) .then(() => TPromise.wrapError('Sent env to running instance. Terminating...')); }, @@ -426,7 +424,7 @@ function getEnvironment(accessor: ServicesAccessor): TPromise { const paths = [environmentService.appSettingsHome, environmentService.userHome, environmentService.extensionsPath]; - + return TPromise.join(paths.map(p => mkdirp(p))) as TPromise; } @@ -435,6 +433,7 @@ function start(): void { try { args = parseMainProcessArgv(process.argv); + args = validatePaths(args); } catch (err) { console.error(err.message); process.exit(1); @@ -445,7 +444,6 @@ function start(): void { const services = new ServiceCollection(); services.set(IEnvironmentService, new SyncDescriptor(EnvironmentService, args, process.execPath)); - services.set(IEnvService, new SyncDescriptor(EnvService)); services.set(ILogService, new SyncDescriptor(MainLogService)); services.set(IWindowsService, new SyncDescriptor(WindowsManager)); services.set(IWindowEventService, new SyncDescriptor(WindowEventService)); diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 1a05bee2bb0..3e4f3944257 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -8,7 +8,7 @@ import * as nls from 'vs/nls'; import * as platform from 'vs/base/common/platform'; import * as arrays from 'vs/base/common/arrays'; -import { IEnvService } from 'vs/code/electron-main/env'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ipcMain as ipc, app, shell, dialog, Menu, MenuItem } from 'electron'; import { IWindowsService } from 'vs/code/electron-main/windows'; import { IPath, VSCodeWindow } from 'vs/code/electron-main/window'; @@ -45,7 +45,7 @@ export class VSCodeMenu { @IUpdateService private updateService: IUpdateService, @IConfigurationService private configurationService: IConfigurationService, @IWindowsService private windowsService: IWindowsService, - @IEnvService private envService: IEnvService + @IEnvironmentService private environmentService: IEnvironmentService ) { this.actionIdKeybindingRequests = []; @@ -405,7 +405,7 @@ export class VSCodeMenu { return new MenuItem({ label: unMnemonicLabel(path), click: (menuItem, win, event) => { const openInNewWindow = event && ((!platform.isMacintosh && event.ctrlKey) || (platform.isMacintosh && event.metaKey)); - const success = !!this.windowsService.open({ cli: this.envService.cliArgs, pathsToOpen: [path], forceNewWindow: openInNewWindow }); + const success = !!this.windowsService.open({ cli: this.environmentService.args, pathsToOpen: [path], forceNewWindow: openInNewWindow }); if (!success) { this.windowsService.removeFromRecentPathsList(path); this.updateMenu(); diff --git a/src/vs/code/electron-main/env.ts b/src/vs/code/electron-main/paths.ts similarity index 61% rename from src/vs/code/electron-main/env.ts rename to src/vs/code/electron-main/paths.ts index 299ba7ce47c..4e361d80ba1 100644 --- a/src/vs/code/electron-main/env.ts +++ b/src/vs/code/electron-main/paths.ts @@ -12,55 +12,26 @@ import * as strings from 'vs/base/common/strings'; import * as paths from 'vs/base/common/paths'; import * as platform from 'vs/base/common/platform'; import * as types from 'vs/base/common/types'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { parseMainProcessArgv, ParsedArgs } from 'vs/platform/environment/node/argv'; +import { ParsedArgs } from 'vs/platform/environment/node/argv'; -export const IEnvService = createDecorator('mainEnvironmentService'); +export function validatePaths(args: ParsedArgs): ParsedArgs { -export interface IEnvService { - _serviceBrand: any; - cliArgs: ParsedArgs; + // Realpath/normalize paths and watch out for goto line mode + const paths = doValidatePaths(args._, args.goto); + + // Update environment + args._ = paths; + args.diff = args.diff && paths.length === 2; + + return args; } -export class EnvService implements IEnvService { - - _serviceBrand: any; - - private _cliArgs: ParsedArgs; - get cliArgs(): ParsedArgs { return this._cliArgs; } - - constructor() { - const argv = parseMainProcessArgv(process.argv); - const paths = parsePathArguments(argv._, argv.goto); - - this._cliArgs = Object.freeze({ - _: paths, - performance: argv.performance, - verbose: argv.verbose, - debugPluginHost: argv.debugPluginHost, - debugBrkPluginHost: argv.debugBrkPluginHost, - logExtensionHostCommunication: argv.logExtensionHostCommunication, - 'new-window': argv['new-window'], - 'reuse-window': argv['reuse-window'], - goto: argv.goto, - diff: argv.diff && paths.length === 2, - extensionHomePath: normalizePath(argv.extensionHomePath), - extensionDevelopmentPath: normalizePath(argv.extensionDevelopmentPath), - extensionTestsPath: normalizePath(argv.extensionTestsPath), - 'disable-extensions': argv['disable-extensions'], - 'open-url': argv['open-url'], - locale: argv.locale, - wait: argv.wait - }); - } -} - -function parsePathArguments(args: string[], gotoLineMode?: boolean): string[] { +function doValidatePaths(args: string[], gotoLineMode?: boolean): string[] { const cwd = process.env['VSCODE_CWD'] || process.cwd(); const result = args.map(arg => { let pathCandidate = String(arg); - let parsedPath: IParsedPath; + let parsedPath: IPathWithLineAndColumn; if (gotoLineMode) { parsedPath = parseLineAndColumnAware(pathCandidate); pathCandidate = parsedPath.path; @@ -86,7 +57,7 @@ function parsePathArguments(args: string[], gotoLineMode?: boolean): string[] { if (gotoLineMode) { parsedPath.path = realPath; - return toLineAndColumnPath(parsedPath); + return toPath(parsedPath); } return realPath; @@ -120,17 +91,13 @@ function preparePath(cwd: string, p: string): string { return p; } -function normalizePath(p?: string): string { - return p ? path.normalize(p) : p; -} - -export interface IParsedPath { +export interface IPathWithLineAndColumn { path: string; line?: number; column?: number; } -export function parseLineAndColumnAware(rawPath: string): IParsedPath { +export function parseLineAndColumnAware(rawPath: string): IPathWithLineAndColumn { const segments = rawPath.split(':'); // C:\file.txt:: let path: string; @@ -159,15 +126,15 @@ export function parseLineAndColumnAware(rawPath: string): IParsedPath { }; } -function toLineAndColumnPath(parsedPath: IParsedPath): string { - const segments = [parsedPath.path]; +function toPath(p: IPathWithLineAndColumn): string { + const segments = [p.path]; - if (types.isNumber(parsedPath.line)) { - segments.push(String(parsedPath.line)); + if (types.isNumber(p.line)) { + segments.push(String(p.line)); } - if (types.isNumber(parsedPath.column)) { - segments.push(String(parsedPath.column)); + if (types.isNumber(p.column)) { + segments.push(String(p.column)); } return segments.join(':'); diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index d2a454dcac8..d4a9327154f 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -18,7 +18,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IStorageService } from 'vs/code/electron-main/storage'; import { IPath, VSCodeWindow, ReadyState, IWindowConfiguration, IWindowState as ISingleWindowState, defaultWindowState, IWindowSettings } from 'vs/code/electron-main/window'; import { ipcMain as ipc, app, screen, crashReporter, BrowserWindow, dialog } from 'electron'; -import { IEnvService, IParsedPath, parseLineAndColumnAware } from 'vs/code/electron-main/env'; +import { IPathWithLineAndColumn, parseLineAndColumnAware } from 'vs/code/electron-main/paths'; import { ILifecycleService } from 'vs/code/electron-main/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IUpdateService, IUpdate } from 'vs/code/electron-main/update-manager'; @@ -163,7 +163,6 @@ export class WindowsManager implements IWindowsService { @IInstantiationService private instantiationService: IInstantiationService, @ILogService private logService: ILogService, @IStorageService private storageService: IStorageService, - @IEnvService private envService: IEnvService, @IEnvironmentService private environmentService: IEnvironmentService, @ILifecycleService private lifecycleService: ILifecycleService, @IUpdateService private updateService: IUpdateService, @@ -222,7 +221,7 @@ export class WindowsManager implements IWindowsService { // Handle paths delayed in case more are coming! runningTimeout = setTimeout(() => { - this.open({ cli: this.envService.cliArgs, pathsToOpen: macOpenFiles, preferNewWindow: true /* dropping on the dock prefers to open in a new window */ }); + this.open({ cli: this.environmentService.args, pathsToOpen: macOpenFiles, preferNewWindow: true /* dropping on the dock prefers to open in a new window */ }); macOpenFiles = []; runningTimeout = null; }, 100); @@ -238,7 +237,7 @@ export class WindowsManager implements IWindowsService { this.logService.log('IPC#vscode-windowOpen: ', paths); if (paths && paths.length) { - this.open({ cli: this.envService.cliArgs, pathsToOpen: paths, forceNewWindow: forceNewWindow }); + this.open({ cli: this.environmentService.args, pathsToOpen: paths, forceNewWindow: forceNewWindow }); } }); @@ -277,7 +276,7 @@ export class WindowsManager implements IWindowsService { const win = this.getWindowById(windowId); if (win) { - this.open({ cli: this.envService.cliArgs, forceEmpty: true, windowToUse: win }); + this.open({ cli: this.environmentService.args, forceEmpty: true, windowToUse: win }); } }); @@ -862,7 +861,7 @@ export class WindowsManager implements IWindowsService { return null; } - let parsedPath: IParsedPath; + let parsedPath: IPathWithLineAndColumn; if (gotoLineMode) { parsedPath = parseLineAndColumnAware(anyPath); anyPath = parsedPath.path; @@ -1107,7 +1106,7 @@ export class WindowsManager implements IWindowsService { private doPickAndOpen(options: INativeOpenDialogOptions): void { this.getFileOrFolderPaths(options, (paths: string[]) => { if (paths && paths.length) { - this.open({ cli: this.envService.cliArgs, pathsToOpen: paths, forceNewWindow: options.forceNewWindow }); + this.open({ cli: this.environmentService.args, pathsToOpen: paths, forceNewWindow: options.forceNewWindow }); } }); } @@ -1213,7 +1212,7 @@ export class WindowsManager implements IWindowsService { } public openNewWindow(): void { - this.open({ cli: this.envService.cliArgs, forceNewWindow: true, forceEmpty: true }); + this.open({ cli: this.environmentService.args, forceNewWindow: true, forceEmpty: true }); } public sendToFocused(channel: string, ...args: any[]): void { diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index f3bb9a38948..97bf71f3c34 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -79,9 +79,12 @@ export class EnvironmentService implements IEnvironmentService { @memoize get extensionsPath(): string { return path.normalize(this._args.extensionHomePath || path.join(this.userHome, 'extensions')); } - get extensionDevelopmentPath(): string { return this._args.extensionDevelopmentPath; } + @memoize + get extensionDevelopmentPath(): string { return this._args.extensionDevelopmentPath ? path.normalize(this._args.extensionDevelopmentPath) : this._args.extensionDevelopmentPath; } + + @memoize + get extensionTestsPath(): string { return this._args.extensionTestsPath ? path.normalize(this._args.extensionTestsPath) : this._args.extensionTestsPath; } - get extensionTestsPath(): string { return this._args.extensionTestsPath; } get disableExtensions(): boolean { return this._args['disable-extensions']; } @memoize From 7e51cbe4d06305b9f4e63a2f605ae53cd502d3a9 Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Thu, 6 Oct 2016 14:20:03 +0200 Subject: [PATCH 094/163] rename EditorTabContext -> EditorTitleContext --- .../actions/browser/menusExtensionPoint.ts | 22 ++++---- src/vs/platform/actions/common/actions.ts | 6 +- .../browser/parts/editor/titleControl.ts | 56 +++++++++---------- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 40f51309200..d53beaea511 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -4,15 +4,15 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {createCSSRule} from 'vs/base/browser/dom'; -import {localize} from 'vs/nls'; -import {join} from 'vs/base/common/paths'; -import {IdGenerator} from 'vs/base/common/idGenerator'; -import {IJSONSchema} from 'vs/base/common/jsonSchema'; -import {forEach} from 'vs/base/common/collections'; -import {IExtensionPointUser, IExtensionMessageCollector, ExtensionsRegistry} from 'vs/platform/extensions/common/extensionsRegistry'; -import {ContextKeyExpr} from 'vs/platform/contextkey/common/contextkey'; -import {MenuId, MenuRegistry} from 'vs/platform/actions/common/actions'; +import { createCSSRule } from 'vs/base/browser/dom'; +import { localize } from 'vs/nls'; +import { join } from 'vs/base/common/paths'; +import { IdGenerator } from 'vs/base/common/idGenerator'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { forEach } from 'vs/base/common/collections'; +import { IExtensionPointUser, IExtensionMessageCollector, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; namespace schema { @@ -30,7 +30,7 @@ namespace schema { case 'editor/title': return MenuId.EditorTitle; case 'editor/context': return MenuId.EditorContext; case 'explorer/context': return MenuId.ExplorerContext; - case 'editor/title/context': return MenuId.EditorTabContext; + case 'editor/title/context': return MenuId.EditorTitleContext; } } @@ -211,7 +211,7 @@ ExtensionsRegistry.registerExtensionPoint) { + function handleCommand(userFriendlyCommand: schema.IUserFriendlyCommand, extension: IExtensionPointUser) { if (!schema.isValidCommand(userFriendlyCommand, extension.collector)) { return; diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 1474cd8a0a8..3458e1e1ad2 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -38,9 +38,9 @@ export interface IMenuItem { export enum MenuId { EditorTitle = 1, - EditorContext = 2, - ExplorerContext = 3, - EditorTabContext = 4, + EditorTitleContext = 2, + EditorContext = 3, + ExplorerContext = 4, ProblemsPanelContext = 5 } diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 6bbe529c0d5..2f64a824bfc 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -7,36 +7,36 @@ import 'vs/css!./media/titlecontrol'; import nls = require('vs/nls'); -import {Registry} from 'vs/platform/platform'; -import {Scope, IActionBarRegistry, Extensions, prepareActions} from 'vs/workbench/browser/actionBarRegistry'; -import {IAction, Action} from 'vs/base/common/actions'; +import { Registry } from 'vs/platform/platform'; +import { Scope, IActionBarRegistry, Extensions, prepareActions } from 'vs/workbench/browser/actionBarRegistry'; +import { IAction, Action } from 'vs/base/common/actions'; import errors = require('vs/base/common/errors'); import DOM = require('vs/base/browser/dom'); -import {TPromise} from 'vs/base/common/winjs.base'; -import {BaseEditor, IEditorInputActionContext} from 'vs/workbench/browser/parts/editor/baseEditor'; -import {RunOnceScheduler} from 'vs/base/common/async'; -import {isCommonCodeEditor, isCommonDiffEditor} from 'vs/editor/common/editorCommon'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { BaseEditor, IEditorInputActionContext } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import { isCommonCodeEditor, isCommonDiffEditor } from 'vs/editor/common/editorCommon'; import arrays = require('vs/base/common/arrays'); -import {IEditorStacksModel, IEditorGroup, IEditorIdentifier, EditorInput, IWorkbenchEditorConfiguration, IStacksModelChangeEvent, getResource} from 'vs/workbench/common/editor'; -import {EventType as BaseEventType} from 'vs/base/common/events'; -import {IActionItem, ActionsOrientation, Separator} from 'vs/base/browser/ui/actionbar/actionbar'; -import {ToolBar} from 'vs/base/browser/ui/toolbar/toolbar'; -import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; -import {IContextMenuService} from 'vs/platform/contextview/browser/contextView'; -import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; -import {IEditorGroupService} from 'vs/workbench/services/group/common/groupService'; -import {IMessageService, Severity} from 'vs/platform/message/common/message'; -import {StandardMouseEvent} from 'vs/base/browser/mouseEvent'; -import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; -import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; -import {IQuickOpenService} from 'vs/workbench/services/quickopen/common/quickOpenService'; -import {IKeybindingService} from 'vs/platform/keybinding/common/keybinding'; -import {IContextKeyService} from 'vs/platform/contextkey/common/contextkey'; -import {CloseEditorsInGroupAction, SplitEditorAction, CloseEditorAction, KeepEditorAction, CloseOtherEditorsInGroupAction, CloseRightEditorsInGroupAction, ShowEditorsInGroupAction} from 'vs/workbench/browser/parts/editor/editorActions'; -import {IDisposable, dispose} from 'vs/base/common/lifecycle'; -import {createActionItem, fillInActions} from 'vs/platform/actions/browser/menuItemActionItem'; -import {IMenuService, MenuId, IMenu} from 'vs/platform/actions/common/actions'; -import {ResourceContextKey} from 'vs/platform/actions/common/resourceContextKey'; +import { IEditorStacksModel, IEditorGroup, IEditorIdentifier, EditorInput, IWorkbenchEditorConfiguration, IStacksModelChangeEvent, getResource } from 'vs/workbench/common/editor'; +import { EventType as BaseEventType } from 'vs/base/common/events'; +import { IActionItem, ActionsOrientation, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import { IMessageService, Severity } from 'vs/platform/message/common/message'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { CloseEditorsInGroupAction, SplitEditorAction, CloseEditorAction, KeepEditorAction, CloseOtherEditorsInGroupAction, CloseRightEditorsInGroupAction, ShowEditorsInGroupAction } from 'vs/workbench/browser/parts/editor/editorActions'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { createActionItem, fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; +import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; +import { ResourceContextKey } from 'vs/platform/actions/common/resourceContextKey'; export interface IToolbarActions { primary: IAction[]; @@ -116,7 +116,7 @@ export abstract class TitleControl implements ITitleAreaControl { this.resourceContext = instantiationService.createInstance(ResourceContextKey); - this.contextMenu = this.menuService.createMenu(MenuId.EditorTabContext, this.contextKeyService); + this.contextMenu = this.menuService.createMenu(MenuId.EditorTitleContext, this.contextKeyService); this.toDispose.push(this.contextMenu); this.initActions(); From 55b734fd5622b0f2708c8ed01a0551392a890304 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2016 14:26:56 +0200 Subject: [PATCH 095/163] Implements #12756 --- .../electron-browser/dependenciesViewer.ts | 97 +++++++++++++++++++ .../electron-browser/extensionEditor.ts | 53 ++++++++-- .../extensions/electron-browser/extensions.ts | 9 ++ .../extensionsWorkbenchService.ts | 49 +++++++++- .../media/extensionEditor.css | 48 +++++++++ 5 files changed, 248 insertions(+), 8 deletions(-) create mode 100644 src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts diff --git a/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts b/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts new file mode 100644 index 00000000000..e80b99b3a88 --- /dev/null +++ b/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts @@ -0,0 +1,97 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as dom from 'vs/base/browser/dom'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { TPromise, Promise } from 'vs/base/common/winjs.base'; +import { IDataSource, ITree, IRenderer } from 'vs/base/parts/tree/browser/tree'; +import { IExtensionDependencies } from './extensions'; +import { once } from 'vs/base/common/event'; +import { domEvent } from 'vs/base/browser/event'; + +interface IExtensionTemplateData { + icon: HTMLImageElement; + name: HTMLElement; + identifier: HTMLElement; + author: HTMLElement; + extensionDisposables: IDisposable[]; +} + +export class DataSource implements IDataSource { + + public getId(tree: ITree, element: IExtensionDependencies): string { + let id = `${element.extension.publisher}.${element.extension.name}`; + this.getParent(tree, element).then(parent => { + id = parent ? this.getId(tree, parent) + '/' + id : id; + }); + return id; + } + + public hasChildren(tree: ITree, element: IExtensionDependencies): boolean { + return element.hasDependencies; + } + + public getChildren(tree: ITree, element: IExtensionDependencies): Promise { + return TPromise.as(element.dependencies); + } + + public getParent(tree: ITree, element: IExtensionDependencies): Promise { + return TPromise.as(element.dependent); + } +} + +export class Renderer implements IRenderer { + + private static EXTENSION_TEMPLATE_ID = 'extension-template'; + + public getHeight(tree: ITree, element: IExtensionDependencies): number { + return 62; + } + + public getTemplateId(tree: ITree, element: IExtensionDependencies): string { + return Renderer.EXTENSION_TEMPLATE_ID; + } + + public renderTemplate(tree: ITree, templateId: string, container: HTMLElement): any { + dom.addClass(container, 'dependency'); + + var data: IExtensionTemplateData = Object.create(null); + data.icon = dom.append(container, dom.$('img.icon')); + const details = dom.append(container, dom.$('.details')); + + const header = dom.append(details, dom.$('.header')); + data.name = dom.append(header, dom.$('span.name')); + data.identifier = dom.append(header, dom.$('span.identifier')); + + const footer = dom.append(details, dom.$('.footer')); + data.author = dom.append(footer, dom.$('.author')); + return data; + } + + + public renderElement(tree: ITree, element: IExtensionDependencies, templateId: string, templateData: any): void { + const extension = element.extension; + const data = templateData; + + const onError = once(domEvent(data.icon, 'error')); + onError(() => data.icon.src = extension.iconUrlFallback, null, data.extensionDisposables); + data.icon.src = extension.iconUrl; + + if (!data.icon.complete) { + data.icon.style.visibility = 'hidden'; + data.icon.onload = () => data.icon.style.visibility = 'inherit'; + } else { + data.icon.style.visibility = 'inherit'; + } + + data.name.textContent = extension.displayName; + data.identifier.textContent = `${extension.publisher}.${extension.name}`; + data.author.textContent = extension.publisherDisplayName; + } + + public disposeTemplate(tree: ITree, templateId: string, templateData: any): void { + (templateData).extensionDisposables = dispose((templateData).extensionDisposables); + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index f31ab5598ab..6d99400ec00 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -27,7 +27,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IExtensionGalleryService, IExtensionManifest, IKeyBinding } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IThemeService } from 'vs/workbench/services/themes/common/themeService'; import { ExtensionsInput } from './extensionsInput'; -import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension } from './extensions'; +import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension, IExtensionDependencies } from './extensions'; +import { Renderer, DataSource } from './dependenciesViewer'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITemplateData } from './extensionsList'; import { RatingsWidget, InstallWidget } from './extensionsWidgets'; @@ -42,6 +43,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { IMessageService } from 'vs/platform/message/common/message'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; function renderBody(body: string): string { return ` @@ -98,7 +100,8 @@ class NavBar { const NavbarSection = { Readme: 'readme', Contributions: 'contributions', - Changelog: 'changelog' + Changelog: 'changelog', + Dependencies: 'dependencies' }; interface ILayoutParticipant { @@ -127,6 +130,7 @@ export class ExtensionEditor extends BaseEditor { private extensionReadme: Cache; private extensionChangelog: Cache; private extensionManifest: Cache; + private extensionDependencies: Cache; private layoutParticipants: ILayoutParticipant[] = []; private contentDisposables: IDisposable[] = []; @@ -152,6 +156,7 @@ export class ExtensionEditor extends BaseEditor { this.extensionReadme = null; this.extensionChangelog = null; this.extensionManifest = null; + this.extensionDependencies = null; } createEditor(parent: Builder): void { @@ -205,6 +210,7 @@ export class ExtensionEditor extends BaseEditor { this.extensionReadme = new Cache(() => extension.getReadme()); this.extensionChangelog = new Cache(() => extension.getChangelog()); this.extensionManifest = new Cache(() => extension.getManifest()); + this.extensionDependencies = new Cache(() => this.extensionsWorkbenchService.loadDependencies(extension)); const onError = once(domEvent(this.icon, 'error')); onError(() => this.icon.src = extension.iconUrlFallback, null, this.transientDisposables); @@ -263,6 +269,9 @@ export class ExtensionEditor extends BaseEditor { if (extension.hasChangelog) { this.navbar.push(NavbarSection.Changelog, localize('changelog', "Changelog")); } + if (extension.hasDependencies) { + this.navbar.push(NavbarSection.Dependencies, localize('dependencies', "Dependencies")); + } this.content.innerHTML = ''; @@ -270,10 +279,13 @@ export class ExtensionEditor extends BaseEditor { } private onNavbarChange(extension: IExtension, id: string): void { + this.contentDisposables = dispose(this.contentDisposables); + this.content.innerHTML = ''; switch (id) { case NavbarSection.Readme: return this.openReadme(); case NavbarSection.Contributions: return this.openContributions(); case NavbarSection.Changelog: return this.openChangelog(); + case NavbarSection.Dependencies: return this.openDependencies(); } } @@ -311,8 +323,6 @@ export class ExtensionEditor extends BaseEditor { private openContributions() { return this.loadContents(() => this.extensionManifest.get() .then(manifest => { - this.content.innerHTML = ''; - const content = $('div', { class: 'subcontent' }); const scrollableContent = new DomScrollableElement(content, { canUseTranslate3d: false }); append(this.content, scrollableContent.getDomNode()); @@ -333,6 +343,38 @@ export class ExtensionEditor extends BaseEditor { })); } + private openDependencies() { + addClass(this.content, 'loading'); + this.extensionDependencies.get().then(extensionDependencies => { + removeClass(this.content, 'loading'); + + const content = $('div', { class: 'subcontent' }); + const scrollableContent = new DomScrollableElement(content, { canUseTranslate3d: false }); + append(this.content, scrollableContent.getDomNode()); + this.contentDisposables.push(scrollableContent); + + const layout = () => scrollableContent.scanDomNode(); + const removeLayoutParticipant = arrays.insert(this.layoutParticipants, { layout }); + this.contentDisposables.push(toDisposable(removeLayoutParticipant)); + + this.contentDisposables.push(ExtensionEditor.renderDependencies(content, extensionDependencies)); + scrollableContent.scanDomNode(); + }); + } + + private static renderDependencies(container: HTMLElement, extensionDependencies: IExtensionDependencies): Tree { + var renderer = new Renderer(); + const tree = new Tree(container, { + dataSource: new DataSource(), + renderer + }, { + indentPixels: 40, + twistiePixels: 20 + }); + tree.setInput(extensionDependencies); + return tree; + } + private static renderSettings(container: HTMLElement, manifest: IExtensionManifest, onDetailsToggle: Function): void { const contributes = manifest.contributes; const configuration = contributes && contributes.configuration; @@ -563,9 +605,6 @@ export class ExtensionEditor extends BaseEditor { } private loadContents(loadingTask: ()=>TPromise): void { - this.contentDisposables = dispose(this.contentDisposables); - - this.content.innerHTML = ''; addClass(this.content, 'loading'); let promise = loadingTask(); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts index b81ea2e821f..ae7a5c4200f 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts @@ -40,6 +40,7 @@ export interface IExtension { rating: number; ratingCount: number; outdated: boolean; + hasDependencies: boolean; telemetryData: any; getManifest(): TPromise; getReadme(): TPromise; @@ -47,6 +48,13 @@ export interface IExtension { getChangelog() : TPromise; } +export interface IExtensionDependencies { + dependencies: IExtensionDependencies[]; + hasDependencies: boolean; + extension: IExtension; + dependent: IExtensionDependencies; +} + export const SERVICE_ID = 'extensionsWorkbenchService'; export const IExtensionsWorkbenchService = createDecorator(SERVICE_ID); @@ -61,6 +69,7 @@ export interface IExtensionsWorkbenchService { install(vsix: string): TPromise; install(extension: IExtension, promptToInstallDependencies?: boolean): TPromise; uninstall(extension: IExtension): TPromise; + loadDependencies(extension: IExtension): TPromise; } export const ConfigurationKey = 'extensions'; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts index eefc3a990d1..2b164e0ebfe 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts @@ -9,6 +9,7 @@ import 'vs/css!./media/extensionsViewlet'; import { localize } from 'vs/nls'; import Event, { Emitter, chain } from 'vs/base/common/event'; import { index } from 'vs/base/common/arrays'; +import { LinkedMap as Map } from 'vs/base/common/map'; import { assign } from 'vs/base/common/objects'; import { isUUID } from 'vs/base/common/uuid'; import { ThrottledDelayer } from 'vs/base/common/async'; @@ -29,7 +30,7 @@ import * as path from 'path'; import URI from 'vs/base/common/uri'; import { readFile } from 'vs/base/node/pfs'; import { asText } from 'vs/base/node/request'; -import { IExtension, ExtensionState, IExtensionsWorkbenchService, IExtensionsConfiguration, ConfigurationKey } from './extensions'; +import { IExtension, IExtensionDependencies, ExtensionState, IExtensionsWorkbenchService, IExtensionsConfiguration, ConfigurationKey } from './extensions'; import { UpdateAllAction } from './extensionsActions'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; @@ -215,6 +216,35 @@ class Extension implements IExtension { return TPromise.wrapError('not available'); } + + get hasDependencies(): boolean { + const { local, gallery } = this; + if (gallery) { + return !!gallery.properties.dependencies.length; + } + return false; + } +} + +class ExtensionDependencies implements IExtensionDependencies { + + constructor(private _extension: Extension, private _map: Map, private _dependent: IExtensionDependencies = null) {} + + get hasDependencies(): boolean { + return this._extension.gallery.properties.dependencies.length > 0; + } + + get extension(): IExtension { + return this._extension; + } + + get dependent(): IExtensionDependencies { + return this._dependent; + } + + get dependencies(): IExtensionDependencies[] { + return this._extension.gallery.properties.dependencies.map(d => new ExtensionDependencies(this._map.get(d), this._map, this)); + } } function stripVersion(id: string): string { @@ -322,6 +352,23 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { }); } + loadDependencies(extension: IExtension): TPromise { + if (!extension.hasDependencies) { + return TPromise.wrap(null); + } + + return this.galleryService.getAllDependencies((extension).gallery) + .then(galleryExtensions => galleryExtensions.map(galleryExtension => this.fromGallery(galleryExtension))) + .then(extensions => { + const map = new Map(); + map.set(`${extension.publisher}.${extension.name}`, extension); + for (const extension of extensions) { + map.set(`${extension.publisher}.${extension.name}`, extension); + } + return new ExtensionDependencies(extension, map); + }); + } + private fromGallery(gallery: IGalleryExtension): Extension { const installedByGalleryId = index(this.installed, e => e.local.metadata ? e.local.metadata.id : ''); const id = gallery.id; diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css index ae447138055..b09e93bf6b8 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -212,4 +212,52 @@ background-color: rgba(128, 128, 128, 0.17); border-radius: 4px; padding: 1px 4px; +} + +.extension-editor .subcontent .monaco-tree-row .dependency { + display: flex; + align-items: center; +} + +.extension-editor .subcontent .monaco-tree-row .dependency > .details { + flex: 1; + overflow: hidden; + padding-left: 10px; +} + +.extension-editor .subcontent .monaco-tree-row .dependency > .details > .header { + display: flex; + align-items: baseline; + flex-wrap: wrap; + height: 19px; + overflow: hidden; +} + +.extension-editor .subcontent .monaco-tree-row .dependency > .icon { + height: 40px; + width: 40px; +} + +.extension-editor .subcontent .monaco-tree-row .dependency > .details > .header > .name { + font-weight: bold; + font-size: 16px; +} + +.extension-editor .subcontent .monaco-tree-row .dependency > .details > .header > .identifier { + font-size: 90%; + opacity: 0.6; + padding-left: 10px; +} + +.extension-editor .subcontent .monaco-tree-row .dependency > .details > .footer { + display: flex; + height: 19px; + overflow: hidden; + padding-top: 5px; +} + +.extension-editor .subcontent .monaco-tree-row .dependency > .details > .footer > .author { + font-size: 90%; + font-weight: 600; + opacity: 0.6; } \ No newline at end of file From 8ee72d2534396ec979894cb8610ac10bb2746676 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 6 Oct 2016 14:56:59 +0200 Subject: [PATCH 096/163] resolveEditorModel: dispose input after model is resolved --- .../services/editor/browser/editorService.ts | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 37021f28a3d..dd88f1f470a 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -107,7 +107,7 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { const schema = resourceInput.resource.scheme; if (schema === network.Schemas.http || schema === network.Schemas.https) { window.open(resourceInput.resource.toString(true)); - + return TPromise.as(null); } } @@ -198,12 +198,29 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { public resolveEditorModel(input: IEditorInput, refresh?: boolean): TPromise; public resolveEditorModel(input: IResourceInput, refresh?: boolean): TPromise; public resolveEditorModel(input: any, refresh?: boolean): TPromise { + let disposeInput = !(input instanceof EditorInput); // dispose input if we created it in here + return this.createInput(input).then(typedInput => { + let resolvePromise: TPromise; if (typedInput instanceof EditorInput) { - return typedInput.resolve(!!refresh); + resolvePromise = typedInput.resolve(!!refresh); + } else { + resolvePromise = TPromise.as(null); } - return TPromise.as(null); + return resolvePromise.then(model => { + if (disposeInput) { + typedInput.dispose(); + } + + return model; + }, error => { + if (disposeInput) { + typedInput.dispose(); + } + + return TPromise.wrapError(error); + }); }); } From 3abecd3e76dd78e7a55b68efae3bff9507d4effa Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 6 Oct 2016 15:40:46 +0200 Subject: [PATCH 097/163] Revert "resolveEditorModel: dispose input after model is resolved" This reverts commit 8ee72d2534396ec979894cb8610ac10bb2746676. --- .../services/editor/browser/editorService.ts | 23 +++---------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index dd88f1f470a..37021f28a3d 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -107,7 +107,7 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { const schema = resourceInput.resource.scheme; if (schema === network.Schemas.http || schema === network.Schemas.https) { window.open(resourceInput.resource.toString(true)); - + return TPromise.as(null); } } @@ -198,29 +198,12 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { public resolveEditorModel(input: IEditorInput, refresh?: boolean): TPromise; public resolveEditorModel(input: IResourceInput, refresh?: boolean): TPromise; public resolveEditorModel(input: any, refresh?: boolean): TPromise { - let disposeInput = !(input instanceof EditorInput); // dispose input if we created it in here - return this.createInput(input).then(typedInput => { - let resolvePromise: TPromise; if (typedInput instanceof EditorInput) { - resolvePromise = typedInput.resolve(!!refresh); - } else { - resolvePromise = TPromise.as(null); + return typedInput.resolve(!!refresh); } - return resolvePromise.then(model => { - if (disposeInput) { - typedInput.dispose(); - } - - return model; - }, error => { - if (disposeInput) { - typedInput.dispose(); - } - - return TPromise.wrapError(error); - }); + return TPromise.as(null); }); } From f7c3778223b104346dff8464fb55d4719f625953 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 6 Oct 2016 16:25:11 +0200 Subject: [PATCH 098/163] history: avoid typed input for recently closed editors (for #13283) --- .../browser/parts/editor/editorActions.ts | 12 +-- .../services/history/browser/history.ts | 95 ++++++++++--------- .../services/history/common/history.ts | 9 +- 3 files changed, 54 insertions(+), 62 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 3f7fe6457ed..52dd1060b64 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -924,17 +924,7 @@ export class ReopenClosedEditorAction extends Action { } public run(): TPromise { - const stacks = this.editorGroupService.getStacksModel(); - - // Find an editor that was closed and is currently not opened in the group - let lastClosedEditor = this.historyService.popLastClosedEditor(); - while (lastClosedEditor && stacks.activeGroup && stacks.activeGroup.indexOf(lastClosedEditor.editor) >= 0) { - lastClosedEditor = this.historyService.popLastClosedEditor(); - } - - if (lastClosedEditor) { - this.editorService.openEditor(lastClosedEditor.editor, { pinned: true, index: lastClosedEditor.index }); - } + this.historyService.reopenLastClosedEditor(); return TPromise.as(false); } diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index e9663b165e0..1e2afd4dbe5 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -8,12 +8,13 @@ import errors = require('vs/base/common/errors'); import platform = require('vs/base/common/platform'); import nls = require('vs/nls'); +import URI from 'vs/base/common/uri'; import product from 'vs/platform/product'; import {IEditor as IBaseEditor} from 'vs/platform/editor/common/editor'; -import {EditorInput, IGroupEvent, IEditorRegistry, Extensions} from 'vs/workbench/common/editor'; +import {EditorInput, IGroupEvent, IEditorRegistry, Extensions, asFileEditorInput, IEditorGroup} from 'vs/workbench/common/editor'; import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; -import {IRecentlyClosedEditor, IHistoryService} from 'vs/workbench/services/history/common/history'; +import {IHistoryService} from 'vs/workbench/services/history/common/history'; import {Selection} from 'vs/editor/common/core/selection'; import {IEditorInput, ITextEditorOptions} from 'vs/platform/editor/common/editor'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; @@ -225,6 +226,11 @@ interface IStackEntry { options?: ITextEditorOptions; } +interface IRecentlyClosedFile { + resource: URI; + index: number; +} + export class HistoryService extends BaseHistoryService implements IHistoryService { public _serviceBrand: any; @@ -240,7 +246,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic private currentFileEditorState: EditorState; private history: IEditorInput[]; - private recentlyClosed: IRecentlyClosedEditor[]; + private recentlyClosedFiles: IRecentlyClosedFile[]; private loaded: boolean; private registry: IEditorRegistry; @@ -258,7 +264,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic this.index = -1; this.stack = []; - this.recentlyClosed = []; + this.recentlyClosedFiles = []; this.loaded = false; this.registry = Registry.as(Extensions.Editors); @@ -275,31 +281,34 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic // Track closing of pinned editor to support to reopen closed editors if (event.pinned) { - const editor = this.restoreInput(event.editor); // closed editors are always disposed so we need to restore - if (editor) { + const fileEditor = asFileEditorInput(event.editor); // we only support files to reopen + if (fileEditor) { // Remove all inputs matching and add as last recently closed - this.removeFromRecentlyClosed(editor); - this.recentlyClosed.push({ editor, index: event.index }); + this.removeFromRecentlyClosedFiles(event.editor); + this.recentlyClosedFiles.push({ resource: fileEditor.getResource(), index: event.index }); // Bounding - if (this.recentlyClosed.length > HistoryService.MAX_RECENTLY_CLOSED_EDITORS) { - this.recentlyClosed.shift(); + if (this.recentlyClosedFiles.length > HistoryService.MAX_RECENTLY_CLOSED_EDITORS) { + this.recentlyClosedFiles.shift(); } - - // Restore on dispose - const onceDispose = once(editor.onDispose); - onceDispose(() => { - this.restoreInRecentlyClosed(editor); - }); } } } - public popLastClosedEditor(): IRecentlyClosedEditor { + public reopenLastClosedEditor(): void { this.ensureLoaded(); - return this.recentlyClosed.pop(); + const stacks = this.editorGroupService.getStacksModel(); + + let lastClosedFile = this.recentlyClosedFiles.pop(); + while (lastClosedFile && this.isFileOpened(lastClosedFile.resource, stacks.activeGroup)) { + lastClosedFile = this.recentlyClosedFiles.pop(); // pop until we find a file that is not opened + } + + if (lastClosedFile) { + this.editorService.openEditor({ resource: lastClosedFile.resource, options: { pinned: true, index: lastClosedFile.index } }); + } } public forward(): void { @@ -322,7 +331,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic this.index = -1; this.stack.splice(0); this.history = []; - this.recentlyClosed = []; + this.recentlyClosedFiles = []; } private navigate(): void { @@ -400,7 +409,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic public remove(input: IEditorInput): void { this.removeFromHistory(input); this.removeFromStack(input); - setTimeout(() => this.removeFromRecentlyClosed(input)); // race condition with editor close and dispose + this.removeFromRecentlyClosedFiles(input); } private removeFromHistory(input: IEditorInput, index?: number): void { @@ -571,26 +580,6 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic }); } - private restoreInRecentlyClosed(input: IEditorInput): void { - let restoredInput: EditorInput; - let restored = false; - - this.recentlyClosed.forEach((e, i) => { - if (e.editor.matches(input)) { - if (!restored) { - restoredInput = this.restoreInput(input); - restored = true; - } - - if (restoredInput) { - this.recentlyClosed[i].editor = restoredInput; - } else { - this.stack.splice(i, 1); - } - } - }); - } - private restoreInput(input: IEditorInput): EditorInput { if (input instanceof EditorInput) { const factory = this.registry.getEditorInputFactory(input.getTypeId()); @@ -616,14 +605,32 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic }); } - private removeFromRecentlyClosed(input: IEditorInput): void { - this.recentlyClosed.forEach((e, i) => { - if (e.editor.matches(input)) { - this.recentlyClosed.splice(i, 1); + private removeFromRecentlyClosedFiles(input: IEditorInput): void { + this.recentlyClosedFiles.forEach((e, i) => { + if (this.matchesFile(e.resource, input)) { + this.recentlyClosedFiles.splice(i, 1); } }); } + private isFileOpened(resource: URI, group: IEditorGroup): boolean { + if (!group) { + return false; + } + + if (!group.contains(resource)) { + return false; // fast check + } + + return group.getEditors().some(e => this.matchesFile(resource, e)); + } + + private matchesFile(resource: URI, input: IEditorInput): boolean { + const fileInput = asFileEditorInput(input); + + return fileInput && fileInput.getResource().toString() === resource.toString(); + } + public getHistory(): IEditorInput[] { this.ensureLoaded(); diff --git a/src/vs/workbench/services/history/common/history.ts b/src/vs/workbench/services/history/common/history.ts index a49e53e8b68..67d99afb0f9 100644 --- a/src/vs/workbench/services/history/common/history.ts +++ b/src/vs/workbench/services/history/common/history.ts @@ -9,19 +9,14 @@ import {IEditorInput, ITextEditorOptions} from 'vs/platform/editor/common/editor export const IHistoryService = createDecorator('historyService'); -export class IRecentlyClosedEditor { - editor: IEditorInput; - index: number; -} - export interface IHistoryService { _serviceBrand: ServiceIdentifier; /** - * Removes and returns the last closed editor if any. + * Re-opens the last closed editor if any. */ - popLastClosedEditor(): IRecentlyClosedEditor; + reopenLastClosedEditor(): void; /** * Add an entry to the navigation stack of the history. From 39020559949b17aa23d939a735bd7ea6344d205f Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2016 15:49:45 +0200 Subject: [PATCH 099/163] Gallery.loadDeps include self if it is a dep in hierarchy --- .../node/extensionGalleryService.ts | 10 ++++++---- .../node/extensionManagementService.ts | 11 +++++++---- .../electron-browser/extensionsWorkbenchService.ts | 1 - 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index ce726731b9f..2c8c4651fa6 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -390,8 +390,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { getAllDependencies(extension: IGalleryExtension): TPromise { return this.loadCompatibleVersion(extension) - .then(compatible => this.getDependenciesReccursively(compatible.properties.dependencies, [extension])) - .then(dependencies => dependencies.slice(1)); + .then(compatible => this.getDependenciesReccursively(compatible.properties.dependencies, [], extension)); } loadCompatibleVersion(extension: IGalleryExtension): TPromise { @@ -445,10 +444,13 @@ export class ExtensionGalleryService implements IExtensionGalleryService { }); } - private getDependenciesReccursively(toGet: string[], result: IGalleryExtension[]): TPromise { + private getDependenciesReccursively(toGet: string[], result: IGalleryExtension[], root: IGalleryExtension): TPromise { if (!toGet || !toGet.length) { return TPromise.wrap(result); } + if (toGet.indexOf(`${root.publisher}.${root.name}`) && result.indexOf(root) === -1) { + result.push(root); + } toGet = result.length ? toGet.filter(e => !ExtensionGalleryService.hasExtensionByName(result, e)) : toGet; if (!toGet.length) { return TPromise.wrap(result); @@ -464,7 +466,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { } result = distinct(result.concat(loadedDependencies), d => d.id); const dependencies = dependenciesSet.elements.filter(d => !ExtensionGalleryService.hasExtensionByName(result, d)); - return this.getDependenciesReccursively(dependencies, result); + return this.getDependenciesReccursively(dependencies, result, root); }); } diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 95594d97399..b7f58cb0976 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -202,7 +202,7 @@ export class ExtensionManagementService implements IExtensionManagementService { private installWithDependencies(extension: IGalleryExtension): TPromise { return this.galleryService.getAllDependencies(extension) - .then(allDependencies => this.filterOutInstalled(allDependencies)) + .then(allDependencies => this.filterDependenciesToInstall(extension, allDependencies)) .then(toInstall => this.filterObsolete(...toInstall.map(i => getExtensionId(i, i.version))) .then((obsolete) => { if (obsolete.length) { @@ -248,11 +248,14 @@ export class ExtensionManagementService implements IExtensionManagementService { .then(() => null); } - private filterOutInstalled(extensions: IGalleryExtension[]): TPromise { + private filterDependenciesToInstall(extension: IGalleryExtension, dependencies: IGalleryExtension[]): TPromise { return this.getInstalled() .then(local => { - return extensions.filter(extension => { - const extensionId = getExtensionId(extension, extension.version); + return dependencies.filter(d => { + if (extension.id === d.id) { + return false; + } + const extensionId = getExtensionId(d, d.version); return local.every(local => local.id !== extensionId); }); }); diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts index 2b164e0ebfe..918aafc03a1 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts @@ -361,7 +361,6 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { .then(galleryExtensions => galleryExtensions.map(galleryExtension => this.fromGallery(galleryExtension))) .then(extensions => { const map = new Map(); - map.set(`${extension.publisher}.${extension.name}`, extension); for (const extension of extensions) { map.set(`${extension.publisher}.${extension.name}`, extension); } From 8cb43c2a1144396f91d9ee16d7fe836b2078cb49 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2016 16:02:52 +0200 Subject: [PATCH 100/163] #12756 sytle identifier in the view --- .../extensions/electron-browser/media/extensionEditor.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css index b09e93bf6b8..c76b0ab7793 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -227,7 +227,7 @@ .extension-editor .subcontent .monaco-tree-row .dependency > .details > .header { display: flex; - align-items: baseline; + align-items: center; flex-wrap: wrap; height: 19px; overflow: hidden; @@ -246,7 +246,10 @@ .extension-editor .subcontent .monaco-tree-row .dependency > .details > .header > .identifier { font-size: 90%; opacity: 0.6; - padding-left: 10px; + margin-left: 10px; + background: rgba(173, 173, 173, 0.31); + padding: 0px 4px; + border-radius: 4px; } .extension-editor .subcontent .monaco-tree-row .dependency > .details > .footer { From 8b88c3ea2c564160aef25910ff133ac8b71f3157 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2016 16:29:54 +0200 Subject: [PATCH 101/163] Dependency viewer: fix wrapping --- .../electron-browser/dependenciesViewer.ts | 20 +++++++++++++++++++ .../electron-browser/extensionEditor.ts | 16 ++++++++++----- .../media/extensionEditor.css | 1 - 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts b/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts index e80b99b3a88..4184689bda9 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts @@ -5,8 +5,10 @@ import * as dom from 'vs/base/browser/dom'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { TPromise, Promise } from 'vs/base/common/winjs.base'; import { IDataSource, ITree, IRenderer } from 'vs/base/parts/tree/browser/tree'; +import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; import { IExtensionDependencies } from './extensions'; import { once } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; @@ -94,4 +96,22 @@ export class Renderer implements IRenderer { public disposeTemplate(tree: ITree, templateId: string, templateData: any): void { (templateData).extensionDisposables = dispose((templateData).extensionDisposables); } +} + +export class Controller extends DefaultController { + + protected onLeftClick(tree: ITree, element: IExtensionDependencies, event: IMouseEvent): boolean { + let currentFoucssed = tree.getFocus(); + if (super.onLeftClick(tree, element, event)) { + if (element.dependent === null) { + if (currentFoucssed) { + tree.setFocus(currentFoucssed); + } else { + tree.focusFirst(); + } + return true; + } + } + return false; + } } \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 6d99400ec00..32df1bc350b 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -28,7 +28,7 @@ import { IExtensionGalleryService, IExtensionManifest, IKeyBinding } from 'vs/pl import { IThemeService } from 'vs/workbench/services/themes/common/themeService'; import { ExtensionsInput } from './extensionsInput'; import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension, IExtensionDependencies } from './extensions'; -import { Renderer, DataSource } from './dependenciesViewer'; +import { Renderer, DataSource, Controller } from './dependenciesViewer'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITemplateData } from './extensionsList'; import { RatingsWidget, InstallWidget } from './extensionsWidgets'; @@ -353,20 +353,26 @@ export class ExtensionEditor extends BaseEditor { append(this.content, scrollableContent.getDomNode()); this.contentDisposables.push(scrollableContent); - const layout = () => scrollableContent.scanDomNode(); + const tree = ExtensionEditor.renderDependencies(content, extensionDependencies); + const layout = () => { + scrollableContent.scanDomNode(); + tree.layout(scrollableContent.getHeight()); + }; const removeLayoutParticipant = arrays.insert(this.layoutParticipants, { layout }); this.contentDisposables.push(toDisposable(removeLayoutParticipant)); - this.contentDisposables.push(ExtensionEditor.renderDependencies(content, extensionDependencies)); + this.contentDisposables.push(tree); scrollableContent.scanDomNode(); }); } private static renderDependencies(container: HTMLElement, extensionDependencies: IExtensionDependencies): Tree { - var renderer = new Renderer(); + const renderer = new Renderer(); + const controller = new Controller(); const tree = new Tree(container, { dataSource: new DataSource(), - renderer + renderer, + controller }, { indentPixels: 40, twistiePixels: 20 diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css index c76b0ab7793..2cad6cb9d06 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionEditor.css @@ -228,7 +228,6 @@ .extension-editor .subcontent .monaco-tree-row .dependency > .details > .header { display: flex; align-items: center; - flex-wrap: wrap; height: 19px; overflow: hidden; } From 4f9fe722c1fbe166c769b53eae7bf4064a176a7e Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 6 Oct 2016 16:39:03 +0200 Subject: [PATCH 102/163] Diff editor does not ask to save when closing (fixes #13095) --- src/vs/workbench/browser/parts/editor/editorPart.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 6a9ffe6df5d..91763e0466e 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -678,7 +678,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupService editors.push(editor.modifiedInput); } - return editors.reduce((prev, e) => prev += this.stacks.count(editor), 0); + return editors.reduce((prev, e) => prev += this.stacks.count(e), 0); } public getStacksModel(): EditorStacksModel { From 26f738171dbe3c6262f86431580670e12a1e1a95 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 6 Oct 2016 17:59:12 +0200 Subject: [PATCH 103/163] history: avoid typed input for editor navigation (for #13283) --- .../services/history/browser/history.ts | 87 ++++++++++--------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index 1e2afd4dbe5..e0ff2ef18e5 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -5,6 +5,7 @@ 'use strict'; +import {TPromise} from 'vs/base/common/winjs.base'; import errors = require('vs/base/common/errors'); import platform = require('vs/base/common/platform'); import nls = require('vs/nls'); @@ -16,7 +17,7 @@ import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor'; import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService'; import {IHistoryService} from 'vs/workbench/services/history/common/history'; import {Selection} from 'vs/editor/common/core/selection'; -import {IEditorInput, ITextEditorOptions} from 'vs/platform/editor/common/editor'; +import {IEditorInput, ITextEditorOptions, IResourceInput} from 'vs/platform/editor/common/editor'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IDisposable, dispose} from 'vs/base/common/lifecycle'; import {IStorageService, StorageScope} from 'vs/platform/storage/common/storage'; @@ -222,7 +223,7 @@ export abstract class BaseHistoryService { } interface IStackEntry { - input: IEditorInput; + input: IEditorInput|IResourceInput; options?: ITextEditorOptions; } @@ -335,9 +336,9 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic } private navigate(): void { - const state = this.stack[this.index]; + const entry = this.stack[this.index]; - let options = state.options; + let options = entry.options; if (options) { options.revealIfVisible = true; } else { @@ -345,7 +346,16 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic } this.blockStackChanges = true; - this.editorService.openEditor(state.input, options).done(() => { + + let openEditorPromise: TPromise; + if (entry.input instanceof EditorInput) { + openEditorPromise = this.editorService.openEditor(entry.input, options); + } else { + const resourceInput = entry.input as IResourceInput; + openEditorPromise = this.editorService.openEditor({ resource: resourceInput.resource, options }); + } + + openEditorPromise.done(() => { this.blockStackChanges = false; }, (error) => { this.blockStackChanges = false; @@ -472,7 +482,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic private handleNonTextEditorEvent(editor: IBaseEditor): void { const currentStack = this.stack[this.index]; - if (currentStack && currentStack.input.matches(editor.input)) { + if (currentStack && this.matches(editor.input, currentStack.input)) { return; // do not push same editor input again } @@ -493,15 +503,13 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic let replace = false; if (this.stack[this.index]) { const currentEntry = this.stack[this.index]; - if (currentEntry.input.matches(input) && this.sameOptions(currentEntry.options, options)) { + if (this.matches(input, currentEntry.input) && this.sameOptions(currentEntry.options, options)) { replace = true; } } - const entry = { - input, - options - }; + const stackInput = this.preferResourceInput(input); + const entry = { input: stackInput, options }; // If we are not at the end of history, we remove anything after if (this.stack.length > this.index + 1) { @@ -527,11 +535,23 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic } } - // Restore on dispose - const onceDispose = once(input.onDispose); - onceDispose(() => { - this.restoreInStack(input); - }); + // Remove this from the stack unless the stack input is a resource + // that can easily be restored even when the input gets disposed + if (stackInput instanceof EditorInput) { + const onceDispose = once(stackInput.onDispose); + onceDispose(() => { + this.removeFromStack(input); + }); + } + } + + private preferResourceInput(input: IEditorInput): IEditorInput|IResourceInput { + const fileInput = asFileEditorInput(input); + if (fileInput) { + return { resource: fileInput.getResource() }; + } + + return input; } private sameOptions(optionsA?: ITextEditorOptions, optionsB?: ITextEditorOptions): boolean { @@ -557,29 +577,6 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic return s1.startLineNumber === s2.startLineNumber; // we consider the history entry same if we are on the same line } - private restoreInStack(input: IEditorInput): void { - let restoredInput: EditorInput; - let restored = false; - - this.stack.forEach((e, i) => { - if (e.input.matches(input)) { - if (!restored) { - restoredInput = this.restoreInput(input); - restored = true; - } - - if (restoredInput) { - this.stack[i].input = restoredInput; - } else { - this.stack.splice(i, 1); - if (this.index >= i) { - this.index--; // reduce index if the element is before index - } - } - } - }); - } - private restoreInput(input: IEditorInput): EditorInput { if (input instanceof EditorInput) { const factory = this.registry.getEditorInputFactory(input.getTypeId()); @@ -596,7 +593,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic private removeFromStack(input: IEditorInput): void { this.stack.forEach((e, i) => { - if (e.input.matches(input)) { + if (this.matches(input, e.input)) { this.stack.splice(i, 1); if (this.index >= i) { this.index--; // reduce index if the element is before index @@ -625,6 +622,16 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic return group.getEditors().some(e => this.matchesFile(resource, e)); } + private matches(typedInput: IEditorInput, input: IEditorInput|IResourceInput): boolean { + if (input instanceof EditorInput) { + return input.matches(typedInput); + } + + const resourceInput = input as IResourceInput; + + return this.matchesFile(resourceInput.resource, typedInput); + } + private matchesFile(resource: URI, input: IEditorInput): boolean { const fileInput = asFileEditorInput(input); From f498f7dfa5d2e40d1f66891b7f1202b7c8a5d19a Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2016 17:47:27 +0200 Subject: [PATCH 104/163] Extension: Make open extension a service --- .../extensions/electron-browser/extensionsViewlet.ts | 7 +------ .../electron-browser/extensionsWorkbenchService.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 563664eed0c..8aa56caa2ed 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -116,7 +116,7 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { chain(this.list.onSelectionChange) .map(e => e.elements[0]) .filter(e => !!e) - .on(this.openExtension, this, this.disposables); + .on(this.extensionsWorkbenchService.open, this, this.disposables); return TPromise.as(null); } @@ -296,11 +296,6 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { .then(result => new PagedModel(result)); } - private openExtension(extension: IExtension): void { - this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension)) - .done(null, err => this.onError(err)); - } - private onEnter(): void { this.list.setSelection(...this.list.getFocus()); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts index 918aafc03a1..1f7616f5410 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts @@ -368,6 +368,11 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { }); } + open(extension: IExtension): void { + this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension)) + .done(null, err => this.onError(err)); + } + private fromGallery(gallery: IGalleryExtension): Extension { const installedByGalleryId = index(this.installed, e => e.local.metadata ? e.local.metadata.id : ''); const id = gallery.id; @@ -620,15 +625,10 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } const extension = result.firstPage[0]; - this.openExtension(extension); + this.open(extension); }); } - private openExtension(extension: IExtension): void { - this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension)) - .done(null, err => this.onError(err)); - } - dispose(): void { this.disposables = dispose(this.disposables); } From af98e43c377af074cefe752b1bed4e10debdcba9 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2016 18:04:18 +0200 Subject: [PATCH 105/163] Dependencies view: Open extension --- .../electron-browser/dependenciesViewer.ts | 84 ++++++++++++++++++- .../electron-browser/extensionEditor.ts | 6 +- .../extensions/electron-browser/extensions.ts | 1 + 3 files changed, 86 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts b/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts index 4184689bda9..09ad615d600 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts @@ -4,14 +4,21 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; +import { localize } from 'vs/nls'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { TPromise, Promise } from 'vs/base/common/winjs.base'; -import { IDataSource, ITree, IRenderer } from 'vs/base/parts/tree/browser/tree'; +import { IDataSource, ITree, IRenderer, ContextMenuEvent } from 'vs/base/parts/tree/browser/tree'; import { DefaultController } from 'vs/base/parts/tree/browser/treeDefaults'; -import { IExtensionDependencies } from './extensions'; +import { Action } from 'vs/base/common/actions'; +import { IExtensionDependencies, IExtensionsWorkbenchService, IExtension } from './extensions'; import { once } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; +import { Keybinding } from 'vs/base/common/keybinding'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; interface IExtensionTemplateData { icon: HTMLImageElement; @@ -100,6 +107,12 @@ export class Renderer implements IRenderer { export class Controller extends DefaultController { + constructor(@IContextMenuService private contextMenuService: IContextMenuService, + @IExtensionsWorkbenchService private extensionWorkbenchService: IExtensionsWorkbenchService, + @IInstantiationService private instantiationService: IInstantiationService) { + super(); + } + protected onLeftClick(tree: ITree, element: IExtensionDependencies, event: IMouseEvent): boolean { let currentFoucssed = tree.getFocus(); if (super.onLeftClick(tree, element, event)) { @@ -114,4 +127,71 @@ export class Controller extends DefaultController { } return false; } + + public onContextMenu(tree: ITree, element: any, event: ContextMenuEvent): boolean { + tree.setFocus(element); + const anchor = { x: event.posx + 1, y: event.posy }; + this.contextMenuService.showContextMenu({ + getAnchor: () => anchor, + + getActions: () => { + return TPromise.as([this.instantiationService.createInstance(OpenExtensionAction)]); + }, + + getActionItem: () => null, + + getKeyBinding: (action): Keybinding => { + return this.keybindingForAction(action.id); + }, + + getActionsContext: (event) => { + return { + extension: (tree.getFocus()).extension + }; + }, + + onHide: (wasCancelled?: boolean) => { + if (wasCancelled) { + tree.DOMFocus(); + } + } + }); + + return true; + } + + protected onEnter(tree: ITree, event: IKeyboardEvent): boolean { + if (super.onEnter(tree, event)) { + return this.openExtension(tree.getFocus()); + } + return false; + } + + private openExtension(element: IExtensionDependencies, sideByside: boolean = false): boolean { + this.extensionWorkbenchService.open(element.extension); + return true; + } + + private keybindingForAction(id: string): Keybinding { + switch (id) { + case OpenExtensionAction.ID: + return new Keybinding(KeyCode.Enter); + } + + return null; + } +} + +class OpenExtensionAction extends Action { + + public static ID = 'extensions.open.extension'; + + constructor(@IExtensionsWorkbenchService private extensionsWorkdbenchService: IExtensionsWorkbenchService) { + super('extensions.open.extension', localize('extensions.open', "Open")); + } + + run(context: { extension: IExtension, sideByside?: boolean }): TPromise { + this.extensionsWorkdbenchService.open(context.extension); + return TPromise.as(null); + } } \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts index 32df1bc350b..a1ac76694c5 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionEditor.ts @@ -353,7 +353,7 @@ export class ExtensionEditor extends BaseEditor { append(this.content, scrollableContent.getDomNode()); this.contentDisposables.push(scrollableContent); - const tree = ExtensionEditor.renderDependencies(content, extensionDependencies); + const tree = ExtensionEditor.renderDependencies(content, extensionDependencies, this.instantiationService); const layout = () => { scrollableContent.scanDomNode(); tree.layout(scrollableContent.getHeight()); @@ -366,9 +366,9 @@ export class ExtensionEditor extends BaseEditor { }); } - private static renderDependencies(container: HTMLElement, extensionDependencies: IExtensionDependencies): Tree { + private static renderDependencies(container: HTMLElement, extensionDependencies: IExtensionDependencies, instantiationService: IInstantiationService): Tree { const renderer = new Renderer(); - const controller = new Controller(); + const controller = instantiationService.createInstance(Controller); const tree = new Tree(container, { dataSource: new DataSource(), renderer, diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts index ae7a5c4200f..6747f7e22ca 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts @@ -70,6 +70,7 @@ export interface IExtensionsWorkbenchService { install(extension: IExtension, promptToInstallDependencies?: boolean): TPromise; uninstall(extension: IExtension): TPromise; loadDependencies(extension: IExtension): TPromise; + open(extension: IExtension): void; } export const ConfigurationKey = 'extensions'; From afbba4816da897f139ddbacf96c7ff1ce27e21e0 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2016 18:39:24 +0200 Subject: [PATCH 106/163] Dependency view: Open extension to the side --- .../electron-browser/dependenciesViewer.ts | 46 +++++++++++++++---- .../extensions/electron-browser/extensions.ts | 2 +- .../extensionsWorkbenchService.ts | 4 +- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts b/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts index 09ad615d600..7c854c5c8af 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/dependenciesViewer.ts @@ -17,8 +17,10 @@ import { domEvent } from 'vs/base/browser/event'; import { Keybinding } from 'vs/base/common/keybinding'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { KeyCode } from 'vs/base/common/keyCodes'; +import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { Position } from 'vs/platform/editor/common/editor'; interface IExtensionTemplateData { icon: HTMLImageElement; @@ -111,6 +113,8 @@ export class Controller extends DefaultController { @IExtensionsWorkbenchService private extensionWorkbenchService: IExtensionsWorkbenchService, @IInstantiationService private instantiationService: IInstantiationService) { super(); + + this.downKeyBindingDispatcher.set(OpenExtensionToSideAction.KEY_BINDING.value, (tree: ITree, event: any) => { this.openExtension(tree.getFocus(), true); }); } protected onLeftClick(tree: ITree, element: IExtensionDependencies, event: IMouseEvent): boolean { @@ -135,7 +139,8 @@ export class Controller extends DefaultController { getAnchor: () => anchor, getActions: () => { - return TPromise.as([this.instantiationService.createInstance(OpenExtensionAction)]); + return TPromise.as([this.instantiationService.createInstance(OpenExtensionAction), + this.instantiationService.createInstance(OpenExtensionToSideAction)]); }, getActionItem: () => null, @@ -162,20 +167,22 @@ export class Controller extends DefaultController { protected onEnter(tree: ITree, event: IKeyboardEvent): boolean { if (super.onEnter(tree, event)) { - return this.openExtension(tree.getFocus()); + return this.openExtension(tree.getFocus(), event.ctrlKey || event.metaKey); } return false; } private openExtension(element: IExtensionDependencies, sideByside: boolean = false): boolean { - this.extensionWorkbenchService.open(element.extension); + this.extensionWorkbenchService.open(element.extension, sideByside); return true; } private keybindingForAction(id: string): Keybinding { switch (id) { case OpenExtensionAction.ID: - return new Keybinding(KeyCode.Enter); + return OpenExtensionAction.KEY_BINDING; + case OpenExtensionToSideAction.ID: + return OpenExtensionToSideAction.KEY_BINDING; } return null; @@ -184,14 +191,37 @@ export class Controller extends DefaultController { class OpenExtensionAction extends Action { - public static ID = 'extensions.open.extension'; + public static ID = 'extensions.action.open'; + public static KEY_BINDING = new Keybinding(KeyCode.Enter); constructor(@IExtensionsWorkbenchService private extensionsWorkdbenchService: IExtensionsWorkbenchService) { - super('extensions.open.extension', localize('extensions.open', "Open")); + super(OpenExtensionAction.ID, localize('extensions.open', "Open")); } - run(context: { extension: IExtension, sideByside?: boolean }): TPromise { + run(context: { extension: IExtension }): TPromise { this.extensionsWorkdbenchService.open(context.extension); return TPromise.as(null); } +} + +class OpenExtensionToSideAction extends Action { + + public static ID = 'extensions.action.openSide'; + public static KEY_BINDING = new Keybinding(KeyMod.WinCtrl | KeyCode.Enter); + + constructor(@IExtensionsWorkbenchService private extensionsWorkdbenchService: IExtensionsWorkbenchService, + @IWorkbenchEditorService private editorService: IWorkbenchEditorService) { + super(OpenExtensionToSideAction.ID, localize('extensions.openSide', "Open to the Side")); + this.updateEnablement(); + } + + private updateEnablement(): void { + const activeEditor = this.editorService.getActiveEditor(); + this.enabled = (!activeEditor || activeEditor.position !== Position.RIGHT); + } + + run(context: { extension: IExtension }): TPromise { + this.extensionsWorkdbenchService.open(context.extension, true); + return TPromise.as(null); + } } \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts index 6747f7e22ca..1abe44f0318 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts @@ -70,7 +70,7 @@ export interface IExtensionsWorkbenchService { install(extension: IExtension, promptToInstallDependencies?: boolean): TPromise; uninstall(extension: IExtension): TPromise; loadDependencies(extension: IExtension): TPromise; - open(extension: IExtension): void; + open(extension: IExtension, sideByside?: boolean): void; } export const ConfigurationKey = 'extensions'; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts index 1f7616f5410..72e19184034 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts @@ -368,8 +368,8 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { }); } - open(extension: IExtension): void { - this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension)) + open(extension: IExtension, sideByside: boolean = false): void { + this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension), null, sideByside) .done(null, err => this.onError(err)); } From e24a82b3ef7af1e58f3d8795b3cefda8dd678b22 Mon Sep 17 00:00:00 2001 From: Sandeep Somavarapu Date: Thu, 6 Oct 2016 18:56:36 +0200 Subject: [PATCH 107/163] ExtensionWorkbenchService.open return promise --- .../parts/extensions/electron-browser/extensions.ts | 2 +- .../parts/extensions/electron-browser/extensionsViewlet.ts | 6 +++++- .../electron-browser/extensionsWorkbenchService.ts | 7 +++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts index 1abe44f0318..b1c28084987 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.ts @@ -70,7 +70,7 @@ export interface IExtensionsWorkbenchService { install(extension: IExtension, promptToInstallDependencies?: boolean): TPromise; uninstall(extension: IExtension): TPromise; loadDependencies(extension: IExtension): TPromise; - open(extension: IExtension, sideByside?: boolean): void; + open(extension: IExtension, sideByside?: boolean): TPromise; } export const ConfigurationKey = 'extensions'; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 8aa56caa2ed..5bbff76ef67 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -116,7 +116,7 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { chain(this.list.onSelectionChange) .map(e => e.elements[0]) .filter(e => !!e) - .on(this.extensionsWorkbenchService.open, this, this.disposables); + .on(this.openExtension, this, this.disposables); return TPromise.as(null); } @@ -296,6 +296,10 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { .then(result => new PagedModel(result)); } + private openExtension(extension: IExtension): void { + this.extensionsWorkbenchService.open(extension).done(null, err => this.onError(err)); + } + private onEnter(): void { this.list.setSelection(...this.list.getFocus()); } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts index 72e19184034..a2ef221cb77 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts @@ -368,9 +368,8 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { }); } - open(extension: IExtension, sideByside: boolean = false): void { - this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension), null, sideByside) - .done(null, err => this.onError(err)); + open(extension: IExtension, sideByside: boolean = false): TPromise { + return this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension), null, sideByside); } private fromGallery(gallery: IGalleryExtension): Extension { @@ -625,7 +624,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } const extension = result.firstPage[0]; - this.open(extension); + this.open(extension).done(null, error => this.onError(error)); }); } From 7e4d966c0947e9b57788d8a31fcc0e4d714969e2 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Thu, 6 Oct 2016 10:28:21 -0700 Subject: [PATCH 108/163] Pass exact path matches to find (#12743) --- src/vs/base/common/glob.ts | 49 ++++++++------- src/vs/base/test/common/glob.test.ts | 60 ++++++++++--------- .../services/search/node/fileSearch.ts | 16 ++--- .../services/search/test/node/search.test.ts | 30 +++++++++- 4 files changed, 93 insertions(+), 62 deletions(-) diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index 8ea9941c5c1..61c28a4a77e 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -214,6 +214,7 @@ const T2 = /^\*\*\/([\w\.-]+)\/?$/; // **/something const T3 = /^{\*\*\/[\*\.]?[\w\.-]+\/?(,\*\*\/[\*\.]?[\w\.-]+\/?)*}$/; // {**/*.something,**/*.else} or {**/package.json,**/project.json} const T3_2 = /^{\*\*\/[\*\.]?[\w\.-]+(\/(\*\*)?)?(,\*\*\/[\*\.]?[\w\.-]+(\/(\*\*)?)?)*}$/; // Like T3, with optional trailing /** const T4 = /^\*\*((\/[\w\.-]+)+)\/?$/; // **/something/else +const T5 = /^([\w\.-]+(\/[\w\.-]+)*)\/?$/; // something/else export type ParsedPattern = (path: string, basename?: string) => boolean; export type ParsedExpression = (path: string, basename?: string, siblingsFn?: () => string[]) => string /* the matching pattern */; @@ -227,14 +228,14 @@ interface ParsedStringPattern { basenames?: string[]; patterns?: string[]; allBasenames?: string[]; - allPathEnds?: string[]; + allPaths?: string[]; } type SiblingsPattern = { siblings: string[], name: string }; interface ParsedExpressionPattern { (path: string, basename: string, siblingsPatternFn: () => SiblingsPattern): string /* the matching pattern */; requiresSiblings?: boolean; allBasenames?: string[]; - allPathEnds?: string[]; + allPaths?: string[]; } const CACHE = new BoundedLinkedMap(10000); // bounded to 10000 elements @@ -274,7 +275,9 @@ function parsePattern(pattern: string, options: IGlobOptions): ParsedStringPatte } else if ((options.trimForExclusions ? T3_2 : T3).test(pattern)) { // repetition of common patterns (see above) {**/*.txt,**/*.png} parsedPattern = trivia3(pattern, options); } else if (match = T4.exec(trimForExclusions(pattern, options))) { // common pattern: **/something/else just need endsWith check - parsedPattern = trivia4(match[1], pattern); + parsedPattern = trivia4and5(match[1].substr(1), pattern, true); + } else if (match = T5.exec(trimForExclusions(pattern, options))) { // common pattern: something/else just need equals check + parsedPattern = trivia4and5(match[1], pattern, false); } // Otherwise convert to pattern @@ -336,21 +339,23 @@ function trivia3 (pattern: string, options: IGlobOptions): ParsedStringPattern { if (withBasenames) { parsedPattern.allBasenames = (withBasenames).allBasenames; } - const allPathEnds = parsedPatterns.reduce((all, current) => current.allPathEnds ? all.concat(current.allPathEnds) : all, []); - if (allPathEnds.length) { - parsedPattern.allPathEnds = allPathEnds; + const allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, []); + if (allPaths.length) { + parsedPattern.allPaths = allPaths; } return parsedPattern; } -// common pattern: **/something/else just need endsWith check -function trivia4(pathEnd: string, pattern: string): ParsedStringPattern { - const nativePathEnd = pathEnd.replace(paths.sep, paths.nativeSep); - const nativePath = nativePathEnd.substr(1); - const parsedPattern: ParsedStringPattern = function (path, basename) { +// common patterns: **/something/else just need endsWith check, something/else just needs and equals check +function trivia4and5(path: string, pattern: string, matchPathEnds: boolean): ParsedStringPattern { + const nativePath = path.replace(paths.sep, paths.nativeSep); + const nativePathEnd = paths.nativeSep + nativePath; + const parsedPattern: ParsedStringPattern = matchPathEnds ? function (path, basename) { return path && (path === nativePath || strings.endsWith(path, nativePathEnd)) ? pattern : null; + } : function (path, basename) { + return path && path === nativePath ? pattern : null; }; - parsedPattern.allPathEnds = [pathEnd]; + parsedPattern.allPaths = [(matchPathEnds ? '*/' : './') + path]; return parsedPattern; } @@ -411,8 +416,8 @@ export function parse(arg1: string | IExpression, options: IGlobOptions = {}): a if (parsedPattern.allBasenames) { (resultPattern).allBasenames = parsedPattern.allBasenames; } - if (parsedPattern.allPathEnds) { - (resultPattern).allPathEnds = parsedPattern.allPathEnds; + if (parsedPattern.allPaths) { + (resultPattern).allPaths = parsedPattern.allPaths; } return resultPattern; } @@ -425,8 +430,8 @@ export function getBasenameTerms(patternOrExpression: ParsedPattern | ParsedExpr return (patternOrExpression).allBasenames || []; } -export function getPathEndTerms(patternOrExpression: ParsedPattern | ParsedExpression): string[] { - return (patternOrExpression).allPathEnds || []; +export function getPathTerms(patternOrExpression: ParsedPattern | ParsedExpression): string[] { + return (patternOrExpression).allPaths || []; } function parsedExpression(expression: IExpression, options: IGlobOptions): ParsedExpression { @@ -461,9 +466,9 @@ function parsedExpression(expression: IExpression, options: IGlobOptions): Parse resultExpression.allBasenames = (withBasenames).allBasenames; } - const allPathEnds = parsedPatterns.reduce((all, current) => current.allPathEnds ? all.concat(current.allPathEnds) : all, []); - if (allPathEnds.length) { - resultExpression.allPathEnds = allPathEnds; + const allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, []); + if (allPaths.length) { + resultExpression.allPaths = allPaths; } return resultExpression; @@ -505,9 +510,9 @@ function parsedExpression(expression: IExpression, options: IGlobOptions): Parse resultExpression.allBasenames = (withBasenames).allBasenames; } - const allPathEnds = parsedPatterns.reduce((all, current) => current.allPathEnds ? all.concat(current.allPathEnds) : all, []); - if (allPathEnds.length) { - resultExpression.allPathEnds = allPathEnds; + const allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, []); + if (allPaths.length) { + resultExpression.allPaths = allPaths; } return resultExpression; diff --git a/src/vs/base/test/common/glob.test.ts b/src/vs/base/test/common/glob.test.ts index a085b05005a..c587290e236 100644 --- a/src/vs/base/test/common/glob.test.ts +++ b/src/vs/base/test/common/glob.test.ts @@ -5,6 +5,7 @@ 'use strict'; import * as assert from 'assert'; +import * as path from 'path'; import glob = require('vs/base/common/glob'); suite('Glob', () => { @@ -460,12 +461,10 @@ suite('Glob', () => { assert(glob.match(p, 'foo.f')); }); - test('backslash agnostic', function () { + test('full path', function () { var p = 'testing/this/foo.txt'; - assert(glob.match(p, 'testing/this/foo.txt')); - assert(glob.match(p, 'testing\\this\\foo.txt')); - assert(glob.match(p, 'testing/this\\foo.txt')); + assert(glob.match(p, 'testing/this/foo.txt'.replace('/', path.sep))); }); test('prefix agnostic', function () { @@ -772,7 +771,7 @@ suite('Glob', () => { assert.strictEqual(glob.parse('{**/foo/,**/abc/}', { trimForExclusions: true })('bar/abc', 'abc'), true); }); - test('expression/pattern path end', function () { + test('expression/pattern path', function () { assert.strictEqual(glob.parse('**/foo/bar')('foo/baz', 'baz'), false); assert.strictEqual(glob.parse('**/foo/bar')('foo/bar', 'bar'), true); assert.strictEqual(glob.parse('**/foo/bar')('bar/foo/bar', 'bar'), true); @@ -780,16 +779,23 @@ suite('Glob', () => { assert.strictEqual(glob.parse('**/foo/bar/**')('bar/foo/bar/baz', 'baz'), true); assert.strictEqual(glob.parse('**/foo/bar/**', { trimForExclusions: true })('bar/foo/bar', 'bar'), true); assert.strictEqual(glob.parse('**/foo/bar/**', { trimForExclusions: true })('bar/foo/bar/baz', 'baz'), false); + + assert.strictEqual(glob.parse('foo/bar')('foo/baz', 'baz'), false); + assert.strictEqual(glob.parse('foo/bar')('foo/bar', 'bar'), true); + assert.strictEqual(glob.parse('foo/bar')('bar/foo/bar', 'bar'), false); + assert.strictEqual(glob.parse('foo/bar/**')('foo/bar/baz', 'baz'), true); + assert.strictEqual(glob.parse('foo/bar/**', { trimForExclusions: true })('foo/bar', 'bar'), true); + assert.strictEqual(glob.parse('foo/bar/**', { trimForExclusions: true })('foo/bar/baz', 'baz'), false); }); - test('expression/pattern path ends', function () { - assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/*.foo')), []); - assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/foo')), []); - assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/foo/bar')), ['/foo/bar']); - assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/foo/bar/')), ['/foo/bar']); + test('expression/pattern paths', function () { + assert.deepStrictEqual(glob.getPathTerms(glob.parse('**/*.foo')), []); + assert.deepStrictEqual(glob.getPathTerms(glob.parse('**/foo')), []); + assert.deepStrictEqual(glob.getPathTerms(glob.parse('**/foo/bar')), ['*/foo/bar']); + assert.deepStrictEqual(glob.getPathTerms(glob.parse('**/foo/bar/')), ['*/foo/bar']); // Not supported - // assert.deepStrictEqual(glob.getNativePathEnds(glob.parse('{**/baz/bar,**/foo/bar,**/bar}')), ['/baz/bar', '/foo/bar']); - // assert.deepStrictEqual(glob.getNativePathEnds(glob.parse('{**/baz/bar/,**/foo/bar/,**/bar/}')), ['/baz/bar', '/foo/bar']); + // assert.deepStrictEqual(glob.getPathTerms(glob.parse('{**/baz/bar,**/foo/bar,**/bar}')), ['*/baz/bar', '*/foo/bar']); + // assert.deepStrictEqual(glob.getPathTerms(glob.parse('{**/baz/bar/,**/foo/bar/,**/bar/}')), ['*/baz/bar', '*/foo/bar']); const parsed = glob.parse({ '**/foo/bar': true, @@ -801,30 +807,30 @@ suite('Glob', () => { '**/bulb2': true, '**/bulb/foo': false }); - assert.deepStrictEqual(glob.getPathEndTerms(parsed), ['/foo/bar', '/foo2/bar2']); + assert.deepStrictEqual(glob.getPathTerms(parsed), ['*/foo/bar', '*/foo2/bar2']); assert.deepStrictEqual(glob.getBasenameTerms(parsed), ['bulb', 'bulb2']); - assert.deepStrictEqual(glob.getPathEndTerms(glob.parse({ + assert.deepStrictEqual(glob.getPathTerms(glob.parse({ '**/foo/bar': { when: '$(basename).zip' }, '**/bar/foo': true, '**/bar2/foo2': true - })), ['/bar/foo', '/bar2/foo2']); + })), ['*/bar/foo', '*/bar2/foo2']); }); - test('expression/pattern optimization for path ends', function () { - assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/foo/bar/**')), []); - assert.deepStrictEqual(glob.getPathEndTerms(glob.parse('**/foo/bar/**', { trimForExclusions: true })), ['/foo/bar']); + test('expression/pattern optimization for paths', function () { + assert.deepStrictEqual(glob.getPathTerms(glob.parse('**/foo/bar/**')), []); + assert.deepStrictEqual(glob.getPathTerms(glob.parse('**/foo/bar/**', { trimForExclusions: true })), ['*/foo/bar']); - testOptimizationForPathEnds('**/*.foo/bar/**', [], [['baz/bar.foo/bar/baz', true]]); - testOptimizationForPathEnds('**/foo/bar/**', ['/foo/bar'], [['bar/foo/bar', true], ['bar/foo/bar/baz', false]]); + testOptimizationForPaths('**/*.foo/bar/**', [], [['baz/bar.foo/bar/baz', true]]); + testOptimizationForPaths('**/foo/bar/**', ['*/foo/bar'], [['bar/foo/bar', true], ['bar/foo/bar/baz', false]]); // Not supported - // testOptimizationForPathEnds('{**/baz/bar/**,**/foo/bar/**}', ['/baz/bar', '/foo/bar'], [['bar/baz/bar', true], ['bar/foo/bar', true]]); + // testOptimizationForPaths('{**/baz/bar/**,**/foo/bar/**}', ['*/baz/bar', '*/foo/bar'], [['bar/baz/bar', true], ['bar/foo/bar', true]]); - testOptimizationForPathEnds({ + testOptimizationForPaths({ '**/foo/bar/**': true, // Not supported // '{**/bar/bar/**,**/baz/bar/**}': true, '**/bulb/bar/**': false - }, ['/foo/bar'], [ + }, ['*/foo/bar'], [ ['bar/foo/bar', '**/foo/bar/**'], // Not supported // ['foo/bar/bar', '{**/bar/bar/**,**/baz/bar/**}'], @@ -832,10 +838,10 @@ suite('Glob', () => { ]); const siblingsFn = () => ['baz', 'baz.zip', 'nope']; - testOptimizationForPathEnds({ + testOptimizationForPaths({ '**/foo/123/**': { when: '$(basename).zip' }, '**/bar/123/**': true - }, ['/bar/123'], [ + }, ['*/bar/123'], [ ['bar/foo/123', null], ['bar/foo/123/baz', null], ['bar/foo/123/nope', null], @@ -847,9 +853,9 @@ suite('Glob', () => { ]); }); - function testOptimizationForPathEnds(pattern: string|glob.IExpression, pathEndTerms: string[], matches: [string, string|boolean][], siblingsFns: (() => string[])[] = []) { + function testOptimizationForPaths(pattern: string|glob.IExpression, pathTerms: string[], matches: [string, string|boolean][], siblingsFns: (() => string[])[] = []) { const parsed = glob.parse(pattern, { trimForExclusions: true }); - assert.deepStrictEqual(glob.getPathEndTerms(parsed), pathEndTerms); + assert.deepStrictEqual(glob.getPathTerms(parsed), pathTerms); matches.forEach(([text, result], i) => { assert.strictEqual(parsed(text, null, siblingsFns[i]), result); }); diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index 600c1643577..6e9472386d1 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -256,16 +256,16 @@ export class FileWalker { */ public spawnFindCmd(rootFolder: string, excludePattern: glob.ParsedExpression) { const basenames = glob.getBasenameTerms(excludePattern); - const pathEnds = glob.getPathEndTerms(excludePattern); + const paths = glob.getPathTerms(excludePattern); let args = ['-L', '.']; - if (basenames.length || pathEnds.length) { + if (basenames.length || paths.length) { args.push('-not', '(', '('); for (const basename of basenames) { - args.push('-name', FileWalker.escapeGlobSpecials(basename)); + args.push('-name', basename); args.push('-o'); } - for (const pathEnd of pathEnds) { - args.push('-path', '*' + FileWalker.escapeGlobSpecials(pathEnd)); + for (const path of paths) { + args.push('-path', path); args.push('-o'); } args.pop(); @@ -275,12 +275,6 @@ export class FileWalker { return childProcess.spawn('find', args, { cwd: rootFolder }); } - private static GLOB_SPECIALS = /[*?\[\]\\]/g; - private static ESCAPE_CHAR = '\\$&'; - private static escapeGlobSpecials(string) { - return string.replace(this.GLOB_SPECIALS, this.ESCAPE_CHAR); - } - /** * Public for testing. */ diff --git a/src/vs/workbench/services/search/test/node/search.test.ts b/src/vs/workbench/services/search/test/node/search.test.ts index d649a585c9a..f3a60d1c78d 100644 --- a/src/vs/workbench/services/search/test/node/search.test.ts +++ b/src/vs/workbench/services/search/test/node/search.test.ts @@ -478,7 +478,7 @@ suite('Search', () => { }); }); - test('Find: exclude folder path', function (done: () => void) { + test('Find: exclude folder path suffix', function (done: () => void) { if (platform.isWindows) { done(); return; @@ -504,7 +504,7 @@ suite('Search', () => { }); }); - test('Find: exclude subfolder path', function (done: () => void) { + test('Find: exclude subfolder path suffix', function (done: () => void) { if (platform.isWindows) { done(); return; @@ -530,6 +530,32 @@ suite('Search', () => { }); }); + test('Find: exclude folder path', function (done: () => void) { + if (platform.isWindows) { + done(); + return; + } + + const walker = new FileWalker({ rootFolders: rootfolders() }); + const file0 = './examples/company.js'; + const file1 = './examples/subfolder/subfile.txt'; + + const cmd1 = walker.spawnFindCmd(rootfolders()[0], glob.parse({ 'examples/something': true })); + walker.readStdout(cmd1, 'utf8', (err1, stdout1) => { + assert.equal(err1, null); + assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); + assert.notStrictEqual(stdout1.split('\n').indexOf(file1), -1, stdout1); + + const cmd2 = walker.spawnFindCmd(rootfolders()[0], glob.parse({ 'examples/subfolder': true })); + walker.readStdout(cmd2, 'utf8', (err2, stdout2) => { + assert.equal(err2, null); + assert.notStrictEqual(stdout1.split('\n').indexOf(file0), -1, stdout1); + assert.strictEqual(stdout2.split('\n').indexOf(file1), -1, stdout2); + done(); + }); + }); + }); + test('Find: exclude combination of paths', function (done: () => void) { if (platform.isWindows) { done(); From 122881f3192a12c3c211a5f990294875a250c56c Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Thu, 6 Oct 2016 15:00:54 -0700 Subject: [PATCH 109/163] Bind Save All to Alt+Ctrl+S (fixes #11433) --- .../workbench/parts/files/browser/fileActions.contribution.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts index 66ce5b12083..f09d6f636e4 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts @@ -163,7 +163,7 @@ const category = nls.localize('filesCategory', "Files"); const registry = Registry.as(ActionExtensions.WorkbenchActions); registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFileAction, SaveFileAction.ID, SaveFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_S }), 'Files: Save', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveAllAction, SaveAllAction.ID, SaveAllAction.LABEL), 'Files: Save All', category); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveAllAction, SaveAllAction.ID, SaveAllAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_S }), 'Files: Save All', category); registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFilesAction, SaveFilesAction.ID, null /* only for programmatic trigger */), null); registry.registerWorkbenchAction(new SyncActionDescriptor(RevertFileAction, RevertFileAction.ID, RevertFileAction.LABEL), 'Files: Revert File', category); registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewFileAction, GlobalNewFileAction.ID, GlobalNewFileAction.LABEL), 'Files: New File', category); From 40fdd128202257342368303d85f6fceae2f02a05 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 7 Oct 2016 07:46:15 +0200 Subject: [PATCH 110/163] history: avoid typed input for editor history (for #13283) --- .../browser/parts/editor/editorActions.ts | 18 ++- .../parts/quickopen/quickOpenController.ts | 60 +++++++--- .../services/history/browser/history.ts | 106 ++++++++---------- .../services/history/common/history.ts | 4 +- 4 files changed, 105 insertions(+), 83 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorActions.ts b/src/vs/workbench/browser/parts/editor/editorActions.ts index 52dd1060b64..a70c39c2fdc 100644 --- a/src/vs/workbench/browser/parts/editor/editorActions.ts +++ b/src/vs/workbench/browser/parts/editor/editorActions.ts @@ -190,9 +190,13 @@ export class FocusFirstGroupAction extends Action { const history = this.historyService.getHistory(); for (let input of history) { - // For now only support to open resources from history to the side - if (!!getUntitledOrFileResource(input)) { - return this.editorService.openEditor(input, null, Position.LEFT); + // For now only support to open files from history to the side + if (input instanceof EditorInput) { + if (!!getUntitledOrFileResource(input)) { + return this.editorService.openEditor(input, null, Position.LEFT); + } + } else { + return this.editorService.openEditor(input as IResourceInput, Position.LEFT); } } @@ -259,8 +263,12 @@ export abstract class BaseFocusSideGroupAction extends Action { for (let input of history) { // For now only support to open files from history to the side - if (!!getUntitledOrFileResource(input)) { - return this.editorService.openEditor(input, { pinned: true }, this.getTargetEditorSide()); + if (input instanceof EditorInput) { + if (!!getUntitledOrFileResource(input)) { + return this.editorService.openEditor(input, { pinned: true }, this.getTargetEditorSide()); + } + } else { + return this.editorService.openEditor({ resource: (input as IResourceInput).resource, options: { pinned: true } }, this.getTargetEditorSide()); } } } diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index bc81a6712e2..8a20b5da372 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -24,7 +24,9 @@ import {QuickOpenWidget, HideReason} from 'vs/base/parts/quickopen/browser/quick import {ContributableActionProvider} from 'vs/workbench/browser/actionBarRegistry'; import labels = require('vs/base/common/labels'); import paths = require('vs/base/common/paths'); +import {ITextFileService} from 'vs/workbench/services/textfile/common/textfiles'; import {Registry} from 'vs/platform/platform'; +import {IResourceInput, IEditorInput} from 'vs/platform/editor/common/editor'; import {IModeService} from 'vs/editor/common/services/modeService'; import {getIconClasses} from 'vs/workbench/browser/labels'; import {IModelService} from 'vs/editor/common/services/modelService'; @@ -744,14 +746,28 @@ export class QuickOpenController extends WorkbenchComponent implements IQuickOpe const results: QuickOpenEntry[] = []; history.forEach(input => { - const resource = getUntitledOrFileResource(input); + let resource: URI; + if (input instanceof EditorInput) { + resource = getUntitledOrFileResource(input); + } else { + resource = (input as IResourceInput).resource; + } + if (!resource) { return; //For now, only support to match on inputs that provide resource information } + let searchTargetToMatch: string; + if (searchInPath) { + searchTargetToMatch = labels.getPathLabel(resource, this.contextService); + } else if (input instanceof EditorInput) { + searchTargetToMatch = input.getName(); + } else { + searchTargetToMatch = paths.basename((input as IResourceInput).resource.fsPath); + } + // Check if this entry is a match for the search value - const targetToMatch = searchInPath ? labels.getPathLabel(resource, this.contextService) : input.getName(); - if (!filters.matchesFuzzy(searchValue, targetToMatch)) { + if (!filters.matchesFuzzy(searchValue, searchTargetToMatch)) { return; } @@ -1018,28 +1034,42 @@ export class EditorHistoryEntryGroup extends QuickOpenEntryGroup { } export class EditorHistoryEntry extends EditorQuickOpenEntry { - private input: EditorInput; + private input: IEditorInput | IResourceInput; private resource: URI; + private label: string; + private description: string; constructor( - input: EditorInput, + input: IEditorInput | IResourceInput, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IModeService private modeService: IModeService, @IModelService private modelService: IModelService, + @ITextFileService private textFileService: ITextFileService, + @IWorkspaceContextService contextService: IWorkspaceContextService, @IConfigurationService private configurationService: IConfigurationService ) { super(editorService); this.input = input; - this.resource = getUntitledOrFileResource(input); + + if (input instanceof EditorInput) { + this.resource = getUntitledOrFileResource(input); + this.label = input.getName(); + this.description = input.getDescription(); + } else { + const resourceInput = input as IResourceInput; + this.resource = resourceInput.resource; + this.label = paths.basename(resourceInput.resource.fsPath); + this.description = labels.getPathLabel(paths.dirname(this.resource.fsPath), contextService); + } } public getIcon(): string { - return this.input.isDirty() ? 'dirty' : ''; + return this.resource && this.textFileService.isDirty(this.resource) ? 'dirty' : ''; } public getLabel(): string { - return this.input.getName(); + return this.label; } public getLabelOptions(): IIconLabelOptions { @@ -1053,27 +1083,27 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { } public getDescription(): string { - return this.input.getDescription(); + return this.description; } public getResource(): URI { return this.resource; } - public getInput(): EditorInput { + public getInput(): IEditorInput | IResourceInput { return this.input; } - public matches(input: EditorInput): boolean { - return this.input.matches(input); - } - public run(mode: Mode, context: IEntryRunContext): boolean { if (mode === Mode.OPEN) { const sideBySide = !context.quickNavigateConfiguration && context.keymods.indexOf(KeyMod.CtrlCmd) >= 0; const pinned = !this.configurationService.getConfiguration().workbench.editor.enablePreviewFromQuickOpen; - this.editorService.openEditor(this.input, { pinned }, sideBySide).done(null, errors.onUnexpectedError); + if (this.input instanceof EditorInput) { + this.editorService.openEditor(this.input, { pinned }, sideBySide).done(null, errors.onUnexpectedError); + } else { + this.editorService.openEditor({ resource: (this.input as IResourceInput).resource, options: { pinned: true } }, sideBySide); + } return true; } diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index e0ff2ef18e5..d21eae90c8a 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -70,11 +70,15 @@ export class EditorState { } } -interface ISerializedEditorInput { +interface ILegacySerializedEditorInput { id: string; value: string; } +interface ISerializedFileEditorInput { + resource: string; +} + export abstract class BaseHistoryService { protected toUnbind: IDisposable[]; @@ -246,7 +250,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic private blockStackChanges: boolean; private currentFileEditorState: EditorState; - private history: IEditorInput[]; + private history: (IEditorInput|IResourceInput)[]; private recentlyClosedFiles: IRecentlyClosedFile[]; private loaded: boolean; private registry: IEditorRegistry; @@ -351,8 +355,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic if (entry.input instanceof EditorInput) { openEditorPromise = this.editorService.openEditor(entry.input, options); } else { - const resourceInput = entry.input as IResourceInput; - openEditorPromise = this.editorService.openEditor({ resource: resourceInput.resource, options }); + openEditorPromise = this.editorService.openEditor({ resource: (entry.input as IResourceInput).resource, options }); } openEditorPromise.done(() => { @@ -382,37 +385,24 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic this.ensureLoaded(); + const historyInput = this.preferResourceInput(input); + // Remove any existing entry and add to the beginning this.removeFromHistory(input); - this.history.unshift(input); + this.history.unshift(historyInput); // Respect max entries setting if (this.history.length > HistoryService.MAX_HISTORY_ITEMS) { this.history.pop(); } - // Restore on dispose - const onceDispose = once(input.onDispose); - onceDispose(() => { - this.restoreInHistory(input); - }); - } - - private restoreInHistory(input: IEditorInput): void { - const index = this.indexOf(input); - if (index < 0) { - return; - } - - // Using the factory we try to recreate the input - const restoredInput = this.restoreInput(input); - if (restoredInput) { - this.history[index] = restoredInput; - } - - // Factory failed, just remove entry then - else { - this.removeFromHistory(input, index); + // Remove this from the history unless the history input is a resource + // that can easily be restored even when the input gets disposed + if (historyInput instanceof EditorInput) { + const onceDispose = once(historyInput.onDispose); + onceDispose(() => { + this.removeFromHistory(input); + }); } } @@ -437,7 +427,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic private indexOf(input: IEditorInput): number { for (let i = 0; i < this.history.length; i++) { const entry = this.history[i]; - if (entry.matches(input)) { + if (this.matches(input, entry)) { return i; } } @@ -577,20 +567,6 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic return s1.startLineNumber === s2.startLineNumber; // we consider the history entry same if we are on the same line } - private restoreInput(input: IEditorInput): EditorInput { - if (input instanceof EditorInput) { - const factory = this.registry.getEditorInputFactory(input.getTypeId()); - if (factory) { - const inputRaw = factory.serialize(input); - if (inputRaw) { - return factory.deserialize(this.instantiationService, inputRaw); - } - } - } - - return null; - } - private removeFromStack(input: IEditorInput): void { this.stack.forEach((e, i) => { if (this.matches(input, e.input)) { @@ -627,9 +603,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic return input.matches(typedInput); } - const resourceInput = input as IResourceInput; - - return this.matchesFile(resourceInput.resource, typedInput); + return this.matchesFile((input as IResourceInput).resource, typedInput); } private matchesFile(resource: URI, input: IEditorInput): boolean { @@ -638,7 +612,7 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic return fileInput && fileInput.getResource().toString() === resource.toString(); } - public getHistory(): IEditorInput[] { + public getHistory(): (IEditorInput|IResourceInput)[] { this.ensureLoaded(); return this.history.slice(0); @@ -657,35 +631,45 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic return; // nothing to save because history was not used } - const entries: ISerializedEditorInput[] = this.history.map((input: EditorInput) => { - const factory = this.registry.getEditorInputFactory(input.getTypeId()); - if (factory) { - const value = factory.serialize(input); - if (typeof value === 'string') { - return { - id: input.getTypeId(), - value: value - }; - } + const entries: ISerializedFileEditorInput[] = this.history.map(input => { + if (input instanceof EditorInput) { + return void 0; // only file resource inputs are serializable currently } - return void 0; + return { resource: (input as IResourceInput).resource.toString() }; }).filter(serialized => !!serialized); this.storageService.store(HistoryService.STORAGE_KEY, JSON.stringify(entries), StorageScope.WORKSPACE); } private load(): void { - let entries: ISerializedEditorInput[] = []; + let entries: (ILegacySerializedEditorInput|ISerializedFileEditorInput)[] = []; + const entriesRaw = this.storageService.get(HistoryService.STORAGE_KEY, StorageScope.WORKSPACE); if (entriesRaw) { entries = JSON.parse(entriesRaw); } this.history = entries.map(entry => { - const factory = this.registry.getEditorInputFactory(entry.id); - if (factory && typeof entry.value === 'string') { - return factory.deserialize(this.instantiationService, entry.value); + const serializedLegacyInput = entry as ILegacySerializedEditorInput; + const serializedFileInput = entry as ISerializedFileEditorInput; + + // Legacy support (TODO@Ben remove me - migration) + if (serializedLegacyInput.id) { + const factory = this.registry.getEditorInputFactory(serializedLegacyInput.id); + if (factory && typeof serializedLegacyInput.value === 'string') { + const fileInput = asFileEditorInput(factory.deserialize(this.instantiationService, serializedLegacyInput.value)); + if (fileInput) { + return { resource: fileInput.getResource() } as IResourceInput; + } + + return void 0; + } + } + + // New resource input support + else if (serializedFileInput.resource) { + return { resource: URI.parse(serializedFileInput.resource) } as IResourceInput; } return void 0; diff --git a/src/vs/workbench/services/history/common/history.ts b/src/vs/workbench/services/history/common/history.ts index 67d99afb0f9..968445aab09 100644 --- a/src/vs/workbench/services/history/common/history.ts +++ b/src/vs/workbench/services/history/common/history.ts @@ -5,7 +5,7 @@ 'use strict'; import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation'; -import {IEditorInput, ITextEditorOptions} from 'vs/platform/editor/common/editor'; +import {IEditorInput, ITextEditorOptions, IResourceInput} from 'vs/platform/editor/common/editor'; export const IHistoryService = createDecorator('historyService'); @@ -46,5 +46,5 @@ export interface IHistoryService { /** * Get the entire history of opened editors. */ - getHistory(): IEditorInput[]; + getHistory(): (IEditorInput|IResourceInput)[]; } \ No newline at end of file From 4e9a7b837e53478f149076690bd4075c9db0e9a4 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 7 Oct 2016 10:00:20 +0200 Subject: [PATCH 111/163] :lipstick: --- .../workbench/browser/actions/openSettings.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/browser/actions/openSettings.ts b/src/vs/workbench/browser/actions/openSettings.ts index ae5232d883b..a014bdea0c3 100644 --- a/src/vs/workbench/browser/actions/openSettings.ts +++ b/src/vs/workbench/browser/actions/openSettings.ts @@ -57,9 +57,9 @@ export class BaseTwoEditorsAction extends Action { } protected createIfNotExists(resource: URI, contents: string): TPromise { - return this.fileService.resolveContent(resource, { acceptTextOnly: true }).then(null, (error) => { + return this.fileService.resolveContent(resource, { acceptTextOnly: true }).then(null, error => { if ((error).fileOperationResult === FileOperationResult.FILE_NOT_FOUND) { - return this.fileService.updateContent(resource, contents).then(null, (error) => { + return this.fileService.updateContent(resource, contents).then(null, error => { return TPromise.wrapError(new Error(nls.localize('fail.createSettings', "Unable to create '{0}' ({1}).", labels.getPathLabel(resource, this.contextService), error))); }); } @@ -72,7 +72,7 @@ export class BaseTwoEditorsAction extends Action { // Create as needed and open in editor return this.createIfNotExists(editableResource, defaultEditableContents).then(() => { - return this.editorService.createInput({ resource: editableResource }).then((typedRightHandEditableInput) => { + return this.editorService.createInput({ resource: editableResource }).then(typedRightHandEditableInput => { const editors = [ { input: leftHandDefaultInput, position: Position.LEFT, options: { pinned: true } }, { input: typedRightHandEditableInput, position: Position.CENTER, options: { pinned: true } } @@ -150,9 +150,9 @@ export class OpenGlobalSettingsAction extends BaseOpenSettingsAction { message: nls.localize('workspaceHasSettings', "The currently opened folder contains workspace settings that may override user settings"), actions: [ new Action('open.workspaceSettings', nls.localize('openWorkspaceSettings', "Open Workspace Settings"), null, true, () => { - let editorCount = this.editorService.getVisibleEditors().length; + const editorCount = this.editorService.getVisibleEditors().length; - return this.editorService.createInput({ resource: this.contextService.toResource(WORKSPACE_CONFIG_DEFAULT_PATH) }).then((typedInput) => { + return this.editorService.createInput({ resource: this.contextService.toResource(WORKSPACE_CONFIG_DEFAULT_PATH) }).then(typedInput => { return this.editorService.openEditor(typedInput, { pinned: true }, editorCount === 2 ? Position.RIGHT : editorCount === 1 ? Position.CENTER : void 0); }); }), @@ -167,7 +167,7 @@ export class OpenGlobalSettingsAction extends BaseOpenSettingsAction { } // Open settings - let emptySettingsHeader = nls.localize('emptySettingsHeader', "Place your settings in this file to overwrite the default settings"); + const emptySettingsHeader = nls.localize('emptySettingsHeader', "Place your settings in this file to overwrite the default settings"); return this.open('// ' + emptySettingsHeader + '\n{\n}', URI.file(this.environmentService.appSettingsPath)); } @@ -195,7 +195,7 @@ export class OpenGlobalKeybindingsAction extends BaseTwoEditorsAction { } public run(event?: any): TPromise { - let emptyContents = '// ' + nls.localize('emptyKeybindingsHeader', "Place your key bindings in this file to overwrite the defaults") + '\n[\n]'; + const emptyContents = '// ' + nls.localize('emptyKeybindingsHeader', "Place your key bindings in this file to overwrite the defaults") + '\n[\n]'; return this.openTwoEditors(DefaultKeybindingsInput.getInstance(this.instantiationService, this.keybindingService), URI.file(this.environmentService.appKeybindingsPath), emptyContents); } @@ -213,7 +213,7 @@ export class OpenWorkspaceSettingsAction extends BaseOpenSettingsAction { return; } - let emptySettingsHeader = [ + const emptySettingsHeader = [ '// ' + nls.localize('emptySettingsHeader1', "Place your settings in this file to overwrite default and user settings."), '{', '}' @@ -228,8 +228,8 @@ class DefaultSettingsInput extends StringEditorInput { public static getInstance(instantiationService: IInstantiationService, configurationService: IWorkspaceConfigurationService): DefaultSettingsInput { if (!DefaultSettingsInput.INSTANCE) { - let editorConfig = configurationService.getConfiguration(); - let defaults = getDefaultValuesContent(editorConfig.editor.insertSpaces ? strings.repeat(' ', editorConfig.editor.tabSize) : '\t'); + const editorConfig = configurationService.getConfiguration(); + const defaults = getDefaultValuesContent(editorConfig.editor.insertSpaces ? strings.repeat(' ', editorConfig.editor.tabSize) : '\t'); let defaultsHeader = '// ' + nls.localize('defaultSettingsHeader', "Overwrite settings by placing them into your settings file."); defaultsHeader += '\n// ' + nls.localize('defaultSettingsHeader2', "See http://go.microsoft.com/fwlink/?LinkId=808995 for the most commonly used settings."); @@ -249,8 +249,8 @@ class DefaultKeybindingsInput extends StringEditorInput { public static getInstance(instantiationService: IInstantiationService, keybindingService: IKeybindingService): DefaultKeybindingsInput { if (!DefaultKeybindingsInput.INSTANCE) { - let defaultsHeader = '// ' + nls.localize('defaultKeybindingsHeader', "Overwrite key bindings by placing them into your key bindings file."); - let defaultContents = keybindingService.getDefaultKeybindings(); + const defaultsHeader = '// ' + nls.localize('defaultKeybindingsHeader', "Overwrite key bindings by placing them into your key bindings file."); + const defaultContents = keybindingService.getDefaultKeybindings(); DefaultKeybindingsInput.INSTANCE = instantiationService.createInstance(DefaultKeybindingsInput, nls.localize('defaultKeybindings', "Default Keyboard Shortcuts"), null, defaultsHeader + '\n' + defaultContents, 'application/json', false); } From 1a15210f010a950778739a8480894570ba3255f3 Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 7 Oct 2016 10:30:44 +0200 Subject: [PATCH 112/163] first set code editor, then setConfiguration fixes #12879 --- src/vs/workbench/api/node/mainThreadEditorsTracker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/api/node/mainThreadEditorsTracker.ts b/src/vs/workbench/api/node/mainThreadEditorsTracker.ts index 3816013b817..4d44594122f 100644 --- a/src/vs/workbench/api/node/mainThreadEditorsTracker.ts +++ b/src/vs/workbench/api/node/mainThreadEditorsTracker.ts @@ -102,13 +102,13 @@ export class MainThreadTextEditor { this._onConfigurationChanged = new Emitter(); this._lastSelection = [ new Selection(1,1,1,1) ]; - this._setConfiguration(this._readConfiguration(this._model, this._codeEditor)); this._modelListeners = []; this._modelListeners.push(this._model.onDidChangeOptions((e) => { this._setConfiguration(this._readConfiguration(this._model, this._codeEditor)); })); this.setCodeEditor(codeEditor); + this._setConfiguration(this._readConfiguration(this._model, this._codeEditor)); } public dispose(): void { From 59e53464bb37f921c38e603d8c217984206f117c Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 7 Oct 2016 10:33:17 +0200 Subject: [PATCH 113/163] Write window zoom configuration to settings (fixes #13334) --- src/vs/workbench/electron-browser/actions.ts | 83 +++++++++++++------- 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index 8054efc6f45..c922c2d7d45 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -18,12 +18,12 @@ import product from 'vs/platform/product'; import pkg from 'vs/platform/package'; import errors = require('vs/base/common/errors'); import {IMessageService, Severity} from 'vs/platform/message/common/message'; -import {IWindowConfiguration} from 'vs/workbench/electron-browser/common'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IPartService} from 'vs/workbench/services/part/common/partService'; import {IEnvironmentService} from 'vs/platform/environment/common/environment'; +import {IConfigurationEditingService, ConfigurationTarget} from 'vs/workbench/services/configuration/common/configurationEditing'; import {IExtensionManagementService, LocalExtensionType, ILocalExtension} from 'vs/platform/extensionManagement/common/extensionManagement'; -import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; +import {IWorkspaceConfigurationService} from 'vs/workbench/services/configuration/common/configuration'; import {CommandsRegistry} from 'vs/platform/commands/common/commands'; import paths = require('vs/base/common/paths'); import {isMacintosh} from 'vs/base/common/platform'; @@ -205,44 +205,82 @@ export class ToggleDevToolsAction extends Action { } } -export class ZoomInAction extends Action { +export abstract class BaseZoomAction extends Action { + private static SETTING_KEY = 'window.zoomLevel'; + + constructor( + id: string, + label: string, + @IMessageService private messageService: IMessageService, + @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService, + @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + ) { + super(id, label); + } + + protected setConfiguredZoomLevel(level: number): void { + let target = ConfigurationTarget.USER; + if (typeof this.configurationService.lookup(BaseZoomAction.SETTING_KEY).workspace === 'number') { + target = ConfigurationTarget.WORKSPACE; + } + + this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }).done(null, error => { + + // Fallback to apply on window + webFrame.setZoomLevel(level); + browser.setZoomLevel(level); // Ensure others can listen to zoom level changes + + // Inform user + this.messageService.show(Severity.Error, error); + }); + } +} + +export class ZoomInAction extends BaseZoomAction { public static ID = 'workbench.action.zoomIn'; public static LABEL = nls.localize('zoomIn', "Zoom In"); - constructor(id: string, label: string) { - super(id, label); + constructor( + id: string, + label: string, + @IMessageService messageService: IMessageService, + @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService, + @IConfigurationEditingService configurationEditingService: IConfigurationEditingService + ) { + super(id, label, messageService, configurationService, configurationEditingService); } public run(): TPromise { - webFrame.setZoomLevel(webFrame.getZoomLevel() + 1); - browser.setZoomLevel(webFrame.getZoomLevel()); // Ensure others can listen to zoom level changes + this.setConfiguredZoomLevel(webFrame.getZoomLevel() + 1); return TPromise.as(true); } } -export class ZoomOutAction extends Action { +export class ZoomOutAction extends BaseZoomAction { public static ID = 'workbench.action.zoomOut'; public static LABEL = nls.localize('zoomOut', "Zoom Out"); constructor( id: string, - label: string + label: string, + @IMessageService messageService: IMessageService, + @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService, + @IConfigurationEditingService configurationEditingService: IConfigurationEditingService ) { - super(id, label); + super(id, label, messageService, configurationService, configurationEditingService); } public run(): TPromise { - webFrame.setZoomLevel(webFrame.getZoomLevel() - 1); - browser.setZoomLevel(webFrame.getZoomLevel()); // Ensure others can listen to zoom level changes + this.setConfiguredZoomLevel(webFrame.getZoomLevel() - 1); return TPromise.as(true); } } -export class ZoomResetAction extends Action { +export class ZoomResetAction extends BaseZoomAction { public static ID = 'workbench.action.zoomReset'; public static LABEL = nls.localize('zoomReset', "Reset Zoom"); @@ -250,27 +288,18 @@ export class ZoomResetAction extends Action { constructor( id: string, label: string, - @IConfigurationService private configurationService: IConfigurationService + @IMessageService messageService: IMessageService, + @IWorkspaceConfigurationService configurationService: IWorkspaceConfigurationService, + @IConfigurationEditingService configurationEditingService: IConfigurationEditingService ) { - super(id, label); + super(id, label, messageService, configurationService, configurationEditingService); } public run(): TPromise { - const level = this.getConfiguredZoomLevel(); - webFrame.setZoomLevel(level); - browser.setZoomLevel(webFrame.getZoomLevel()); // Ensure others can listen to zoom level changes + this.setConfiguredZoomLevel(0); return TPromise.as(true); } - - private getConfiguredZoomLevel(): number { - const windowConfig = this.configurationService.getConfiguration(); - if (windowConfig.window && typeof windowConfig.window.zoomLevel === 'number') { - return windowConfig.window.zoomLevel; - } - - return 0; // default - } } /* Copied from loader.ts */ From 39c9f26e4d9a99f1b74a507431e9d8086bdd442b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 7 Oct 2016 10:37:41 +0200 Subject: [PATCH 114/163] always apply zoom fast before watcher kicks in --- src/vs/workbench/electron-browser/actions.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index c922c2d7d45..afde026baea 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -224,15 +224,17 @@ export abstract class BaseZoomAction extends Action { target = ConfigurationTarget.WORKSPACE; } - this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }).done(null, error => { - - // Fallback to apply on window + const applyZoom = (error?: Error) => { webFrame.setZoomLevel(level); browser.setZoomLevel(level); // Ensure others can listen to zoom level changes // Inform user - this.messageService.show(Severity.Error, error); - }); + if (error) { + this.messageService.show(Severity.Error, error); + } + }; + + this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }).done(() => applyZoom(), error => applyZoom(error)); } } From cb83b10321c99bd2167bfa3effa0b9d2d10aa553 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 7 Oct 2016 10:38:29 +0200 Subject: [PATCH 115/163] less noise when setting zoom --- src/vs/workbench/electron-browser/actions.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index afde026baea..e50a681ba83 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -224,17 +224,12 @@ export abstract class BaseZoomAction extends Action { target = ConfigurationTarget.WORKSPACE; } - const applyZoom = (error?: Error) => { + const applyZoom = () => { webFrame.setZoomLevel(level); browser.setZoomLevel(level); // Ensure others can listen to zoom level changes - - // Inform user - if (error) { - this.messageService.show(Severity.Error, error); - } }; - this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }).done(() => applyZoom(), error => applyZoom(error)); + this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }).done(() => applyZoom(), error => applyZoom()); } } From 069984e003cc9d35fbe68ded04acafc796545a8a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 7 Oct 2016 11:09:59 +0200 Subject: [PATCH 116/163] Make sidebar position a real setting (fixes #13338) --- src/vs/test/utils/servicesTestUtils.ts | 1 - .../browser/actions/toggleSidebarPosition.ts | 22 ++++++++-- .../actions/toggleSidebarVisibility.ts | 8 +++- .../actions/toggleStatusbarVisibility.ts | 8 +++- src/vs/workbench/common/editor.ts | 2 +- .../common/editor/editorStacksModel.ts | 6 ++- .../electron-browser/main.contribution.ts | 8 +++- .../workbench/electron-browser/workbench.ts | 40 ++++++++++++------- .../services/part/common/partService.ts | 6 --- 9 files changed, 68 insertions(+), 33 deletions(-) diff --git a/src/vs/test/utils/servicesTestUtils.ts b/src/vs/test/utils/servicesTestUtils.ts index b39619fe14e..6941fd3af0d 100644 --- a/src/vs/test/utils/servicesTestUtils.ts +++ b/src/vs/test/utils/servicesTestUtils.ts @@ -256,7 +256,6 @@ export class TestPartService implements IPartService { return 0; } - public setSideBarPosition(position): void { } public addClass(clazz: string): void { } public removeClass(clazz: string): void { } public getWorkbenchElementId(): string { return ''; } diff --git a/src/vs/workbench/browser/actions/toggleSidebarPosition.ts b/src/vs/workbench/browser/actions/toggleSidebarPosition.ts index e8b69ff814c..ce54051829c 100644 --- a/src/vs/workbench/browser/actions/toggleSidebarPosition.ts +++ b/src/vs/workbench/browser/actions/toggleSidebarPosition.ts @@ -9,7 +9,9 @@ import nls = require('vs/nls'); import {Registry} from 'vs/platform/platform'; import {Action} from 'vs/base/common/actions'; import {SyncActionDescriptor} from 'vs/platform/actions/common/actions'; +import {IMessageService, Severity} from 'vs/platform/message/common/message'; import {IWorkbenchActionRegistry, Extensions} from 'vs/workbench/common/actionRegistry'; +import {IConfigurationEditingService, ConfigurationTarget} from 'vs/workbench/services/configuration/common/configurationEditing'; import {IPartService, Position} from 'vs/workbench/services/part/common/partService'; export class ToggleSidebarPositionAction extends Action { @@ -17,15 +19,27 @@ export class ToggleSidebarPositionAction extends Action { public static ID = 'workbench.action.toggleSidebarPosition'; public static LABEL = nls.localize('togglePosition', "Toggle Side Bar Position"); - constructor(id: string, label: string, @IPartService private partService: IPartService) { + private static sidebarPositionConfigurationKey = 'workbench.sideBar.location'; + + constructor( + id: string, + label: string, + @IPartService private partService: IPartService, + @IMessageService private messageService: IMessageService, + @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService + ) { super(id, label); - this.enabled = !!this.partService; + this.enabled = !!this.partService && !!this.configurationEditingService; } public run(): TPromise { - let position = this.partService.getSideBarPosition(); - this.partService.setSideBarPosition(position === Position.LEFT ? Position.RIGHT : Position.LEFT); + const position = this.partService.getSideBarPosition(); + const newPositionValue = (position === Position.LEFT) ? 'right' : 'left'; + + this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: ToggleSidebarPositionAction.sidebarPositionConfigurationKey, value: newPositionValue }).then(null, error => { + this.messageService.show(Severity.Error, error); + }); return TPromise.as(null); } diff --git a/src/vs/workbench/browser/actions/toggleSidebarVisibility.ts b/src/vs/workbench/browser/actions/toggleSidebarVisibility.ts index 91f62b6c5c8..c1fc13314e5 100644 --- a/src/vs/workbench/browser/actions/toggleSidebarVisibility.ts +++ b/src/vs/workbench/browser/actions/toggleSidebarVisibility.ts @@ -18,14 +18,18 @@ export class ToggleSidebarVisibilityAction extends Action { public static ID = 'workbench.action.toggleSidebarVisibility'; public static LABEL = nls.localize('toggleSidebar', "Toggle Side Bar Visibility"); - constructor(id: string, label: string, @IPartService private partService: IPartService) { + constructor( + id: string, + label: string, + @IPartService private partService: IPartService + ) { super(id, label); this.enabled = !!this.partService; } public run(): TPromise { - let hideSidebar = !this.partService.isSideBarHidden(); + const hideSidebar = !this.partService.isSideBarHidden(); this.partService.setSideBarHidden(hideSidebar); return TPromise.as(null); diff --git a/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts b/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts index b0fd30585ae..245f7795c8f 100644 --- a/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts +++ b/src/vs/workbench/browser/actions/toggleStatusbarVisibility.ts @@ -17,14 +17,18 @@ export class ToggleStatusbarVisibilityAction extends Action { public static ID = 'workbench.action.toggleStatusbarVisibility'; public static LABEL = nls.localize('toggleStatusbar', "Toggle Status Bar Visibility"); - constructor(id: string, label: string, @IPartService private partService: IPartService) { + constructor( + id: string, + label: string, + @IPartService private partService: IPartService + ) { super(id, label); this.enabled = !!this.partService; } public run(): TPromise { - let hideStatusbar = !this.partService.isStatusBarHidden(); + const hideStatusbar = !this.partService.isStatusBarHidden(); this.partService.setStatusBarHidden(hideStatusbar); return TPromise.as(null); diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index a8ee5aa2930..818f05f257a 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -881,7 +881,7 @@ export interface IWorkbenchEditorConfiguration { showIcons: boolean; enablePreview: boolean; enablePreviewFromQuickOpen: boolean; - openPositioning: string; + openPositioning: 'left' | 'right' | 'first' | 'last'; } }; } diff --git a/src/vs/workbench/common/editor/editorStacksModel.ts b/src/vs/workbench/common/editor/editorStacksModel.ts index 7242b49b898..bdaedda577b 100644 --- a/src/vs/workbench/common/editor/editorStacksModel.ts +++ b/src/vs/workbench/common/editor/editorStacksModel.ts @@ -59,7 +59,7 @@ export class EditorGroup implements IEditorGroup { private active: EditorInput; // editor in active state private toDispose: IDisposable[]; - private editorOpenPositioning: string; + private editorOpenPositioning: 'left' | 'right' | 'first' | 'last'; private _onEditorActivated: Emitter; private _onEditorOpened: Emitter; @@ -114,7 +114,9 @@ export class EditorGroup implements IEditorGroup { } private onConfigurationUpdated(config: IWorkbenchEditorConfiguration): void { - this.editorOpenPositioning = config && config.workbench && config.workbench.editor && config.workbench.editor.openPositioning; + if (config && config.workbench && config.workbench.editor) { + this.editorOpenPositioning = config.workbench.editor.openPositioning; + } } public get id(): GroupIdentifier { diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index 57379719433..849cddc7f52 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -109,7 +109,13 @@ configurationRegistry.registerConfiguration({ 'type': 'boolean', 'description': nls.localize('openDefaultSettings', "Controls if opening settings also opens an editor showing all default settings."), 'default': true - } + }, + 'workbench.sideBar.location': { + 'type': 'string', + 'enum': ['left', 'right'], + 'default': 'left', + 'description': nls.localize('sideBarLocation', "Controls the location of the sidebar. It can either show on the left or right of the workbench.") + }, } }); diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 312f5568829..02030b9be2c 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -43,6 +43,7 @@ import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; import {IStorageService, StorageScope} from 'vs/platform/storage/common/storage'; import {ContextMenuService} from 'vs/workbench/services/contextview/electron-browser/contextmenuService'; import {WorkbenchKeybindingService} from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; +import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {IConfigurationEditingService} from 'vs/workbench/services/configuration/common/configurationEditing'; import {ConfigurationEditingService} from 'vs/workbench/services/configuration/node/configurationEditingService'; import {ContextKeyService} from 'vs/platform/contextkey/browser/contextKeyService'; @@ -104,12 +105,13 @@ const Identifiers = { */ export class Workbench implements IPartService { - private static sidebarPositionSettingKey = 'workbench.sidebar.position'; private static statusbarHiddenSettingKey = 'workbench.statusbar.hidden'; private static sidebarHiddenSettingKey = 'workbench.sidebar.hidden'; private static sidebarRestoreSettingKey = 'workbench.sidebar.restore'; private static panelHiddenSettingKey = 'workbench.panel.hidden'; + private static sidebarPositionConfigurationKey = 'workbench.sideBar.location'; + public _serviceBrand: any; private container: HTMLElement; @@ -122,6 +124,7 @@ export class Workbench implements IPartService { private editorService: WorkbenchEditorService; private contextKeyService: IContextKeyService; private keybindingService: IKeybindingService; + private configurationEditingService: IConfigurationEditingService; private activitybarPart: ActivitybarPart; private sidebarPart: SidebarPart; private panelPart: PanelPart; @@ -154,6 +157,7 @@ export class Workbench implements IPartService { @IStorageService private storageService: IStorageService, @ILifecycleService private lifecycleService: ILifecycleService, @IMessageService private messageService: IMessageService, + @IConfigurationService private configurationService: IConfigurationService, @ITelemetryService private telemetryService: ITelemetryService, @IEnvironmentService private environmentService: IEnvironmentService ) { @@ -392,7 +396,8 @@ export class Workbench implements IPartService { serviceCollection.set(ITextFileService, this.instantiationService.createInstance(TextFileService)); // Configuration Editing - serviceCollection.set(IConfigurationEditingService, this.instantiationService.createInstance(ConfigurationEditingService)); + this.configurationEditingService = this.instantiationService.createInstance(ConfigurationEditingService); + serviceCollection.set(IConfigurationEditingService, this.configurationEditingService); // Configuration Resolver const workspace = this.contextService.getWorkspace(); @@ -438,8 +443,8 @@ export class Workbench implements IPartService { } // Sidebar position - const rawPosition = this.storageService.get(Workbench.sidebarPositionSettingKey, StorageScope.GLOBAL, 'left'); - this.sideBarPosition = (rawPosition === 'left') ? Position.LEFT : Position.RIGHT; + const sideBarPosition = this.configurationService.lookup(Workbench.sidebarPositionConfigurationKey).value; + this.sideBarPosition = (sideBarPosition === 'right') ? Position.RIGHT : Position.LEFT; // Statusbar visibility this.statusBarHidden = this.storageService.getBoolean(Workbench.statusbarHiddenSettingKey, StorageScope.GLOBAL, false); @@ -613,7 +618,7 @@ export class Workbench implements IPartService { return this.sideBarPosition; } - public setSideBarPosition(position: Position): void { + private setSideBarPosition(position: Position): void { if (this.sideBarHidden) { this.setSideBarHidden(false, true /* Skip Layout */); } @@ -630,9 +635,6 @@ export class Workbench implements IPartService { // Layout this.workbenchLayout.layout(true); - - // Remember in settings - this.storageService.store(Workbench.sidebarPositionSettingKey, position === Position.LEFT ? 'left' : 'right', StorageScope.GLOBAL); } public dispose(): void { @@ -666,13 +668,14 @@ export class Workbench implements IPartService { this.toDispose.push(this.editorPart.onEditorsChanged(() => this.onEditorsChanged())); // Handle message service and quick open events - if (this.messageService instanceof WorkbenchMessageService) { - this.toDispose.push((this.messageService).onMessagesShowing(() => this.messagesVisibleContext.set(true))); - this.toDispose.push((this.messageService).onMessagesCleared(() => this.messagesVisibleContext.reset())); + this.toDispose.push((this.messageService).onMessagesShowing(() => this.messagesVisibleContext.set(true))); + this.toDispose.push((this.messageService).onMessagesCleared(() => this.messagesVisibleContext.reset())); - this.toDispose.push(this.quickOpen.onShow(() => (this.messageService).suspend())); // when quick open is open, don't show messages behind - this.toDispose.push(this.quickOpen.onHide(() => (this.messageService).resume())); // resume messages once quick open is closed again - } + this.toDispose.push(this.quickOpen.onShow(() => (this.messageService).suspend())); // when quick open is open, don't show messages behind + this.toDispose.push(this.quickOpen.onHide(() => (this.messageService).resume())); // resume messages once quick open is closed again + + // Configuration changes + this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => this.onDidUpdateConfiguration())); } private onEditorsChanged(): void { @@ -691,6 +694,15 @@ export class Workbench implements IPartService { } } + private onDidUpdateConfiguration(): void { + const newSidebarPositionValue = this.configurationService.lookup(Workbench.sidebarPositionConfigurationKey).value; + const newSidebarPosition = newSidebarPositionValue === 'right' ? Position.RIGHT : Position.LEFT; + + if (newSidebarPosition !== this.getSideBarPosition()) { + this.setSideBarPosition(newSidebarPosition); + } + } + private createWorkbenchLayout(): void { const options = new LayoutOptions(); options.setMargin(new Box(0, 0, 0, 0)); diff --git a/src/vs/workbench/services/part/common/partService.ts b/src/vs/workbench/services/part/common/partService.ts index 4c935db776c..be54d9fa15c 100644 --- a/src/vs/workbench/services/part/common/partService.ts +++ b/src/vs/workbench/services/part/common/partService.ts @@ -90,12 +90,6 @@ export interface IPartService { */ getSideBarPosition(): Position; - /** - * Sets the side bar position. If the side bar is hidden, the side bar will - * also be made visible. - */ - setSideBarPosition(position: Position): void; - /** * Adds a class to the workbench part. */ From 90770d236fe50a4f1874c4934d7158a82b5b3808 Mon Sep 17 00:00:00 2001 From: Tereza Tomcova Date: Wed, 5 Oct 2016 17:22:58 +0200 Subject: [PATCH 117/163] Call AllowSetForegroundWindow before sending IPC to the running instance on Windows (Fixes #929) --- build/gulpfile.vscode.js | 1 + npm-shrinkwrap.json | 5 +++++ package.json | 1 + src/typings/windows-foreground-love.d.ts | 10 ++++++++++ src/vs/code/electron-main/launch.ts | 20 +++++++++++++++++--- src/vs/code/electron-main/main.ts | 13 ++++++++++++- 6 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 src/typings/windows-foreground-love.d.ts diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index dabac01f5ab..af5a5fe1fc3 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -268,6 +268,7 @@ function packageTask(platform, arch, opts) { .pipe(util.cleanNodeModule('oniguruma', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node'])) .pipe(util.cleanNodeModule('windows-mutex', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) .pipe(util.cleanNodeModule('native-keymap', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node'])) + .pipe(util.cleanNodeModule('windows-foreground-love', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) .pipe(util.cleanNodeModule('gc-signals', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['**/*.node', 'src/index.js'])) .pipe(util.cleanNodeModule('pty.js', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/**'])); diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 0b3fd12858e..0a9e33916cf 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -414,6 +414,11 @@ "from": "vscode-textmate@2.2.0", "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-2.2.0.tgz" }, + "windows-foreground-love": { + "version": "0.1.0", + "from": "windows-foreground-love@0.1.0", + "resolved": "https://registry.npmjs.org/windows-foreground-love/-/windows-foreground-love-0.1.0.tgz" + }, "windows-mutex": { "version": "0.2.0", "from": "windows-mutex@>=0.2.0 <0.3.0", diff --git a/package.json b/package.json index 8ad3c9f600f..98f8977c726 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ } }, "optionalDependencies": { + "windows-foreground-love": "0.1.0", "windows-mutex": "^0.2.0", "fsevents": "0.3.8" } diff --git a/src/typings/windows-foreground-love.d.ts b/src/typings/windows-foreground-love.d.ts new file mode 100644 index 00000000000..f7d20f13aef --- /dev/null +++ b/src/typings/windows-foreground-love.d.ts @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'windows-foreground-love' { + + export function allowSetForegroundWindow(pid?: number): boolean; + +} \ No newline at end of file diff --git a/src/vs/code/electron-main/launch.ts b/src/vs/code/electron-main/launch.ts index c708a942011..185cd639486 100644 --- a/src/vs/code/electron-main/launch.ts +++ b/src/vs/code/electron-main/launch.ts @@ -21,10 +21,12 @@ export interface IStartArguments { export interface ILaunchService { start(args: ParsedArgs, userEnv: IProcessEnvironment): TPromise; + getMainProcessId(): TPromise; } export interface ILaunchChannel extends IChannel { call(command: 'start', arg: IStartArguments): TPromise; + call(command: 'get-main-process-id', arg: null): TPromise; call(command: string, arg: any): TPromise; } @@ -33,10 +35,13 @@ export class LaunchChannel implements ILaunchChannel { constructor(private service: ILaunchService) { } call(command: string, arg: any): TPromise { - const { args, userEnv } = arg as IStartArguments; - switch (command) { - case 'start': return this.service.start(args, userEnv); + case 'start': + const { args, userEnv } = arg as IStartArguments; + return this.service.start(args, userEnv); + + case 'get-main-process-id': + return this.service.getMainProcessId(); } } } @@ -48,6 +53,10 @@ export class LaunchChannelClient implements ILaunchService { start(args: ParsedArgs, userEnv: IProcessEnvironment): TPromise { return this.channel.call('start', { args, userEnv }); } + + getMainProcessId(): TPromise { + return this.channel.call('get-main-process-id', null); + } } export class LaunchService implements ILaunchService { @@ -105,4 +114,9 @@ export class LaunchService implements ILaunchService { return TPromise.as(null); } + + getMainProcessId(): TPromise { + this.logService.log('Received request for process ID from other instance.'); + return TPromise.as(process.pid); + } } \ No newline at end of file diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 8a1798c023d..8248fb807ce 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -25,6 +25,7 @@ import { AskpassChannel } from 'vs/workbench/parts/git/common/gitIpc'; import { GitAskpassService } from 'vs/workbench/parts/git/electron-main/askpassService'; import { spawnSharedProcess } from 'vs/code/node/sharedProcess'; import { Mutex } from 'windows-mutex'; +import { allowSetForegroundWindow } from 'windows-foreground-love'; import { LaunchService, ILaunchChannel, LaunchChannel, LaunchChannelClient } from './launch'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; @@ -299,7 +300,17 @@ function setupIPC(accessor: ServicesAccessor): TPromise { const channel = client.getChannel('launch'); const service = new LaunchChannelClient(channel); - return service.start(environmentService.args, process.env) + let promise = TPromise.as(null); + if (platform.isWindows) { + promise = service.getMainProcessId() + .then(processId => { + logService.log('Sending some foreground love to the running instance:', processId); + allowSetForegroundWindow(processId); + }); + } + + return promise + .then(() => service.start(environmentService.args, process.env)) .then(() => client.dispose()) .then(() => TPromise.wrapError('Sent env to running instance. Terminating...')); }, From 2f13f1d9b36e677f98bb480935ad7dcf1019dcda Mon Sep 17 00:00:00 2001 From: Tereza Tomcova Date: Wed, 5 Oct 2016 19:01:25 +0200 Subject: [PATCH 118/163] Fixed crash on other platforms --- src/vs/code/electron-main/main.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 8248fb807ce..da2755debb6 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -25,7 +25,6 @@ import { AskpassChannel } from 'vs/workbench/parts/git/common/gitIpc'; import { GitAskpassService } from 'vs/workbench/parts/git/electron-main/askpassService'; import { spawnSharedProcess } from 'vs/code/node/sharedProcess'; import { Mutex } from 'windows-mutex'; -import { allowSetForegroundWindow } from 'windows-foreground-love'; import { LaunchService, ILaunchChannel, LaunchChannel, LaunchChannelClient } from './launch'; import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; @@ -305,7 +304,12 @@ function setupIPC(accessor: ServicesAccessor): TPromise { promise = service.getMainProcessId() .then(processId => { logService.log('Sending some foreground love to the running instance:', processId); - allowSetForegroundWindow(processId); + try { + const { allowSetForegroundWindow } = require.__$__nodeRequire('windows-foreground-love'); + allowSetForegroundWindow(processId); + } catch (e) { + // noop + } }); } From 052679a740b5bda3528369ab6937bc09cee90b28 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 7 Oct 2016 11:17:02 +0200 Subject: [PATCH 119/163] naming --- src/vs/workbench/browser/actions/toggleSidebarPosition.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/actions/toggleSidebarPosition.ts b/src/vs/workbench/browser/actions/toggleSidebarPosition.ts index ce54051829c..08d89b8e39a 100644 --- a/src/vs/workbench/browser/actions/toggleSidebarPosition.ts +++ b/src/vs/workbench/browser/actions/toggleSidebarPosition.ts @@ -17,7 +17,7 @@ import {IPartService, Position} from 'vs/workbench/services/part/common/partServ export class ToggleSidebarPositionAction extends Action { public static ID = 'workbench.action.toggleSidebarPosition'; - public static LABEL = nls.localize('togglePosition', "Toggle Side Bar Position"); + public static LABEL = nls.localize('toggleLocation', "Toggle Side Bar Location"); private static sidebarPositionConfigurationKey = 'workbench.sideBar.location'; From fb59b1b8f1e50ead3baf362a24a27546984a0e45 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 7 Oct 2016 11:24:22 +0200 Subject: [PATCH 120/163] remove shared process connection from ext host --- src/vs/workbench/node/extensionHostMain.ts | 3 +-- src/vs/workbench/node/extensionHostProcess.ts | 23 ++++--------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/node/extensionHostMain.ts b/src/vs/workbench/node/extensionHostMain.ts index 31c77f33aed..62460d02cb0 100644 --- a/src/vs/workbench/node/extensionHostMain.ts +++ b/src/vs/workbench/node/extensionHostMain.ts @@ -23,7 +23,6 @@ import {ExtHostThreadService} from 'vs/workbench/services/thread/common/extHostT import {RemoteTelemetryService} from 'vs/workbench/api/node/extHostTelemetry'; import {ExtensionScanner, MessagesCollector} from 'vs/workbench/node/extensionPoints'; import {IWorkspaceContextService, WorkspaceContextService} from 'vs/platform/workspace/common/workspace'; -import {Client} from 'vs/base/parts/ipc/node/ipc.net'; const DIRNAME = URI.parse(require.toUrl('./')).fsPath; const BASE_PATH = paths.normalize(paths.join(DIRNAME, '../../../..')); @@ -66,7 +65,7 @@ export class ExtensionHostMain { private _environment: IEnvironment; private _extensionService: ExtHostExtensionService; - constructor(remoteCom: IMainProcessExtHostIPC, initData: IInitData, sharedProcessClient: Client) { + constructor(remoteCom: IMainProcessExtHostIPC, initData: IInitData) { this._isTerminating = false; this._environment = initData.environment; diff --git a/src/vs/workbench/node/extensionHostProcess.ts b/src/vs/workbench/node/extensionHostProcess.ts index f37d2f14855..d60ec327d6b 100644 --- a/src/vs/workbench/node/extensionHostProcess.ts +++ b/src/vs/workbench/node/extensionHostProcess.ts @@ -8,7 +8,6 @@ import {onUnexpectedError} from 'vs/base/common/errors'; import { TPromise } from 'vs/base/common/winjs.base'; import { ExtensionHostMain, IInitData, exit } from 'vs/workbench/node/extensionHostMain'; -import { Client, connect } from 'vs/base/parts/ipc/node/ipc.net'; import { create as createIPC, IMainProcessExtHostIPC } from 'vs/platform/extensions/common/ipcRemoteCom'; import marshalling = require('vs/base/common/marshalling'); @@ -103,20 +102,8 @@ function connectToRenderer(): TPromise { }); } -function connectToSharedProcess(): TPromise { - return connect(process.env['VSCODE_SHARED_IPC_HOOK'], `extensionHost:${ process.env['VSCODE_WINDOW_ID'] }`); -} - -TPromise.join([connectToRenderer(), connectToSharedProcess()]) - .done(result => { - const renderer: IRendererConnection = result[0]; - const sharedProcessClient: Client = result[1]; - const extensionHostMain = new ExtensionHostMain(renderer.remoteCom, renderer.initData, sharedProcessClient); - - onTerminate = () => { - extensionHostMain.terminate(); - }; - - extensionHostMain.start() - .done(null, err => console.error(err)); - }); \ No newline at end of file +connectToRenderer().then(renderer => { + const extensionHostMain = new ExtensionHostMain(renderer.remoteCom, renderer.initData); + onTerminate = () => extensionHostMain.terminate(); + return extensionHostMain.start(); +}).done(null, err => console.error(err)); \ No newline at end of file From 307b58f24fceb9fd35aea6325ce028b16a77b6f3 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 7 Oct 2016 12:19:12 +0200 Subject: [PATCH 121/163] extract method --- src/vs/code/electron-main/main.ts | 47 ++++++++++++++++++------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index da2755debb6..fd59d598624 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -106,11 +106,13 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo // Setup Windows mutex let windowsMutex: Mutex = null; - try { - const Mutex = (require.__$__nodeRequire('windows-mutex')).Mutex; - windowsMutex = new Mutex(product.win32MutexName); - } catch (e) { - // noop + if (platform.isWindows) { + try { + const Mutex = (require.__$__nodeRequire('windows-mutex')).Mutex; + windowsMutex = new Mutex(product.win32MutexName); + } catch (e) { + // noop + } } // Register Main IPC services @@ -265,6 +267,25 @@ function setupIPC(accessor: ServicesAccessor): TPromise { const logService = accessor.get(ILogService); const environmentService = accessor.get(IEnvironmentService); + function allowSetForegroundWindow(service: LaunchChannelClient): TPromise { + let promise = TPromise.as(null); + if (platform.isWindows) { + promise = service.getMainProcessId() + .then(processId => { + logService.log('Sending some foreground love to the running instance:', processId); + + try { + const { allowSetForegroundWindow } = require.__$__nodeRequire('windows-foreground-love'); + allowSetForegroundWindow(processId); + } catch (e) { + // noop + } + }); + } + + return promise; + } + function setup(retry: boolean): TPromise { return serve(environmentService.mainIPCHandle).then(server => { if (platform.isMacintosh) { @@ -299,21 +320,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise { const channel = client.getChannel('launch'); const service = new LaunchChannelClient(channel); - let promise = TPromise.as(null); - if (platform.isWindows) { - promise = service.getMainProcessId() - .then(processId => { - logService.log('Sending some foreground love to the running instance:', processId); - try { - const { allowSetForegroundWindow } = require.__$__nodeRequire('windows-foreground-love'); - allowSetForegroundWindow(processId); - } catch (e) { - // noop - } - }); - } - - return promise + return allowSetForegroundWindow(service) .then(() => service.start(environmentService.args, process.env)) .then(() => client.dispose()) .then(() => TPromise.wrapError('Sent env to running instance. Terminating...')); From 3383ef7de0828bf507b7c4592e83aecdbb12b9dd Mon Sep 17 00:00:00 2001 From: isidor Date: Fri, 7 Oct 2016 13:47:54 +0200 Subject: [PATCH 122/163] use node-debug version 1.6.9 #13336 --- build/gulpfile.vscode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index af5a5fe1fc3..626358bbce4 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -39,7 +39,7 @@ const nodeModules = ['electron', 'original-fs'] // Build const builtInExtensions = [ - { name: 'ms-vscode.node-debug', version: '1.6.8' }, + { name: 'ms-vscode.node-debug', version: '1.6.9' }, { name: 'ms-vscode.node-debug2', version: '0.0.7' } ]; From 2b84bca4047b037f1960c27431cb0d7e97839da6 Mon Sep 17 00:00:00 2001 From: Robin Munn Date: Fri, 7 Oct 2016 19:23:31 +0700 Subject: [PATCH 123/163] Remove incorrect ANSI escape code for LF ANSI technically doesn't have an escape code for LF, since it just uses the 0x0A character. The regex \xA is incorrect (it should be \x0A) and is being treated as the two-character sequence "xA". But then once we've fixed that, replacing 0x0A with \n in removeAnsiEscapeCodes is a no-op. Better to just remove the str.replace(LF, '\n') call. Fixes #12608. --- src/vs/base/common/strings.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 9e35fefb235..93a86fc32f9 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -531,14 +531,12 @@ export function lcut(text: string, n: number): string { // Escape codes // http://en.wikipedia.org/wiki/ANSI_escape_code const EL = /\x1B\x5B[12]?K/g; // Erase in line -const LF = /\xA/g; // line feed const COLOR_START = /\x1b\[\d+m/g; // Color const COLOR_END = /\x1b\[0?m/g; // Color export function removeAnsiEscapeCodes(str: string): string { if (str) { str = str.replace(EL, ''); - str = str.replace(LF, '\n'); str = str.replace(COLOR_START, ''); str = str.replace(COLOR_END, ''); } From 428d4768e0f530286760563c60d65ada4edc031e Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Fri, 7 Oct 2016 14:59:05 +0200 Subject: [PATCH 124/163] Run extension host detached under Windows to ensure correct extension shutdown --- .../workbench/api/node/extHostExtensionService.ts | 13 ++++++++++--- src/vs/workbench/node/extensionHostMain.ts | 14 +++++++++++--- .../thread/electron-browser/threadService.ts | 8 ++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 137317c3415..700032a2bb4 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -148,16 +148,21 @@ export class ExtHostExtensionService extends AbstractExtensionService { + let result:TPromise = TPromise.as(void 0); + let extension = this._activatedExtensions[extensionId]; if (!extension) { - return; + return result; } // call deactivate if available try { if (typeof extension.module.deactivate === 'function') { - extension.module.deactivate(); + result = TPromise.wrap(extension.module.deactivate()).then(null, (err) => { + // TODO: Do something with err if this is not the shutdown case + return TPromise.as(void 0); + }); } } catch (err) { // TODO: Do something with err if this is not the shutdown case @@ -169,6 +174,8 @@ export class ExtHostExtensionService extends AbstractExtensionService { + // TODO: write to log once we have one + }); + + let allPromises: TPromise[] = []; try { let allExtensions = ExtensionsRegistry.getAllExtensionDescriptions(); let allExtensionsIds = allExtensions.map(ext => ext.id); let activatedExtensions = allExtensionsIds.filter(id => this._extensionService.isActivated(id)); - activatedExtensions.forEach((extensionId) => { - this._extensionService.deactivate(extensionId); + allPromises = activatedExtensions.map((extensionId) => { + return this._extensionService.deactivate(extensionId); }); } catch (err) { // TODO: write to log once we have one } + let extensionsDeactivated = TPromise.join(allPromises).then(() => void 0); + // Give extensions 1 second to wrap up any async dispose, then exit setTimeout(() => { - exit(); + TPromise.any([TPromise.timeout(4000), extensionsDeactivated]).then(() => exit(), () => exit()); }, 1000); } diff --git a/src/vs/workbench/services/thread/electron-browser/threadService.ts b/src/vs/workbench/services/thread/electron-browser/threadService.ts index 1acc78c7aea..f867f0854ae 100644 --- a/src/vs/workbench/services/thread/electron-browser/threadService.ts +++ b/src/vs/workbench/services/thread/electron-browser/threadService.ts @@ -12,6 +12,7 @@ import * as objects from 'vs/base/common/objects'; import * as strings from 'vs/base/common/strings'; import URI from 'vs/base/common/uri'; import {TPromise} from 'vs/base/common/winjs.base'; +import {isWindows} from 'vs/base/common/platform'; import {findFreePort} from 'vs/base/node/ports'; import {IMainProcessExtHostIPC, create} from 'vs/platform/extensions/common/ipcRemoteCom'; import {IMessageService, Severity} from 'vs/platform/message/common/message'; @@ -151,6 +152,13 @@ class ExtensionHostProcessManager { if (port) { opts.execArgv = ['--nolazy', (this.isExtensionDevelopmentDebugging ? '--debug-brk=' : '--debug=') + port]; } + // We only detach the extension host on windows. Linux and Mac orphan by default + // and detach under Linux and Mac create another process group. + if (isWindows) { + // We detach because we have noticed that when the renderer exits, its child processes + // (i.e. extension host) is taken down in a brutal fashion by the OS + opts.detached = true; + } // Run Extension Host as fork of current process this.extensionHostProcessHandle = fork(URI.parse(require.toUrl('bootstrap')).fsPath, ['--type=extensionHost'], opts); From 4edf8767499546db1942ef585c4b6e7e01fff853 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 7 Oct 2016 15:32:02 +0200 Subject: [PATCH 125/163] loosen all caps camel case filters fixes #13300 --- src/vs/base/common/filters.ts | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index f3e67f108f8..34ded84f892 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -179,13 +179,16 @@ function _matchesCamelCase(word: string, camelCaseWord: string, i: number, j: nu } } +interface ICamelCaseAnalysis { + upperPercent: number; + lowerPercent: number; + alphaPercent: number; + numericPercent: number; +} + // Heuristic to avoid computing camel case matcher for words that don't // look like camelCaseWords. -function isCamelCaseWord(word: string): boolean { - if (word.length > 60) { - return false; - } - +function analyzeCamelCaseWord(word: string): ICamelCaseAnalysis { let upper = 0, lower = 0, alpha = 0, numeric = 0, code = 0; for (let i = 0; i < word.length; i++) { @@ -202,6 +205,16 @@ function isCamelCaseWord(word: string): boolean { let alphaPercent = alpha / word.length; let numericPercent = numeric / word.length; + return { upperPercent, lowerPercent, alphaPercent, numericPercent }; +} + +function isUpperCaseWord(analysis: ICamelCaseAnalysis): boolean { + const { upperPercent, lowerPercent, alphaPercent, numericPercent } = analysis; + return lowerPercent === 0 && upperPercent > 0.6; +} + +function isCamelCaseWord(analysis: ICamelCaseAnalysis): boolean { + const { upperPercent, lowerPercent, alphaPercent, numericPercent } = analysis; return lowerPercent > 0.2 && upperPercent < 0.8 && alphaPercent > 0.6 && numericPercent < 0.2; } @@ -234,10 +247,20 @@ export function matchesCamelCase(word: string, camelCaseWord: string): IMatch[] return null; } - if (!isCamelCaseWord(camelCaseWord)) { + if (camelCaseWord.length > 60) { return null; } + const analysis = analyzeCamelCaseWord(camelCaseWord); + + if (!isCamelCaseWord(analysis)) { + if (!isUpperCaseWord(analysis)) { + return null; + } + + camelCaseWord = camelCaseWord.toLowerCase(); + } + let result: IMatch[] = null; let i = 0; From 7905486b424b687357a9645f90e44823e612b54b Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 6 Oct 2016 16:05:14 +0200 Subject: [PATCH 126/163] 0.7.2 for monaco-editor-core --- build/monaco/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/monaco/package.json b/build/monaco/package.json index e9b918f6983..78bf4f32070 100644 --- a/build/monaco/package.json +++ b/build/monaco/package.json @@ -1,7 +1,7 @@ { "name": "monaco-editor-core", "private": true, - "version": "0.7.1", + "version": "0.7.2", "description": "A browser based code editor", "author": "Microsoft Corporation", "license": "MIT", From 8e2502ea50801ed44867deae31bca2698496a552 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Thu, 6 Oct 2016 17:37:15 +0200 Subject: [PATCH 127/163] Fixes Microsoft/monaco-editor#160 --- .../browser/standalone/standaloneLanguages.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/vs/editor/browser/standalone/standaloneLanguages.ts b/src/vs/editor/browser/standalone/standaloneLanguages.ts index cb7e4442646..1dd17021bec 100644 --- a/src/vs/editor/browser/standalone/standaloneLanguages.ts +++ b/src/vs/editor/browser/standalone/standaloneLanguages.ts @@ -105,7 +105,24 @@ export function registerSignatureHelpProvider(languageId:string, provider:modes. * Register a hover provider (used by e.g. editor hover). */ export function registerHoverProvider(languageId:string, provider:modes.HoverProvider): IDisposable { - return modes.HoverProviderRegistry.register(languageId, provider); + return modes.HoverProviderRegistry.register(languageId, { + provideHover: (model:editorCommon.IReadOnlyModel, position:Position, token:CancellationToken): Thenable => { + let word = model.getWordAtPosition(position); + + return toThenable(provider.provideHover(model, position, token)).then((value) => { + if (!value) { + return; + } + if (!value.range && word) { + value.range = new Range(position.lineNumber, word.startColumn, position.column, word.endColumn); + } + if (!value.range) { + value.range = new Range(position.lineNumber, position.column, position.lineNumber, position.column); + } + return value; + }); + } + }); } /** From 9c60b989d4ea24362620649e1bb10f8c2d9531e0 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 7 Oct 2016 12:21:16 +0200 Subject: [PATCH 128/163] Fixes Microsoft/monaco-editor#175: bring back context menu functionality for `editor.addAction` --- src/vs/editor/common/commonCodeEditor.ts | 27 ++++++++++++++++++- src/vs/editor/common/editorCommon.ts | 14 ++++++++++ .../contextmenu/browser/contextmenu.ts | 11 ++++---- src/vs/monaco.d.ts | 14 ++++++++++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index 28d4a2debea..c74baecfea6 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -10,7 +10,7 @@ import {Disposable, IDisposable, dispose} from 'vs/base/common/lifecycle'; import {TPromise} from 'vs/base/common/winjs.base'; import {ServicesAccessor, IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {ServiceCollection} from 'vs/platform/instantiation/common/serviceCollection'; -import {IContextKey, IContextKeyServiceTarget, IContextKeyService} from 'vs/platform/contextkey/common/contextkey'; +import {ContextKeyExpr, IContextKey, IContextKeyServiceTarget, IContextKeyService} from 'vs/platform/contextkey/common/contextkey'; import {CommonEditorConfiguration} from 'vs/editor/common/config/commonEditorConfig'; import {DefaultConfig} from 'vs/editor/common/config/defaultConfig'; import {Cursor} from 'vs/editor/common/controller/cursor'; @@ -27,6 +27,8 @@ import {SplitLinesCollection} from 'vs/editor/common/viewModel/splitLinesCollect import {ViewModel} from 'vs/editor/common/viewModel/viewModelImpl'; import {hash} from 'vs/base/common/hash'; import {EditorModeContext} from 'vs/editor/common/modes/editorModeContext'; +import {MenuId, MenuRegistry, IMenuItem} from 'vs/platform/actions/common/actions'; +import {CommandsRegistry} from 'vs/platform/commands/common/commands'; import EditorContextKeys = editorCommon.EditorContextKeys; @@ -511,7 +513,30 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom ) { throw new Error('Invalid action descriptor, `id`, `label` and `run` are required properties!'); } + + // Generate a unique id to allow the same descriptor.id across multiple editor instances + let uniqueId = this.getId() + ':' + descriptor.id; + let action = new DynamicEditorAction(descriptor, this); + + // Register the command + CommandsRegistry.registerCommand(uniqueId, () => action.run()); + + if (descriptor.contextMenuGroupId) { + let menuItem: IMenuItem = { + command: { + id: uniqueId, + title: descriptor.label + }, + when: ContextKeyExpr.equals('editorId', this.getId()), + group: descriptor.contextMenuGroupId, + order: descriptor.contextMenuOrder || 0 + }; + + // Register the menu item + MenuRegistry.appendMenuItem(MenuId.EditorContext, menuItem); + } + this._actions[action.id] = action; } diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index e892b495887..08f35cc944f 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -3439,6 +3439,20 @@ export interface IActionDescriptor { * An array of keybindings for the action. */ keybindings?: number[]; + /** + * Control if the action should show up in the context menu and where. + * The context menu of the editor has these default: + * navigation - The navigation group comes first in all cases. + * 1_modification - This group comes next and contains commands that modify your code. + * 9_cutcopypaste - The last default group with the basic editing commands. + * You can also create your own group. + * Defaults to null (don't show in context menu). + */ + contextMenuGroupId?: string; + /** + * Control the order in the context menu group. + */ + contextMenuOrder?: number; /** * The keybinding rule. */ diff --git a/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts b/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts index 8b131f667fb..1e2d9321168 100644 --- a/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/browser/contextmenu.ts @@ -16,7 +16,7 @@ import {ActionItem, Separator} from 'vs/base/browser/ui/actionbar/actionbar'; import {IContextMenuService, IContextViewService} from 'vs/platform/contextview/browser/contextView'; import {IKeybindingService} from 'vs/platform/keybinding/common/keybinding'; import {IContextKeyService} from 'vs/platform/contextkey/common/contextkey'; -import {IMenuService, IMenu, MenuId} from 'vs/platform/actions/common/actions'; +import {IMenuService, MenuId} from 'vs/platform/actions/common/actions'; import {ICommonCodeEditor, IEditorContribution, MouseTargetType, EditorContextKeys, IScrollEvent} from 'vs/editor/common/editorCommon'; import {editorAction, ServicesAccessor, EditorAction} from 'vs/editor/common/editorCommonExtensions'; import {ICodeEditor, IEditorMouseEvent} from 'vs/editor/browser/editorBrowser'; @@ -39,7 +39,6 @@ export class ContextMenuController implements IEditorContribution { private _toDispose: IDisposable[] = []; private _contextMenuIsBeingShownCount: number = 0; private _editor: ICodeEditor; - private _contextMenu: IMenu; constructor( editor: ICodeEditor, @@ -51,9 +50,6 @@ export class ContextMenuController implements IEditorContribution { ) { this._editor = editor; - this._contextMenu = this._menuService.createMenu(MenuId.EditorContext, this._contextKeyService); - this._toDispose.push(this._contextMenu); - this._toDispose.push(this._editor.onContextMenu((e: IEditorMouseEvent) => this._onContextMenu(e))); this._toDispose.push(this._editor.onDidScrollChange((e: IScrollEvent) => { if (this._contextMenuIsBeingShownCount > 0) { @@ -129,7 +125,10 @@ export class ContextMenuController implements IEditorContribution { private _getMenuActions(): IAction[] { const result: IAction[] = []; - const groups = this._contextMenu.getActions(); + + let contextMenu = this._menuService.createMenu(MenuId.EditorContext, this._contextKeyService); + const groups = contextMenu.getActions(); + contextMenu.dispose(); for (let group of groups) { const [, actions] = group; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index a53abe82de2..316de4bf351 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2788,6 +2788,20 @@ declare module monaco.editor { * An array of keybindings for the action. */ keybindings?: number[]; + /** + * Control if the action should show up in the context menu and where. + * The context menu of the editor has these default: + * navigation - The navigation group comes first in all cases. + * 1_modification - This group comes next and contains commands that modify your code. + * 9_cutcopypaste - The last default group with the basic editing commands. + * You can also create your own group. + * Defaults to null (don't show in context menu). + */ + contextMenuGroupId?: string; + /** + * Control the order in the context menu group. + */ + contextMenuOrder?: number; /** * The keybinding rule. */ From 527f8bb6693280877c7ec26005bdea1927254cfb Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 7 Oct 2016 15:03:38 +0200 Subject: [PATCH 129/163] monaco-editor-core v0.7.3 --- build/monaco/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/monaco/package.json b/build/monaco/package.json index 78bf4f32070..2d5c119e81b 100644 --- a/build/monaco/package.json +++ b/build/monaco/package.json @@ -1,7 +1,7 @@ { "name": "monaco-editor-core", "private": true, - "version": "0.7.2", + "version": "0.7.3", "description": "A browser based code editor", "author": "Microsoft Corporation", "license": "MIT", From 6e52a9f082ab01dfcb0b4cdbaa5100903aa59a78 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 7 Oct 2016 16:02:59 +0200 Subject: [PATCH 130/163] fixes #13298 --- src/vs/base/common/comparers.ts | 14 +++++++++----- src/vs/base/test/common/comparers.test.ts | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 src/vs/base/test/common/comparers.test.ts diff --git a/src/vs/base/common/comparers.ts b/src/vs/base/common/comparers.ts index 7d29ba9a8b0..a90bc8f98a5 100644 --- a/src/vs/base/common/comparers.ts +++ b/src/vs/base/common/comparers.ts @@ -7,22 +7,26 @@ import scorer = require('vs/base/common/scorer'); import strings = require('vs/base/common/strings'); -const FileNameMatch = /^(.*)\.([^.]*)|([^.]+)$/; +const FileNameMatch = /^([^.]*)(\.(.*))?$/; export function compareFileNames(one: string, other: string): number { let oneMatch = FileNameMatch.exec(one.toLowerCase()); let otherMatch = FileNameMatch.exec(other.toLowerCase()); - let oneName = oneMatch[1] || oneMatch[3] || ''; - let oneExtension = oneMatch[2] || ''; + let oneName = oneMatch[1] || ''; + let oneExtension = oneMatch[3] || ''; - let otherName = otherMatch[1] || otherMatch[3] || ''; - let otherExtension = otherMatch[2] || ''; + let otherName = otherMatch[1] || ''; + let otherExtension = otherMatch[3] || ''; if (oneName !== otherName) { return oneName < otherName ? -1 : 1; } + if (oneExtension === otherExtension) { + return 0; + } + return oneExtension < otherExtension ? -1 : 1; } diff --git a/src/vs/base/test/common/comparers.test.ts b/src/vs/base/test/common/comparers.test.ts new file mode 100644 index 00000000000..c038fe981e0 --- /dev/null +++ b/src/vs/base/test/common/comparers.test.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { compareFileNames } from 'vs/base/common/Comparers'; +import * as assert from 'assert'; + +suite('Comparers', () => { + + test('compareFileNames', () => { + + assert(compareFileNames('', '') === 0, 'empty should be equal'); + assert(compareFileNames('abc', 'abc') === 0, 'equal names should be equal'); + assert(compareFileNames('.abc', '.abc') === 0, 'equal full names should be equal'); + assert(compareFileNames('.env', '.env.example') < 0); + assert(compareFileNames('.env.example', '.gitattributes') < 0); + }); +}); From 8bed8f36e345c828d72c421f416f33ae3655c275 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 7 Oct 2016 16:49:20 +0200 Subject: [PATCH 131/163] bad casing --- src/vs/base/test/common/comparers.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/base/test/common/comparers.test.ts b/src/vs/base/test/common/comparers.test.ts index c038fe981e0..b1b475303e0 100644 --- a/src/vs/base/test/common/comparers.test.ts +++ b/src/vs/base/test/common/comparers.test.ts @@ -5,7 +5,7 @@ 'use strict'; -import { compareFileNames } from 'vs/base/common/Comparers'; +import { compareFileNames } from 'vs/base/common/comparers'; import * as assert from 'assert'; suite('Comparers', () => { From 2ea4e8e66b5bf0e55719cfdd0aa7216f7d234a5d Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 7 Oct 2016 16:44:41 +0200 Subject: [PATCH 132/163] Remove vs/languages/razor --- src/vs/editor/test/common/mocks/mockMode.ts | 4 +- src/vs/editor/test/common/modesUtil.ts | 76 --- src/vs/languages/buildfile.js | 5 - .../razor/common/csharpTokenization.ts | 591 ------------------ .../razor/common/razor.contribution.ts | 16 - src/vs/languages/razor/common/razor.ts | 154 ----- .../languages/razor/common/razorTokenTypes.ts | 7 - src/vs/languages/razor/common/razorWorker.ts | 46 -- src/vs/languages/razor/common/vsxml.ts | 234 ------- .../languages/razor/common/vsxmlTokenTypes.ts | 8 - .../languages/razor/test/common/razor.test.ts | 177 ------ 11 files changed, 2 insertions(+), 1316 deletions(-) delete mode 100644 src/vs/languages/razor/common/csharpTokenization.ts delete mode 100644 src/vs/languages/razor/common/razor.contribution.ts delete mode 100644 src/vs/languages/razor/common/razor.ts delete mode 100644 src/vs/languages/razor/common/razorTokenTypes.ts delete mode 100644 src/vs/languages/razor/common/razorWorker.ts delete mode 100644 src/vs/languages/razor/common/vsxml.ts delete mode 100644 src/vs/languages/razor/common/vsxmlTokenTypes.ts delete mode 100644 src/vs/languages/razor/test/common/razor.test.ts diff --git a/src/vs/editor/test/common/mocks/mockMode.ts b/src/vs/editor/test/common/mocks/mockMode.ts index 2e38ea910be..054d572c477 100644 --- a/src/vs/editor/test/common/mocks/mockMode.ts +++ b/src/vs/editor/test/common/mocks/mockMode.ts @@ -4,12 +4,12 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {IMode, IState, IStream, ITokenizationResult, ITokenizationSupport, TokenizationRegistry} from 'vs/editor/common/modes'; +import {IMode, IState, IStream, ITokenizationResult, TokenizationRegistry} from 'vs/editor/common/modes'; import {AbstractState} from 'vs/editor/common/modes/abstractState'; import {TokenizationSupport} from 'vs/editor/common/modes/supports/tokenizationSupport'; let instanceCount = 0; -export function generateMockModeId(): string { +function generateMockModeId(): string { return 'mockMode' + (++instanceCount); } diff --git a/src/vs/editor/test/common/modesUtil.ts b/src/vs/editor/test/common/modesUtil.ts index c57c8bf6b0f..4cd5deba3d3 100644 --- a/src/vs/editor/test/common/modesUtil.ts +++ b/src/vs/editor/test/common/modesUtil.ts @@ -5,11 +5,7 @@ 'use strict'; import * as assert from 'assert'; -import {Model} from 'vs/editor/common/model/model'; import * as modes from 'vs/editor/common/modes'; -import {RichEditSupport, LanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; -import {Token} from 'vs/editor/common/core/token'; -import {generateMockModeId} from 'vs/editor/test/common/mocks/mockMode'; export interface ITestToken { startIndex: number; @@ -21,10 +17,6 @@ export interface ITestItem { tokens: ITestToken[]; } -export function assertWords(actual:string[], expected:string[], message?:string): void { - assert.deepEqual(actual, expected, message); -} - export function assertTokenization(tokenizationSupport: modes.ITokenizationSupport, tests: ITestItem[]): void { var state = tokenizationSupport.getInitialState(); for (var i = 0, len = tests.length; i < len; i++) { @@ -37,71 +29,3 @@ export function assertTokenization(tokenizationSupport: modes.ITokenizationSuppo state = result.endState; } } - -export interface IOnEnterAsserter { - nothing(oneLineAboveText:string, beforeText:string, afterText:string): void; - indents(oneLineAboveText:string, beforeText:string, afterText:string): void; - outdents(oneLineAboveText:string, beforeText:string, afterText:string): void; - indentsOutdents(oneLineAboveText:string, beforeText:string, afterText:string): void; -} - -export function createOnEnterAsserter(conf: LanguageConfiguration): IOnEnterAsserter { - const modeId = generateMockModeId(); - - const assertOne = (oneLineAboveText:string, beforeText:string, afterText:string, expected: modes.IndentAction) => { - let model = Model.createFromString( - [ oneLineAboveText, beforeText + afterText ].join('\n'), - undefined, - modeId - ); - let richEditSupport = new RichEditSupport(modeId, null, conf); - let actual = richEditSupport.onEnter.onEnter(model, { lineNumber: 2, column: beforeText.length + 1 }); - if (expected === modes.IndentAction.None) { - assert.equal(actual, null, oneLineAboveText + '\\n' + beforeText + '|' + afterText); - } else { - assert.equal(actual.indentAction, expected, oneLineAboveText + '\\n' + beforeText + '|' + afterText); - } - model.dispose(); - }; - - return { - nothing: (oneLineAboveText:string, beforeText:string, afterText:string): void => { - assertOne(oneLineAboveText, beforeText, afterText, modes.IndentAction.None); - }, - indents: (oneLineAboveText:string, beforeText:string, afterText:string): void => { - assertOne(oneLineAboveText, beforeText, afterText, modes.IndentAction.Indent); - }, - outdents: (oneLineAboveText:string, beforeText:string, afterText:string): void => { - assertOne(oneLineAboveText, beforeText, afterText, modes.IndentAction.Outdent); - }, - indentsOutdents: (oneLineAboveText:string, beforeText:string, afterText:string): void => { - assertOne(oneLineAboveText, beforeText, afterText, modes.IndentAction.IndentOutdent); - } - }; -} - -export function executeTests(tokenizationSupport: modes.ITokenizationSupport, tests:ITestItem[][]): void { - for (var i = 0, len = tests.length; i < len; i++) { - assert.ok(true, 'TEST #' + i); - executeTest(tokenizationSupport, tests[i]); - } -} - -function executeTest(tokenizationSupport: modes.ITokenizationSupport, tests:ITestItem[]): void { - var state = tokenizationSupport.getInitialState(); - for (var i = 0, len = tests.length; i < len; i++) { - assert.ok(true, tests[i].line); - - var result = tokenizationSupport.tokenize(tests[i].line, state); - - if (tests[i].tokens) { - assertTokens(result.tokens, tests[i].tokens, 'Tokenizing line ' + tests[i].line); - } - - state = result.endState; - } -} - -function assertTokens(actual:Token[], expected:ITestToken[], message?:string): void { - assert.deepEqual(actual, expected, message + ': ' + JSON.stringify(actual, null, '\t')); -} diff --git a/src/vs/languages/buildfile.js b/src/vs/languages/buildfile.js index 0fea1f9007d..b2b3871c120 100644 --- a/src/vs/languages/buildfile.js +++ b/src/vs/languages/buildfile.js @@ -49,10 +49,5 @@ exports.collectModules = function(args) { // .combine(worker) // .define('vs/languages/html/common/htmlWorker', ['vs/languages/lib/common/beautify-html']); - // // ---- razor ----------------------------------- - // common.define('vs/languages/razor/common/razor', ['vs/languages/html/common/html']) - // .combine(worker) - // .define('vs/languages/razor/common/razorWorker', ['vs/languages/html/common/htmlWorker', 'vs/languages/lib/common/beautify-html'] ); - return result; }; \ No newline at end of file diff --git a/src/vs/languages/razor/common/csharpTokenization.ts b/src/vs/languages/razor/common/csharpTokenization.ts deleted file mode 100644 index 434323a1b3f..00000000000 --- a/src/vs/languages/razor/common/csharpTokenization.ts +++ /dev/null @@ -1,591 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import objects = require('vs/base/common/objects'); -import Modes = require('vs/editor/common/modes'); -import htmlMode = require('vs/languages/html/common/html'); -import VSXML = require('vs/languages/razor/common/vsxml'); -import {AbstractState} from 'vs/editor/common/modes/abstractState'; -import {isDigit} from 'vs/editor/common/modes/abstractMode'; -import razorTokenTypes = require('vs/languages/razor/common/razorTokenTypes'); - -var htmlTokenTypes = htmlMode.htmlTokenTypes; - -var punctuations = '+-*%&|^~!=<>/?;:.,'; -var separators = '+-*/%&|^~!=<>(){}[]\"\'\\/?;:.,'; -var whitespace = '\t '; - -var brackets = (function() { - - let bracketsSource = [ - { tokenType:'punctuation.bracket.cs', open: '{', close: '}' }, - { tokenType:'punctuation.array.cs', open: '[', close: ']' }, - { tokenType:'punctuation.parenthesis.cs', open: '(', close: ')' } - ]; - - let MAP: { - [text:string]:{ - tokenType: string; - } - } = Object.create(null); - - for (let i = 0; i < bracketsSource.length; i++) { - let bracket = bracketsSource[i]; - MAP[bracket.open] = { - tokenType: bracket.tokenType, - }; - MAP[bracket.close] = { - tokenType: bracket.tokenType, - }; - } - - return { - stringIsBracket: (text:string): boolean => { - return !!MAP[text]; - }, - tokenTypeFromString: (text:string): string => { - return MAP[text].tokenType; - } - }; -})(); - -var isKeyword = objects.createKeywordMatcher([ - 'abstract', 'as', 'async', 'await', 'base', 'bool', - 'break', 'by', 'byte', 'case', - 'catch', 'char', 'checked', 'class', - 'const', 'continue', 'decimal', 'default', - 'delegate', 'do', 'double', 'descending', - 'explicit', 'event', 'extern', 'else', - 'enum', 'false', 'finally', 'fixed', - 'float', 'for', 'foreach', 'from', - 'goto', 'group', 'if', 'implicit', - 'in', 'int', 'interface', 'internal', - 'into', 'is', 'lock', 'long', 'nameof', - 'new', 'null', 'namespace', 'object', - 'operator', 'out', 'override', 'orderby', - 'params', 'private', 'protected', 'public', - 'readonly', 'ref', 'return', 'switch', - 'struct', 'sbyte', 'sealed', 'short', - 'sizeof', 'stackalloc', 'static', 'string', - 'select', 'this', 'throw', 'true', - 'try', 'typeof', 'uint', 'ulong', - 'unchecked', 'unsafe', 'ushort', 'using', - 'var', 'virtual', 'volatile', 'void', 'when', - 'while', 'where', 'yield', - 'model', 'inject' // Razor specific -]); - -var ispunctuation = (character:string) => { - return punctuations.indexOf(character) > -1; -}; - -export abstract class CSState extends AbstractState { - - public name:string; - public parent:AbstractState; - - constructor(modeId:string, name:string, parent:AbstractState) { - super(modeId); - this.name = name; - this.parent = parent; - } - - public equals(other:Modes.IState):boolean { - if (!super.equals(other)) { - return false; - } - var otherCSState:CSState = other; - return (other instanceof CSState) && (this.getModeId() === otherCSState.getModeId()) && (this.name === otherCSState.name) && ((this.parent === null && otherCSState.parent === null) || (this.parent !== null && this.parent.equals(otherCSState.parent))); - } -} - -class CSString extends CSState { - - private isAtBeginning:boolean; - private punctuation:string; - - constructor(modeId:string, parent:AbstractState, punctuation:string) { - super(modeId, 'string', parent); - this.isAtBeginning = true; - this.punctuation = punctuation; - } - - public makeClone():CSString { - return new CSString(this.getModeId(), this.parent ? this.parent.clone() : null, this.punctuation); - } - - public equals(other:CSString):boolean { - return super.equals(other) && this.punctuation === other.punctuation; - } - - public tokenize(stream:Modes.IStream):Modes.ITokenizationResult { - var readChars = this.isAtBeginning ? 1 : 0; - this.isAtBeginning = false; - while (!stream.eos()) { - var c = stream.next(); - if (c === '\\') { - if (readChars === 0) { - if (stream.eos()) { - return { type: 'string.escape.cs' }; - } else { - stream.next(); - if (stream.eos()) { - return { type: 'string.escape.cs', nextState: this.parent }; - } else { - return { type: 'string.escape.cs' }; - } - } - } else { - stream.goBack(1); - return { type: 'string.cs' }; - } - } else if (c === this.punctuation) { - break; - } - readChars += 1; - } - return { type: 'string.cs', nextState: this.parent }; - } -} - -class CSVerbatimString extends CSState { - - constructor(modeId:string, parent:AbstractState) { - super(modeId, 'verbatimstring', parent); - } - - public makeClone():CSVerbatimString { - return new CSVerbatimString(this.getModeId(), this.parent ? this.parent.clone() : null); - } - - public tokenize(stream:Modes.IStream):Modes.ITokenizationResult { - while (!stream.eos()) { - var token = stream.next(); - if (token === '"') { - if (!stream.eos() && stream.peek() === '"') { - stream.next(); - } else { - return { type: 'string.cs', nextState: this.parent }; - } - } - } - return { type: 'string.cs' }; - } -} - -class CSNumber extends CSState { - private firstDigit:string; - - constructor(modeId:string, parent:AbstractState, firstDigit:string) { - super(modeId, 'number', parent); - this.firstDigit = firstDigit; - } - - public makeClone():CSNumber { - return new CSNumber(this.getModeId(), this.parent ? this.parent.clone() : null, this.firstDigit); - } - - public tokenize(stream:Modes.IStream):Modes.ITokenizationResult { - var character = this.firstDigit; - var base = 10, isDecimal = false, isExponent = false; - if (character === '0' && !stream.eos()) { - character = stream.peek(); - if (character === 'x') { - base = 16; - } else if (character === '.') { - base = 10; - } else { - return { type: 'number.cs', nextState: this.parent }; - } - stream.next(); - } - while (!stream.eos()) { - character = stream.peek(); - if (isDigit(character, base)) { - stream.next(); - } else if (base === 10) { - if (character === '.' && !isExponent && !isDecimal) { - isDecimal = true; - stream.next(); - } else if (character.toLowerCase() === 'e' && !isExponent) { - isExponent = true; - stream.next(); - if (!stream.eos() && stream.peek() === '-') { - stream.next(); - } - } else if (character.toLowerCase() === 'f' || character.toLowerCase() === 'd') { - stream.next(); - break; - } else { - break; - } - } else { - break; - } - } - var tokenType = 'number'; - if (base === 16) { - tokenType += '.hex'; - } - return { type: tokenType + '.cs', nextState: this.parent }; - } -} - -// the multi line comment -export class CSComment extends CSState { - private commentChar:string; - - constructor(modeId:string, parent:AbstractState, commentChar:string) { - super(modeId, 'comment', parent); - this.commentChar = commentChar; - } - - public makeClone():CSComment { - return new CSComment(this.getModeId(), this.parent ? this.parent.clone() : null, this.commentChar); - } - - public tokenize(stream:Modes.IStream):Modes.ITokenizationResult { - while (!stream.eos()) { - var token = stream.next(); - if (token === '*' && !stream.eos() && !stream.peekWhitespace() && stream.peek() === this.commentChar) { - stream.next(); - return { type: 'comment.cs', nextState: this.parent}; - } - } - return { type: 'comment.cs' }; - } -} - -export class CSStatement extends CSState implements VSXML.IVSXMLWrapperState { - private level:number; - private plevel:number; - private razorMode:boolean; - private expression:boolean; - private vsState: VSXML.VSXMLState; - private firstToken: boolean; - private firstTokenWasKeyword: boolean; - - constructor(modeId:string, parent: AbstractState, level: number, plevel: number, razorMode: boolean, - expression: boolean, firstToken: boolean, firstTokenWasKeyword: boolean) { - super(modeId, 'expression', parent); - this.level = level; - this.plevel = plevel; - this.razorMode = razorMode; - this.expression = expression; - this.vsState = new VSXML.VSXMLExpression(modeId, null); - this.firstToken = firstToken; - this.firstTokenWasKeyword = firstTokenWasKeyword; - } - - public setVSXMLState(newVSState:VSXML.VSXMLState):void { - this.vsState = newVSState; - } - - public makeClone():CSStatement { - var st = new CSStatement(this.getModeId(), this.parent ? this.parent.clone() : null, this.level, - this.plevel, this.razorMode, this.expression, this.firstToken, this.firstTokenWasKeyword); - if (this.vsState !== null) { - st.setVSXMLState(this.vsState.clone()); - } - return st; - } - - public equals(other:Modes.IState):boolean { - return super.equals(other) && - (other instanceof CSStatement) && - ((this.vsState === null && (other).vsState === null) || - (this.vsState !== null && this.vsState.equals((other).vsState))); - } - - public tokenize(stream:Modes.IStream):Modes.ITokenizationResult { - stream.setTokenRules(separators, whitespace); - if (stream.skipWhitespace().length > 0) { - return { type: '' }; - } - return this.stateTokenize(stream); - } - - public stateTokenize(stream:Modes.IStream):Modes.ITokenizationResult { - - if (isDigit(stream.peek(), 10)) { - this.firstToken = false; - return { nextState: new CSNumber(this.getModeId(), this, stream.next()) }; - } - - var token = stream.nextToken(); - var acceptNestedModes = !this.firstTokenWasKeyword; - var nextStateAtEnd = (this.level <= 0 && this.plevel <= 0 && stream.eos() ? this.parent : undefined); - - if (stream.eos()) { - this.firstTokenWasKeyword = false; // Set this for the state starting on the next line. - } - - if (isKeyword(token)) { - if (this.level <= 0) { // if we find a keyword outside of a block, we know that we are outside of an expression - this.expression = false; - } - if (this.firstToken) { - this.firstTokenWasKeyword = true; - } - return { type: 'keyword.cs' }; - } - - this.firstToken = false; - - if (this.razorMode && token === '<' && acceptNestedModes) { - if (!stream.eos() && /[_:!\/\w]/.test(stream.peek())) { - return { nextState: new CSSimpleHTML(this.getModeId(), this, htmlMode.States.Content) }; - } - } - - // exit expressions on anything that doesn't look like part of the same expression - if (this.razorMode && this.expression && this.level <= 0 && this.plevel <= 0&& !stream.eos()) { - if (!/^(\.|\[|\(|\{\w+)$/.test(stream.peekToken())) { - nextStateAtEnd = this.parent; - } - } - - if (token === '/') { - if (!stream.eos() && !stream.peekWhitespace()) { - switch(stream.peekToken()) { - case '/': - stream.nextToken(); - if (!stream.eos() && stream.peekToken() === '/') { - stream.nextToken(); - if (stream.eos()) { - return { - type: 'comment.vs' - }; - } - if (stream.peekToken() !== '/') { - return { - type: 'comment.vs', - nextState: new VSXML.VSXMLEmbeddedState(this.getModeId(), this.vsState, this) - }; - } - } - stream.advanceToEOS(); - return { type: 'comment.cs' }; - case '*': - stream.nextToken(); - return { nextState: new CSComment(this.getModeId(), this, '/') }; - } - } - return { type: 'punctuation.cs', nextState: nextStateAtEnd }; - } - if (token === '@') { // a verbatim string (or a razor construct) - if (!stream.eos()) { - switch(stream.peekToken()) { - case '"': - stream.nextToken(); - return { nextState: new CSVerbatimString(this.getModeId(), this) }; - case '*': - stream.nextToken(); - return { nextState: new CSComment(this.getModeId(), this, '@') }; - } - } - } - if (/@?\w+/.test(token)) { - return { type: 'ident.cs', nextState: nextStateAtEnd }; - } - - if (token === '"' || token === '\'') { // string or character - return { nextState: new CSString(this.getModeId(), this, token) }; - } - if (brackets.stringIsBracket(token)) { - - var tr: Modes.ITokenizationResult = { - type: brackets.tokenTypeFromString(token), - nextState: nextStateAtEnd - }; - - if (this.razorMode) { - if (token === '{') { - this.expression = false; // whenever we enter a block, we exit expression mode - this.level++; - if (this.level === 1) { - tr.type = razorTokenTypes.EMBED_CS; - tr.nextState = undefined; - } - } - if (token === '}') { - this.level--; - if (this.level <= 0) { - tr.type = razorTokenTypes.EMBED_CS; - tr.nextState = this.parent; - } - } - if (this.expression) { - if (token === '(') { - this.plevel++; - if (this.plevel === 1) { - tr.type = razorTokenTypes.EMBED_CS; - tr.nextState = undefined; - } - } - if (token === ')') { - this.plevel--; - if (this.expression && this.plevel <= 0) { // we only leave csharp mode if we are in expression mode - tr.type = razorTokenTypes.EMBED_CS; - tr.nextState = this.parent; - } - } - if (token === '[') { - this.plevel++; - tr.nextState = undefined; - } - if (token === ']') { - this.plevel--; - } - } - } - return tr; - } - - if (ispunctuation(token)) { - return { type: 'punctuation.cs', nextState: nextStateAtEnd }; - } - - if (this.razorMode && this.expression && this.plevel <= 0) { // in razor mode exit on non-keywords in expressions - return { type: '', nextState: this.parent }; - } - - return { type: '', nextState: nextStateAtEnd }; - } -} - -// this state always returns to parent state if it leaves a html tag -class CSSimpleHTML extends CSState { - private state:htmlMode.States; - - constructor(modeId:string, parent:AbstractState, state:htmlMode.States) { - super(modeId, 'number', parent); - this.state = state; - } - - public makeClone():CSSimpleHTML { - return new CSSimpleHTML(this.getModeId(), this.parent ? this.parent.clone() : null, this.state); - } - - private nextName(stream:Modes.IStream):string { - return stream.advanceIfRegExp(/^[_:\w][_:\w-.\d]*/); - } - - private nextAttrValue(stream:Modes.IStream):string { - return stream.advanceIfRegExp(/^('|').*?\1/); - } - - public tokenize(stream:Modes.IStream):Modes.ITokenizationResult { - - switch (this.state) { - - case htmlMode.States.WithinComment: - if (stream.advanceUntil('-->', false).length > 0) { - return { type: htmlTokenTypes.COMMENT}; - } - if (stream.advanceIfString('-->').length > 0) { - this.state = htmlMode.States.Content; - return { type: htmlTokenTypes.DELIM_COMMENT, nextState: this.parent }; - } - break; - - case htmlMode.States.WithinDoctype: - if (stream.advanceUntil('>', false).length > 0) { - return { type: htmlTokenTypes.DOCTYPE }; - } - if (stream.advanceIfString('>').length > 0) { - this.state = htmlMode.States.Content; - return { type: htmlTokenTypes.DELIM_DOCTYPE, nextState: this.parent }; - } - break; - - case htmlMode.States.Content: - if (stream.advanceIfString('!--').length > 0){ - this.state = htmlMode.States.WithinComment; - return { type: htmlTokenTypes.DELIM_COMMENT }; - } - if (stream.advanceIfRegExp(/!DOCTYPE/i).length > 0) { - this.state = htmlMode.States.WithinDoctype; - return { type: htmlTokenTypes.DELIM_DOCTYPE }; - } - if (stream.advanceIfString('/').length > 0){ - this.state = htmlMode.States.OpeningEndTag; - return { type: htmlTokenTypes.DELIM_END }; - } - this.state = htmlMode.States.OpeningStartTag; - return { type: htmlTokenTypes.DELIM_START }; - - case htmlMode.States.OpeningEndTag: { - let tagName = this.nextName(stream); - if (tagName.length > 0) { - return { - type: htmlTokenTypes.getTag(tagName) - }; - } - if (stream.advanceIfString('>').length > 0) { - this.state = htmlMode.States.Content; - return { type: htmlTokenTypes.DELIM_END, nextState: this.parent }; - } - stream.advanceUntil('>', false); - return { type: '' }; - } - - case htmlMode.States.OpeningStartTag: { - let tagName = this.nextName(stream); - if (tagName.length > 0) { - this.state = htmlMode.States.WithinTag; - return { - type: htmlTokenTypes.getTag(tagName) - }; - } - break; - } - - case htmlMode.States.WithinTag: - if (stream.skipWhitespace().length > 0) { - return { type: '' }; - } - var name:string = this.nextName(stream); - if (name.length > 0) { - this.state = htmlMode.States.AttributeName; - return { type: htmlTokenTypes.ATTRIB_NAME }; - } - if (stream.advanceIfRegExp(/^\/?>/).length > 0) { - this.state = htmlMode.States.Content; - return { type: htmlTokenTypes.DELIM_START, nextState: this.parent }; - } - stream.next(); - return { type: '' }; - - case htmlMode.States.AttributeName: - if (stream.skipWhitespace().length > 0 || stream.eos()) { - return { type: '' }; - } - if (stream.peek() === '=') { - stream.next(); - this.state = htmlMode.States.AttributeValue; - return { type: '' }; - } - this.state = htmlMode.States.WithinTag; - return this.tokenize(stream); // no advance yet - jump to WithinTag - - case htmlMode.States.AttributeValue: - if (stream.skipWhitespace().length > 0 || stream.eos()) { - return { type: '' }; - } - var value = this.nextAttrValue(stream); - if (value.length > 0) { - this.state = htmlMode.States.WithinTag; - return { type: htmlTokenTypes.ATTRIB_VALUE }; - } - this.state = htmlMode.States.WithinTag; - return this.tokenize(stream); // no advance yet - jump to WithinTag - } - stream.next(); - this.state = htmlMode.States.Content; - return { type: '', nextState: this.parent }; - } -} \ No newline at end of file diff --git a/src/vs/languages/razor/common/razor.contribution.ts b/src/vs/languages/razor/common/razor.contribution.ts deleted file mode 100644 index 82b04d22fe3..00000000000 --- a/src/vs/languages/razor/common/razor.contribution.ts +++ /dev/null @@ -1,16 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; - -ModesRegistry.registerCompatMode({ - id: 'razor', - extensions: ['.cshtml'], - aliases: ['Razor', 'razor'], - mimetypes: ['text/x-cshtml'], - moduleId: 'vs/languages/razor/common/razor', - ctorName: 'RAZORMode' -}); diff --git a/src/vs/languages/razor/common/razor.ts b/src/vs/languages/razor/common/razor.ts deleted file mode 100644 index 51ffd3e9772..00000000000 --- a/src/vs/languages/razor/common/razor.ts +++ /dev/null @@ -1,154 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import modes = require('vs/editor/common/modes'); -import htmlMode = require('vs/languages/html/common/html'); -import csharpTokenization = require('vs/languages/razor/common/csharpTokenization'); -import {createWordRegExp, ModeWorkerManager} from 'vs/editor/common/modes/abstractMode'; -import razorTokenTypes = require('vs/languages/razor/common/razorTokenTypes'); -import {RAZORWorker} from 'vs/languages/razor/common/razorWorker'; -import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; -import {IModeService} from 'vs/editor/common/services/modeService'; -import {LanguageConfigurationRegistry, LanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; -import {wireCancellationToken} from 'vs/base/common/async'; -import {ICompatWorkerService} from 'vs/editor/common/services/compatWorkerService'; -import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; -import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; -import {TokenizationSupport, ILeavingNestedModeData} from 'vs/editor/common/modes/supports/tokenizationSupport'; - -// for a brief description of the razor syntax see http://www.mikesdotnetting.com/Article/153/Inline-Razor-Syntax-Overview - -class RAZORState extends htmlMode.State { - - constructor(modeId:string, kind:htmlMode.States, lastTagName:string, lastAttributeName:string, embeddedContentType:string, attributeValueQuote:string, attributeValueLength:number) { - super(modeId, kind, lastTagName, lastAttributeName, embeddedContentType, attributeValueQuote, attributeValueLength); - } - - public makeClone():RAZORState { - return new RAZORState(this.getModeId(), this.kind, this.lastTagName, this.lastAttributeName, this.embeddedContentType, this.attributeValueQuote, this.attributeValueLength); - } - - public equals(other:modes.IState):boolean { - if (other instanceof RAZORState) { - return ( - super.equals(other) - ); - } - return false; - } - - public tokenize(stream:modes.IStream):modes.ITokenizationResult { - - if (!stream.eos() && stream.peek() === '@') { - stream.next(); - if (!stream.eos() && stream.peek() === '*') { - return { nextState: new csharpTokenization.CSComment(this.getModeId(), this, '@') }; - } - if (stream.eos() || stream.peek() !== '@') { - return { type: razorTokenTypes.EMBED_CS, nextState: new csharpTokenization.CSStatement(this.getModeId(), this, 0, 0, true, true, true, false) }; - } - } - - return super.tokenize(stream); - } -} - -export class RAZORMode extends htmlMode.HTMLMode { - - public static LANG_CONFIG:LanguageConfiguration = { - wordPattern: createWordRegExp('#?%'), - - comments: { - blockComment: [''] - }, - - brackets: [ - [''], - ['{', '}'], - ['(', ')'] - ], - - __electricCharacterSupport: { - embeddedElectricCharacters: ['*', '}', ']', ')'] - }, - - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' } - ], - surroundingPairs: [ - { open: '"', close: '"' }, - { open: '\'', close: '\'' } - ], - - onEnterRules: [ - { - beforeText: new RegExp(`<(?!(?:${htmlMode.EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - afterText: /^<\/(\w[\w\d]*)\s*>$/i, - action: { indentAction: modes.IndentAction.IndentOutdent } - }, - { - beforeText: new RegExp(`<(?!(?:${htmlMode.EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - action: { indentAction: modes.IndentAction.Indent } - } - ], - }; - - constructor( - descriptor:modes.IModeDescriptor, - @IInstantiationService instantiationService: IInstantiationService, - @IModeService modeService: IModeService, - @ICompatWorkerService compatWorkerService: ICompatWorkerService, - @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, - @IConfigurationService configurationService: IConfigurationService - ) { - super(descriptor, instantiationService, modeService, compatWorkerService, workspaceContextService, configurationService); - } - - protected _registerSupports(): void { - modes.SuggestRegistry.register(this.getId(), { - triggerCharacters: ['.', ':', '<', '"', '=', '/'], - provideCompletionItems: (model, position, token): Thenable => { - return wireCancellationToken(token, this._provideCompletionItems(model.uri, position)); - } - }, true); - - modes.DocumentHighlightProviderRegistry.register(this.getId(), { - provideDocumentHighlights: (model, position, token): Thenable => { - return wireCancellationToken(token, this._provideDocumentHighlights(model.uri, position)); - } - }, true); - - modes.LinkProviderRegistry.register(this.getId(), { - provideLinks: (model, token): Thenable => { - return wireCancellationToken(token, this.provideLinks(model.uri)); - } - }, true); - - LanguageConfigurationRegistry.register(this.getId(), RAZORMode.LANG_CONFIG); - - modes.TokenizationRegistry.register(this.getId(), new TokenizationSupport(this._modeService, this.getId(), this, true)); - } - - protected _createModeWorkerManager(descriptor:modes.IModeDescriptor, instantiationService: IInstantiationService): ModeWorkerManager { - return new ModeWorkerManager(descriptor, 'vs/languages/razor/common/razorWorker', 'RAZORWorker', 'vs/languages/html/common/htmlWorker', instantiationService); - } - - public getInitialState(): modes.IState { - return new RAZORState(this.getId(), htmlMode.States.Content, '', '', '', '', 0); - } - - public getLeavingNestedModeData(line:string, state:modes.IState): ILeavingNestedModeData { - var leavingNestedModeData = super.getLeavingNestedModeData(line, state); - if (leavingNestedModeData) { - leavingNestedModeData.stateAfterNestedMode = new RAZORState(this.getId(), htmlMode.States.Content, '', '', '', '', 0); - } - return leavingNestedModeData; - } -} diff --git a/src/vs/languages/razor/common/razorTokenTypes.ts b/src/vs/languages/razor/common/razorTokenTypes.ts deleted file mode 100644 index e0e0afe7b89..00000000000 --- a/src/vs/languages/razor/common/razorTokenTypes.ts +++ /dev/null @@ -1,7 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -export const EMBED_CS = 'support.function.cshtml'; diff --git a/src/vs/languages/razor/common/razorWorker.ts b/src/vs/languages/razor/common/razorWorker.ts deleted file mode 100644 index 507dadba613..00000000000 --- a/src/vs/languages/razor/common/razorWorker.ts +++ /dev/null @@ -1,46 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import htmlWorker = require('vs/languages/html/common/htmlWorker'); -import htmlTags = require('vs/languages/html/common/htmlTags'); - -export function getRazorTagProvider() : htmlTags.IHTMLTagProvider { - var customTags : { [tag:string]: string[]} = { - a: ['asp-action', 'asp-controller', 'asp-fragment', 'asp-host', 'asp-protocol', 'asp-route'], - div: ['asp-validation-summary'], - form: ['asp-action', 'asp-controller', 'asp-anti-forgery'], - input: ['asp-for', 'asp-format'], - label: ['asp-for'], - select: ['asp-for', 'asp-items'], - span: ['asp-validation-for'] - }; - - return { - getId: () => 'razor', - collectTags: (collector: (tag: string) => void) => { - // no extra tags - }, - collectAttributes: (tag: string, collector: (attribute: string, type: string) => void) => { - if (tag) { - var attributes = customTags[tag]; - if (attributes) { - attributes.forEach(a => collector(a, null)); - } - } - }, - collectValues: (tag: string, attribute: string, collector: (value: string) => void) => { - // no values - } - }; -} - -export class RAZORWorker extends htmlWorker.HTMLWorker { - - protected addCustomTagProviders(providers: htmlTags.IHTMLTagProvider[]): void { - // don't call super and don't add the angular provider for now - providers.push(getRazorTagProvider()); - } - -} \ No newline at end of file diff --git a/src/vs/languages/razor/common/vsxml.ts b/src/vs/languages/razor/common/vsxml.ts deleted file mode 100644 index 1aefeb0c818..00000000000 --- a/src/vs/languages/razor/common/vsxml.ts +++ /dev/null @@ -1,234 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -/* In order to use VSXML in your own modes, you need to have an IState - * which implements IVSXMLWrapperState. Upon a START token such as '///', - * the wrapper state can return a new VSXMLEmbeddedState as the nextState in - * the tokenization result. -*/ - - -'use strict'; - -import objects = require('vs/base/common/objects'); -import Modes = require('vs/editor/common/modes'); -import {AbstractState} from 'vs/editor/common/modes/abstractState'; -import vsxmlTokenTypes = require('vs/languages/razor/common/vsxmlTokenTypes'); - -var separators = '<>"=/'; -var whitespace = '\t '; -var isEntity = objects.createKeywordMatcher(['summary', 'reference', 'returns', 'param', 'loc']); -var isAttribute = objects.createKeywordMatcher(['type', 'path', 'name', 'locid', 'filename', 'format', 'optional']); -var isSeparator = objects.createKeywordMatcher(separators.split('')); - -export interface IVSXMLWrapperState extends Modes.IState { - setVSXMLState(newVSXMLState:VSXMLState):void; -} - -export class EmbeddedState extends AbstractState { - - private state:Modes.IState; - private parentState:Modes.IState; - - constructor(modeId:string, state:Modes.IState, parentState:Modes.IState) { - super(modeId); - this.state = state; - this.parentState = parentState; - } - - public getParentState():Modes.IState { - return this.parentState; - } - - public makeClone(): EmbeddedState { - return new EmbeddedState(this.getModeId(), AbstractState.safeClone(this.state), AbstractState.safeClone(this.parentState)); - } - - public equals(other:Modes.IState):boolean { - if (other instanceof EmbeddedState) { - return ( - super.equals(other) && - AbstractState.safeEquals(this.state, other.state) && - AbstractState.safeEquals(this.parentState, other.parentState) - ); - } - return false; - } - - public setState(nextState:Modes.IState):void { - this.state = nextState; - } - - public postTokenize(result:Modes.ITokenizationResult, stream:Modes.IStream) : Modes.ITokenizationResult { - return result; - } - - public tokenize(stream:Modes.IStream) : Modes.ITokenizationResult { - var result = this.state.tokenize(stream); - if (result.nextState !== undefined) { - this.setState(result.nextState); - } - result.nextState = this; - return this.postTokenize(result, stream); - } -} - -export class VSXMLEmbeddedState extends EmbeddedState { - - constructor(modeId:string, state:Modes.IState, parentState:IVSXMLWrapperState) { - super(modeId, state, parentState); - } - - public equals(other:Modes.IState):boolean { - if (other instanceof VSXMLEmbeddedState) { - return ( - super.equals(other) - ); - } - return false; - } - - public setState(nextState:Modes.IState):void{ - super.setState(nextState); - ( this.getParentState()).setVSXMLState(nextState); - } - - public postTokenize(result:Modes.ITokenizationResult, stream:Modes.IStream):Modes.ITokenizationResult { - if (stream.eos()) { - result.nextState = this.getParentState(); - } - return result; - } -} - -export abstract class VSXMLState extends AbstractState { - - public parent:Modes.IState; - public whitespaceTokenType:string; - private name:string; - - constructor(modeId:string, name:string, parent:Modes.IState, whitespaceTokenType:string='') { - super(modeId); - this.name = name; - this.parent = parent; - this.whitespaceTokenType = whitespaceTokenType; - } - - public equals(other:Modes.IState):boolean { - if (other instanceof VSXMLState) { - return ( - super.equals(other) && - this.whitespaceTokenType === other.whitespaceTokenType && - this.name === other.name && - AbstractState.safeEquals(this.parent, other.parent) - ); - } - return false; - } - - public tokenize(stream:Modes.IStream):Modes.ITokenizationResult { - stream.setTokenRules(separators, whitespace); - if (stream.skipWhitespace().length > 0) { - return { type: this.whitespaceTokenType }; - } - return this.stateTokenize(stream); - } - - public abstract stateTokenize(stream:Modes.IStream):Modes.ITokenizationResult; -} - -export class VSXMLString extends VSXMLState { - - constructor(modeId:string, parent:Modes.IState) { - super(modeId, 'string', parent, vsxmlTokenTypes.TOKEN_VALUE); - } - - public makeClone():VSXMLString { - return new VSXMLString(this.getModeId(), this.parent ? this.parent.clone() : null); - } - - public equals(other:Modes.IState):boolean { - if (other instanceof VSXMLString) { - return ( - super.equals(other) - ); - } - return false; - } - - public stateTokenize(stream:Modes.IStream):Modes.ITokenizationResult { - while (!stream.eos()) { - var token = stream.nextToken(); - if (token === '"') { - return { type: vsxmlTokenTypes.TOKEN_VALUE, nextState: this.parent }; - } - } - return { type: vsxmlTokenTypes.TOKEN_VALUE, nextState: this.parent }; - } -} - -export class VSXMLTag extends VSXMLState { - - constructor(modeId:string, parent:Modes.IState) { - super(modeId, 'expression', parent, 'vs'); - } - - public makeClone():VSXMLTag { - return new VSXMLTag(this.getModeId(), this.parent ? this.parent.clone() : null); - } - - public equals(other:Modes.IState):boolean { - if (other instanceof VSXMLTag) { - return ( - super.equals(other) - ); - } - return false; - } - - public stateTokenize(stream:Modes.IStream):Modes.ITokenizationResult { - var token = stream.nextToken(); - var tokenType = this.whitespaceTokenType; - if (token === '>') { - return { type: 'punctuation.vs', nextState: this.parent }; - } else if (token === '"') { - return { type: vsxmlTokenTypes.TOKEN_VALUE, nextState: new VSXMLString(this.getModeId(), this) }; - } else if (isEntity(token)) { - tokenType = 'tag.vs'; - } else if (isAttribute(token)) { - tokenType = vsxmlTokenTypes.TOKEN_KEY; - } else if (isSeparator(token)) { - tokenType = 'punctuation.vs'; - } - return { type:tokenType, nextState: this }; - } -} - -export class VSXMLExpression extends VSXMLState { - - constructor(modeId:string, parent:Modes.IState) { - super(modeId, 'expression', parent, 'vs'); - } - - public makeClone():VSXMLExpression { - return new VSXMLExpression(this.getModeId(), this.parent ? this.parent.clone() : null); - } - - public equals(other:Modes.IState):boolean { - if (other instanceof VSXMLExpression) { - return ( - super.equals(other) - ); - } - return false; - } - - public stateTokenize(stream:Modes.IStream):Modes.ITokenizationResult { - var token = stream.nextToken(); - if (token === '<') { - return { type: 'punctuation.vs', nextState: new VSXMLTag(this.getModeId(), this) }; - } - return { type: this.whitespaceTokenType, nextState: this}; - } -} diff --git a/src/vs/languages/razor/common/vsxmlTokenTypes.ts b/src/vs/languages/razor/common/vsxmlTokenTypes.ts deleted file mode 100644 index ee4602cdb9c..00000000000 --- a/src/vs/languages/razor/common/vsxmlTokenTypes.ts +++ /dev/null @@ -1,8 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -export const TOKEN_VALUE = 'support.property-value.constant.other.json'; -export const TOKEN_KEY = 'support.type.property-name.json'; \ No newline at end of file diff --git a/src/vs/languages/razor/test/common/razor.test.ts b/src/vs/languages/razor/test/common/razor.test.ts deleted file mode 100644 index aeb8af5f2c1..00000000000 --- a/src/vs/languages/razor/test/common/razor.test.ts +++ /dev/null @@ -1,177 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import modesUtil = require('vs/editor/test/common/modesUtil'); -import Modes = require('vs/editor/common/modes'); -import razorTokenTypes = require('vs/languages/razor/common/razorTokenTypes'); -import {htmlTokenTypes} from 'vs/languages/html/common/html'; -import {RAZORMode} from 'vs/languages/razor/common/razor'; -import {MockModeService} from 'vs/editor/test/common/mocks/mockModeService'; - -suite('Syntax Highlighting - Razor', () => { - - var tokenizationSupport: Modes.ITokenizationSupport; - - suiteSetup(function() { - let mode = new RAZORMode( - { id: 'razor' }, - null, - new MockModeService(), - null, - null, - null - ); - - tokenizationSupport = Modes.TokenizationRegistry.get(mode.getId()); - }); - - test('', () => { - modesUtil.executeTests(tokenizationSupport,[ - // Embedding - embedded html - [{ - line: '@{ var x; x }', - tokens: [ - { startIndex: 0, type: razorTokenTypes.EMBED_CS }, - { startIndex: 2, type: '' }, - { startIndex: 3, type: 'keyword.cs' }, - { startIndex: 6, type: '' }, - { startIndex: 7, type: 'ident.cs' }, - { startIndex: 8, type: 'punctuation.cs' }, - { startIndex: 9, type: '' }, - { startIndex: 10, type: htmlTokenTypes.DELIM_START }, - { startIndex: 11, type: htmlTokenTypes.getTag('b') }, - { startIndex: 12, type: htmlTokenTypes.DELIM_START }, - { startIndex: 13, type: 'ident.cs' }, - { startIndex: 14, type: htmlTokenTypes.DELIM_END }, - { startIndex: 16, type: htmlTokenTypes.getTag('b') }, - { startIndex: 17, type: htmlTokenTypes.DELIM_END }, - { startIndex: 18, type: '' }, - { startIndex: 19, type: razorTokenTypes.EMBED_CS } - ]}], - - // Comments - razor comment inside csharp - [{ - line: '@{ var x; @* comment *@ x= 0; }', - tokens: [ - { startIndex: 0, type: razorTokenTypes.EMBED_CS }, - { startIndex: 2, type: '' }, - { startIndex: 3, type: 'keyword.cs' }, - { startIndex: 6, type: '' }, - { startIndex: 7, type: 'ident.cs' }, - { startIndex: 8, type: 'punctuation.cs' }, - { startIndex: 9, type: '' }, - { startIndex: 10, type: 'comment.cs' }, - { startIndex: 23, type: '' }, - { startIndex: 24, type: 'ident.cs' }, - { startIndex: 25, type: 'punctuation.cs' }, - { startIndex: 26, type: '' }, - { startIndex: 27, type: 'number.cs' }, - { startIndex: 28, type: 'punctuation.cs' }, - { startIndex: 29, type: '' }, - { startIndex: 30, type: razorTokenTypes.EMBED_CS } - ]}], - - // Blocks - simple - [{ - line: '@{ var total = 0; }', - tokens: [ - { startIndex: 0, type: razorTokenTypes.EMBED_CS }, - { startIndex: 2, type: '' }, - { startIndex: 3, type: 'keyword.cs' }, - { startIndex: 6, type: '' }, - { startIndex: 7, type: 'ident.cs' }, - { startIndex: 12, type: '' }, - { startIndex: 13, type: 'punctuation.cs' }, - { startIndex: 14, type: '' }, - { startIndex: 15, type: 'number.cs' }, - { startIndex: 16, type: 'punctuation.cs' }, - { startIndex: 17, type: '' }, - { startIndex: 18, type: razorTokenTypes.EMBED_CS } - ]}], - - [{ - line: '@if(true){ var total = 0; }', - tokens: [ - { startIndex: 0, type: razorTokenTypes.EMBED_CS }, - { startIndex: 1, type: 'keyword.cs' }, - { startIndex: 3, type: 'punctuation.parenthesis.cs' }, - { startIndex: 4, type: 'keyword.cs' }, - { startIndex: 8, type: 'punctuation.parenthesis.cs' }, - { startIndex: 9, type: razorTokenTypes.EMBED_CS }, - { startIndex: 10, type: '' }, - { startIndex: 11, type: 'keyword.cs' }, - { startIndex: 14, type: '' }, - { startIndex: 15, type: 'ident.cs' }, - { startIndex: 20, type: '' }, - { startIndex: 21, type: 'punctuation.cs' }, - { startIndex: 22, type: '' }, - { startIndex: 23, type: 'number.cs' }, - { startIndex: 24, type: 'punctuation.cs' }, - { startIndex: 25, type: '' }, - { startIndex: 26, type: razorTokenTypes.EMBED_CS } - ]}], - - // Expressions - csharp expressions in html - [{ - line: 'test@xyz
', - tokens: [ - { startIndex:0, type: '' }, - { startIndex:4, type: razorTokenTypes.EMBED_CS }, - { startIndex:5, type: 'ident.cs' }, - { startIndex:8, type: htmlTokenTypes.DELIM_START }, - { startIndex:9, type: htmlTokenTypes.getTag('br') }, - { startIndex:11, type: htmlTokenTypes.DELIM_START } - ]}], - - [{ - line: 'test@xyz', - tokens: [ - { startIndex:0, type: '' }, - { startIndex:4, type: razorTokenTypes.EMBED_CS }, - { startIndex:5, type: 'ident.cs' } - ]}], - - [{ - line: 'test @ xyz', - tokens: [ - { startIndex: 0, type: '' }, - { startIndex: 5, type: razorTokenTypes.EMBED_CS }, - { startIndex: 6, type: '' }, - { startIndex: 7, type: 'ident.cs' } - ]}], - - [{ - line: 'test @(foo) xyz', - tokens: [ - { startIndex:0, type: '' }, - { startIndex:5, type: razorTokenTypes.EMBED_CS }, - { startIndex:7, type: 'ident.cs' }, - { startIndex:10, type: razorTokenTypes.EMBED_CS }, - { startIndex:11, type: '' } - ]}], - - [{ - line: 'test @(foo(\")\")) xyz', - tokens: [ - { startIndex:0, type: '' }, - { startIndex:5, type: razorTokenTypes.EMBED_CS }, - { startIndex:7, type: 'ident.cs' }, - { startIndex:10, type: 'punctuation.parenthesis.cs' }, - { startIndex:11, type: 'string.cs' }, - { startIndex:14, type: 'punctuation.parenthesis.cs' }, - { startIndex:15, type: razorTokenTypes.EMBED_CS }, - { startIndex:16, type: '' } - ]}], - - // Escaping - escaped at character - [{ - line: 'test@@xyz', - tokens: [ - { startIndex:0, type: '' } - ]}] - ]); - }); -}); From d7397bcadab1f5b9a33d5273ad184e6119beb946 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 7 Oct 2016 16:50:25 +0200 Subject: [PATCH 133/163] Remove vs/languages/handlebars --- src/vs/languages/buildfile.js | 3 - .../common/handlebars.contribution.ts | 16 - .../languages/handlebars/common/handlebars.ts | 202 ---------- .../handlebars/common/handlebarsTokenTypes.ts | 10 - .../handlebars/test/common/handlebars.test.ts | 368 ------------------ 5 files changed, 599 deletions(-) delete mode 100644 src/vs/languages/handlebars/common/handlebars.contribution.ts delete mode 100644 src/vs/languages/handlebars/common/handlebars.ts delete mode 100644 src/vs/languages/handlebars/common/handlebarsTokenTypes.ts delete mode 100644 src/vs/languages/handlebars/test/common/handlebars.test.ts diff --git a/src/vs/languages/buildfile.js b/src/vs/languages/buildfile.js index b2b3871c120..9139e44fc81 100644 --- a/src/vs/languages/buildfile.js +++ b/src/vs/languages/buildfile.js @@ -41,9 +41,6 @@ exports.collectModules = function(args) { // ---- beautify-html (shared btw html and xml) ----------------------------- // worker.define('vs/languages/lib/common/beautify-html'); - // // ---- handlebars ---------------------------------- - // common.define('vs/languages/handlebars/common/handlebars', ['vs/languages/html/common/html']); - // // ---- html ---------------------------------- // common.define('vs/languages/html/common/html') // .combine(worker) diff --git a/src/vs/languages/handlebars/common/handlebars.contribution.ts b/src/vs/languages/handlebars/common/handlebars.contribution.ts deleted file mode 100644 index 0aef06b9b09..00000000000 --- a/src/vs/languages/handlebars/common/handlebars.contribution.ts +++ /dev/null @@ -1,16 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; - -ModesRegistry.registerCompatMode({ - id: 'handlebars', - extensions: ['.handlebars', '.hbs'], - aliases: ['Handlebars', 'handlebars'], - mimetypes: ['text/x-handlebars-template'], - moduleId: 'vs/languages/handlebars/common/handlebars', - ctorName: 'HandlebarsMode' -}); diff --git a/src/vs/languages/handlebars/common/handlebars.ts b/src/vs/languages/handlebars/common/handlebars.ts deleted file mode 100644 index 4ccc898e1f1..00000000000 --- a/src/vs/languages/handlebars/common/handlebars.ts +++ /dev/null @@ -1,202 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import modes = require('vs/editor/common/modes'); -import htmlMode = require('vs/languages/html/common/html'); -import handlebarsTokenTypes = require('vs/languages/handlebars/common/handlebarsTokenTypes'); -import htmlWorker = require('vs/languages/html/common/htmlWorker'); -import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; -import {IModeService} from 'vs/editor/common/services/modeService'; -import {LanguageConfigurationRegistry, LanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; -import {createWordRegExp} from 'vs/editor/common/modes/abstractMode'; -import {wireCancellationToken} from 'vs/base/common/async'; -import {ICompatWorkerService} from 'vs/editor/common/services/compatWorkerService'; -import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; -import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; -import {TokenizationSupport, ILeavingNestedModeData} from 'vs/editor/common/modes/supports/tokenizationSupport'; - -export enum States { - HTML, - Expression, - UnescapedExpression -} - -export class HandlebarsState extends htmlMode.State { - - constructor(modeId:string, - kind:htmlMode.States, - public handlebarsKind:States, - lastTagName:string, - lastAttributeName:string, - embeddedContentType:string, - attributeValueQuote:string, - attributeValueLength:number) { - - super(modeId, kind, lastTagName, lastAttributeName, embeddedContentType, attributeValueQuote, attributeValueLength); - } - - public makeClone(): HandlebarsState { - return new HandlebarsState(this.getModeId(), this.kind, this.handlebarsKind, this.lastTagName, this.lastAttributeName, this.embeddedContentType, this.attributeValueQuote, this.attributeValueLength); - } - - public equals(other:modes.IState):boolean { - if (other instanceof HandlebarsState) { - return ( - super.equals(other) - ); - } - return false; - } - - public tokenize(stream:modes.IStream) : modes.ITokenizationResult { - switch(this.handlebarsKind) { - case States.HTML: - if (stream.advanceIfString('{{{').length > 0) { - this.handlebarsKind = States.UnescapedExpression; - return { type: handlebarsTokenTypes.EMBED_UNESCAPED }; - } - else if (stream.advanceIfString('{{').length > 0) { - this.handlebarsKind = States.Expression; - return { type: handlebarsTokenTypes.EMBED }; - } - break; - - case States.Expression: - case States.UnescapedExpression: - if (this.handlebarsKind === States.Expression && stream.advanceIfString('}}').length > 0) { - this.handlebarsKind = States.HTML; - return { type: handlebarsTokenTypes.EMBED }; - } - else if (this.handlebarsKind === States.UnescapedExpression &&stream.advanceIfString('}}}').length > 0) { - this.handlebarsKind = States.HTML; - return { type: handlebarsTokenTypes.EMBED_UNESCAPED }; - } - else if(stream.skipWhitespace().length > 0) { - return { type: ''}; - } - - if(stream.peek() === '#') { - stream.advanceWhile(/^[^\s}]/); - return { type: handlebarsTokenTypes.KEYWORD }; - } - - if(stream.peek() === '/') { - stream.advanceWhile(/^[^\s}]/); - return { type: handlebarsTokenTypes.KEYWORD }; - } - - if(stream.advanceIfString('else')) { - var next = stream.peek(); - if(next === ' ' || next === '\t' || next === '}') { - return { type: handlebarsTokenTypes.KEYWORD }; - } - else { - stream.goBack(4); - } - } - - if(stream.advanceWhile(/^[^\s}]/).length > 0) { - return { type: handlebarsTokenTypes.VARIABLE }; - } - break; - } - return super.tokenize(stream); - } -} - -export class HandlebarsMode extends htmlMode.HTMLMode { - - public static LANG_CONFIG:LanguageConfiguration = { - wordPattern: createWordRegExp('#-?%'), - - comments: { - blockComment: [''] - }, - - brackets: [ - [''], - ['{{', '}}'] - ], - - __electricCharacterSupport: { - embeddedElectricCharacters: ['*', '}', ']', ')'] - }, - - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' } - ], - - surroundingPairs: [ - { open: '<', close: '>' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' } - ], - - onEnterRules: [ - { - beforeText: new RegExp(`<(?!(?:${htmlMode.EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - afterText: /^<\/(\w[\w\d]*)\s*>$/i, - action: { indentAction: modes.IndentAction.IndentOutdent } - }, - { - beforeText: new RegExp(`<(?!(?:${htmlMode.EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - action: { indentAction: modes.IndentAction.Indent } - } - ], - }; - - constructor( - descriptor:modes.IModeDescriptor, - @IInstantiationService instantiationService: IInstantiationService, - @IModeService modeService: IModeService, - @ICompatWorkerService compatWorkerService: ICompatWorkerService, - @IWorkspaceContextService workspaceContextService: IWorkspaceContextService, - @IConfigurationService configurationService: IConfigurationService - ) { - super(descriptor, instantiationService, modeService, compatWorkerService, workspaceContextService, configurationService); - } - - protected _registerSupports(): void { - modes.SuggestRegistry.register(this.getId(), { - triggerCharacters: ['.', ':', '<', '"', '=', '/'], - provideCompletionItems: (model, position, token): Thenable => { - return wireCancellationToken(token, this._provideCompletionItems(model.uri, position)); - } - }, true); - - modes.DocumentHighlightProviderRegistry.register(this.getId(), { - provideDocumentHighlights: (model, position, token): Thenable => { - return wireCancellationToken(token, this._provideDocumentHighlights(model.uri, position)); - } - }, true); - - modes.LinkProviderRegistry.register(this.getId(), { - provideLinks: (model, token): Thenable => { - return wireCancellationToken(token, this.provideLinks(model.uri)); - } - }, true); - - LanguageConfigurationRegistry.register(this.getId(), HandlebarsMode.LANG_CONFIG); - - modes.TokenizationRegistry.register(this.getId(), new TokenizationSupport(this._modeService, this.getId(), this, true)); - } - - public getInitialState() : modes.IState { - return new HandlebarsState(this.getId(), htmlMode.States.Content, States.HTML, '', '', '', '', 0); - } - - public getLeavingNestedModeData(line:string, state:modes.IState):ILeavingNestedModeData { - var leavingNestedModeData = super.getLeavingNestedModeData(line, state); - if (leavingNestedModeData) { - leavingNestedModeData.stateAfterNestedMode = new HandlebarsState(this.getId(), htmlMode.States.Content, States.HTML, '', '', '', '', 0); - } - return leavingNestedModeData; - } -} diff --git a/src/vs/languages/handlebars/common/handlebarsTokenTypes.ts b/src/vs/languages/handlebars/common/handlebarsTokenTypes.ts deleted file mode 100644 index 2a04f51cc9a..00000000000 --- a/src/vs/languages/handlebars/common/handlebarsTokenTypes.ts +++ /dev/null @@ -1,10 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -export const EMBED = 'punctuation.expression.unescaped.handlebars'; -export const EMBED_UNESCAPED = 'punctuation.expression.handlebars'; -export const KEYWORD = 'keyword.helper.handlebars'; -export const VARIABLE = 'variable.parameter.handlebars'; \ No newline at end of file diff --git a/src/vs/languages/handlebars/test/common/handlebars.test.ts b/src/vs/languages/handlebars/test/common/handlebars.test.ts deleted file mode 100644 index e25688093a7..00000000000 --- a/src/vs/languages/handlebars/test/common/handlebars.test.ts +++ /dev/null @@ -1,368 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import Modes = require('vs/editor/common/modes'); -import modesUtil = require('vs/editor/test/common/modesUtil'); -import {htmlTokenTypes} from 'vs/languages/html/common/html'; -import handlebarsTokenTypes = require('vs/languages/handlebars/common/handlebarsTokenTypes'); -import {HandlebarsMode} from 'vs/languages/handlebars/common/handlebars'; -import {MockModeService} from 'vs/editor/test/common/mocks/mockModeService'; -import {MockTokenizingMode} from 'vs/editor/test/common/mocks/mockMode'; - -class HandlebarsMockModeService extends MockModeService { - - private _handlebarsMode: HandlebarsMode; - - constructor() { - super(); - this._handlebarsMode = null; - } - - public setHandlebarsMode(handlebarsMode: HandlebarsMode): void { - this._handlebarsMode = handlebarsMode; - } - - isRegisteredMode(mimetypeOrModeId: string): boolean { - if (mimetypeOrModeId === 'text/javascript') { - return true; - } - if (mimetypeOrModeId === 'text/x-handlebars-template') { - return true; - } - throw new Error('Not implemented'); - } - - getModeId(mimetypeOrModeId: string): string { - if (mimetypeOrModeId === 'text/javascript') { - return 'js-mode-id'; - } - if (mimetypeOrModeId === 'text/x-handlebars-template') { - return 'handlebars-mode-id'; - } - throw new Error('Not implemented'); - } - - getMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): Modes.IMode { - if (commaSeparatedMimetypesOrCommaSeparatedIds === 'js-mode-id') { - return new MockTokenizingMode('mock-js'); - } - if (commaSeparatedMimetypesOrCommaSeparatedIds === 'handlebars-mode-id') { - return this._handlebarsMode; - } - throw new Error('Not implemented'); - } -} - -suite('Handlebars', () => { - - var tokenizationSupport: Modes.ITokenizationSupport; - suiteSetup(function() { - let modeService = new HandlebarsMockModeService(); - - let mode = new HandlebarsMode( - { id: 'handlebars' }, - null, - modeService, - null, - null, - null - ); - - modeService.setHandlebarsMode(mode); - - tokenizationSupport = Modes.TokenizationRegistry.get(mode.getId()); - }); - - test('Just HTML', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '

handlebars!

', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('h1') }, - { startIndex:3, type: htmlTokenTypes.DELIM_START }, - { startIndex:4, type: '' }, - { startIndex:15, type: htmlTokenTypes.DELIM_END }, - { startIndex:17, type: htmlTokenTypes.getTag('h1') }, - { startIndex:19, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Expressions', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '

{{ title }}

', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('h1') }, - { startIndex:3, type: htmlTokenTypes.DELIM_START }, - { startIndex:4, type: handlebarsTokenTypes.EMBED }, - { startIndex:6, type: '' }, - { startIndex:7, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:12, type: '' }, - { startIndex:13, type: handlebarsTokenTypes.EMBED }, - { startIndex:15, type: htmlTokenTypes.DELIM_END }, - { startIndex:17, type: htmlTokenTypes.getTag('h1') }, - { startIndex:19, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Expressions Sans Whitespace', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '

{{title}}

', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('h1') }, - { startIndex:3, type: htmlTokenTypes.DELIM_START }, - { startIndex:4, type: handlebarsTokenTypes.EMBED }, - { startIndex:6, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:11, type: handlebarsTokenTypes.EMBED }, - { startIndex:13, type: htmlTokenTypes.DELIM_END }, - { startIndex:15, type: htmlTokenTypes.getTag('h1') }, - { startIndex:17, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Unescaped Expressions', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '

{{{ title }}}

', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('h1') }, - { startIndex:3, type: htmlTokenTypes.DELIM_START }, - { startIndex:4, type: handlebarsTokenTypes.EMBED_UNESCAPED }, - { startIndex:7, type: '' }, - { startIndex:8, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:13, type: '' }, - { startIndex:14, type: handlebarsTokenTypes.EMBED_UNESCAPED }, - { startIndex:17, type: htmlTokenTypes.DELIM_END }, - { startIndex:19, type: htmlTokenTypes.getTag('h1') }, - { startIndex:21, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Blocks', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '
    {{#each items}}
  • {{item}}
  • {{/each}}
', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('ul') }, - { startIndex:3, type: htmlTokenTypes.DELIM_START }, - { startIndex:4, type: handlebarsTokenTypes.EMBED }, - { startIndex:6, type: handlebarsTokenTypes.KEYWORD }, - { startIndex:11, type: '' }, - { startIndex:12, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:17, type: handlebarsTokenTypes.EMBED }, - { startIndex:19, type: htmlTokenTypes.DELIM_START }, - { startIndex:20, type: htmlTokenTypes.getTag('li') }, - { startIndex:22, type: htmlTokenTypes.DELIM_START }, - { startIndex:23, type: handlebarsTokenTypes.EMBED }, - { startIndex:25, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:29, type: handlebarsTokenTypes.EMBED }, - { startIndex:31, type: htmlTokenTypes.DELIM_END }, - { startIndex:33, type: htmlTokenTypes.getTag('li') }, - { startIndex:35, type: htmlTokenTypes.DELIM_END }, - { startIndex:36, type: handlebarsTokenTypes.EMBED }, - { startIndex:38, type: handlebarsTokenTypes.KEYWORD }, - { startIndex:43, type: handlebarsTokenTypes.EMBED }, - { startIndex:45, type: htmlTokenTypes.DELIM_END }, - { startIndex:47, type: htmlTokenTypes.getTag('ul') }, - { startIndex:49, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Multiline', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '
', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('div') }, - { startIndex:4, type: htmlTokenTypes.DELIM_START } - ]}, { - line: '{{#if foo}}', - tokens: [ - { startIndex:0, type: handlebarsTokenTypes.EMBED }, - { startIndex:2, type: handlebarsTokenTypes.KEYWORD }, - { startIndex:5, type: '' }, - { startIndex:6, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:9, type: handlebarsTokenTypes.EMBED } - ]}, { - line: '{{bar}}', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('span') }, - { startIndex:5, type: htmlTokenTypes.DELIM_START }, - { startIndex:6, type: handlebarsTokenTypes.EMBED }, - { startIndex:8, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:11, type: handlebarsTokenTypes.EMBED }, - { startIndex:13, type: htmlTokenTypes.DELIM_END }, - { startIndex:15, type: htmlTokenTypes.getTag('span') }, - { startIndex:19, type: htmlTokenTypes.DELIM_END } - ]}, { - line: '{{/if}}', - tokens: null} - ]); - }); - - test('Div end', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '
', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_END }, - { startIndex:2, type: htmlTokenTypes.getTag('div') }, - { startIndex:5, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - // shamelessly stolen from the HTML test bed since Handlebars are a superset of HTML - test('Embedded Content in HTML', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('script') }, - { startIndex:7, type: '' }, - { startIndex:8, type: htmlTokenTypes.ATTRIB_NAME }, - { startIndex:12, type: htmlTokenTypes.DELIM_ASSIGN }, - { startIndex:13, type: htmlTokenTypes.ATTRIB_VALUE }, - { startIndex:30, type: htmlTokenTypes.DELIM_START }, - { startIndex:31, type: 'mock-js' }, - { startIndex:41, type: htmlTokenTypes.DELIM_END }, - { startIndex:43, type: htmlTokenTypes.getTag('script') }, - { startIndex:49, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('HTML Expressions', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('script') }, - { startIndex:7, type: '' }, - { startIndex:8, type: htmlTokenTypes.ATTRIB_NAME }, - { startIndex:12, type: htmlTokenTypes.DELIM_ASSIGN }, - { startIndex:13, type: htmlTokenTypes.ATTRIB_VALUE }, - { startIndex:41, type: htmlTokenTypes.DELIM_START }, - { startIndex:42, type: htmlTokenTypes.DELIM_START }, - { startIndex:43, type: htmlTokenTypes.getTag('h1') }, - { startIndex:45, type: htmlTokenTypes.DELIM_START }, - { startIndex:46, type: handlebarsTokenTypes.EMBED }, - { startIndex:48, type: '' }, - { startIndex:49, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:54, type: '' }, - { startIndex:55, type: handlebarsTokenTypes.EMBED }, - { startIndex:57, type: htmlTokenTypes.DELIM_END }, - { startIndex:59, type: htmlTokenTypes.getTag('h1') }, - { startIndex:61, type: htmlTokenTypes.DELIM_END }, - { startIndex:62, type: htmlTokenTypes.DELIM_END }, - { startIndex:64, type: htmlTokenTypes.getTag('script') }, - { startIndex:70, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('Multi-line HTML Expressions', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_END }, - { startIndex:2, type: htmlTokenTypes.getTag('script') }, - { startIndex:8, type: htmlTokenTypes.DELIM_END } - ]} - ]); - }); - - test('HTML Nested Modes', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '{{foo}}{{bar}}', - tokens: [ - { startIndex:0, type: handlebarsTokenTypes.EMBED }, - { startIndex:2, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:5, type: handlebarsTokenTypes.EMBED }, - { startIndex:7, type: htmlTokenTypes.DELIM_START }, - { startIndex:8, type: htmlTokenTypes.getTag('script') }, - { startIndex:14, type: htmlTokenTypes.DELIM_START }, - { startIndex:15, type: htmlTokenTypes.DELIM_END }, - { startIndex:17, type: htmlTokenTypes.getTag('script') }, - { startIndex:23, type: htmlTokenTypes.DELIM_END }, - { startIndex:24, type: handlebarsTokenTypes.EMBED }, - { startIndex:26, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:29, type: handlebarsTokenTypes.EMBED } - ]} - ]); - }); - - test('else keyword', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '{{else}}', - tokens: [ - { startIndex:0, type: handlebarsTokenTypes.EMBED }, - { startIndex:2, type: handlebarsTokenTypes.KEYWORD }, - { startIndex:6, type: handlebarsTokenTypes.EMBED } - ]} - ]); - }); - - test('else keyword #2', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '{{elseFoo}}', - tokens: [ - { startIndex:0, type: handlebarsTokenTypes.EMBED }, - { startIndex:2, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:9, type: handlebarsTokenTypes.EMBED } - ]} - ]); - }); - - test('Token inside attribute', () => { - modesUtil.assertTokenization(tokenizationSupport, [{ - line: '', - tokens: [ - { startIndex:0, type: htmlTokenTypes.DELIM_START }, - { startIndex:1, type: htmlTokenTypes.getTag('a') }, - { startIndex:2, type: '' }, - { startIndex:3, type: htmlTokenTypes.ATTRIB_NAME }, - { startIndex:7, type: htmlTokenTypes.DELIM_ASSIGN }, - { startIndex:8, type: htmlTokenTypes.ATTRIB_VALUE }, - { startIndex:16, type: handlebarsTokenTypes.EMBED }, - { startIndex:18, type: handlebarsTokenTypes.VARIABLE }, - { startIndex:27, type: handlebarsTokenTypes.EMBED }, - { startIndex:29, type: htmlTokenTypes.ATTRIB_VALUE }, - { startIndex:30, type: htmlTokenTypes.DELIM_START } - ]} - ]); - }); -}); From cf6b4b566188d976e9ed25b6c5a5105b36c5120d Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Fri, 7 Oct 2016 16:56:33 +0200 Subject: [PATCH 134/163] Remove the rest of vs/languages --- build/gulpfile.hygiene.js | 4 - src/buildfile.js | 2 +- .../test/common/modes/modesRegistry.test.ts | 27 - src/vs/languages/buildfile.js | 50 - src/vs/languages/html/common/OSSREADME.json | 88 -- .../html/common/html.contribution.ts | 102 -- src/vs/languages/html/common/html.ts | 473 -------- .../html/common/htmlEmptyTagsShared.ts | 12 - src/vs/languages/html/common/htmlScanner.ts | 142 --- src/vs/languages/html/common/htmlTags.ts | 628 ---------- .../languages/html/common/htmlTokenTypes.ts | 27 - src/vs/languages/html/common/htmlWorker.ts | 609 ---------- .../html/test/common/html-worker.test.ts | 445 ------- .../languages/html/test/common/html.test.ts | 795 ------------- src/vs/languages/lib/common/OSSREADME.json | 9 - src/vs/languages/lib/common/beautify-css.d.ts | 18 - src/vs/languages/lib/common/beautify-css.js | 493 -------- .../languages/lib/common/beautify-html.d.ts | 85 -- src/vs/languages/lib/common/beautify-html.js | 1023 ----------------- .../lib/common/beautify-html.license.txt | 9 - src/vs/languages/lib/common/beautify.ts | 11 - src/vs/languages/lib/common/wireProtocol.ts | 196 ---- 22 files changed, 1 insertion(+), 5247 deletions(-) delete mode 100644 src/vs/editor/test/common/modes/modesRegistry.test.ts delete mode 100644 src/vs/languages/buildfile.js delete mode 100644 src/vs/languages/html/common/OSSREADME.json delete mode 100644 src/vs/languages/html/common/html.contribution.ts delete mode 100644 src/vs/languages/html/common/html.ts delete mode 100644 src/vs/languages/html/common/htmlEmptyTagsShared.ts delete mode 100644 src/vs/languages/html/common/htmlScanner.ts delete mode 100644 src/vs/languages/html/common/htmlTags.ts delete mode 100644 src/vs/languages/html/common/htmlTokenTypes.ts delete mode 100644 src/vs/languages/html/common/htmlWorker.ts delete mode 100644 src/vs/languages/html/test/common/html-worker.test.ts delete mode 100644 src/vs/languages/html/test/common/html.test.ts delete mode 100644 src/vs/languages/lib/common/OSSREADME.json delete mode 100644 src/vs/languages/lib/common/beautify-css.d.ts delete mode 100644 src/vs/languages/lib/common/beautify-css.js delete mode 100644 src/vs/languages/lib/common/beautify-html.d.ts delete mode 100644 src/vs/languages/lib/common/beautify-html.js delete mode 100644 src/vs/languages/lib/common/beautify-html.license.txt delete mode 100644 src/vs/languages/lib/common/beautify.ts delete mode 100644 src/vs/languages/lib/common/wireProtocol.ts diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 34768b9c23e..605da28ff3d 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -47,9 +47,6 @@ const indentationFilter = [ '!**/package.json', '!**/npm-shrinkwrap.json', '!**/octicons/**', - '!**/vs/languages/sass/test/common/example.scss', - '!**/vs/languages/less/common/parser/less.grammar.txt', - '!**/vs/languages/css/common/buildscripts/css-schema.xml', '!**/vs/base/common/marked/raw.marked.js', '!**/vs/base/common/winjs.base.raw.js', '!**/vs/base/node/terminateProcess.sh', @@ -89,7 +86,6 @@ const tslintFilter = [ '!src/vs/base/**/*.test.ts', '!extensions/typescript/test/colorize-fixtures/**', '!extensions/vscode-api-tests/testWorkspace/**', - '!src/vs/languages/**/*.test.ts', '!src/vs/workbench/**/*.test.ts', '!extensions/**/*.test.ts' ]; diff --git a/src/buildfile.js b/src/buildfile.js index ac1cb4b69ef..0c55c799169 100644 --- a/src/buildfile.js +++ b/src/buildfile.js @@ -5,7 +5,7 @@ exports.base = require('./vs/base/buildfile').collectModules(); exports.editor = require('./vs/editor/buildfile').collectModules(); -exports.languages = require('./vs/languages/buildfile').collectModules(); +exports.languages = []; exports.workbench = require('./vs/workbench/buildfile').collectModules(['vs/workbench/workbench.main']); exports.code = require('./vs/code/buildfile').collectModules(); diff --git a/src/vs/editor/test/common/modes/modesRegistry.test.ts b/src/vs/editor/test/common/modes/modesRegistry.test.ts deleted file mode 100644 index e18da231204..00000000000 --- a/src/vs/editor/test/common/modes/modesRegistry.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import 'vs/languages/html/common/html.contribution'; -import { TestInstantiationService } from 'vs/test/utils/instantiationTestUtils'; -import * as assert from 'assert'; -import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; -import {IExtensionService} from 'vs/platform/extensions/common/extensions'; - -suite('Editor Modes - Modes Registry', () => { - - let instantiationService: TestInstantiationService; - - setup(() => { - instantiationService= new TestInstantiationService(); - instantiationService.stub(IExtensionService); - }); - - test('Bug 12104: [f12] createModel not successfully handling mime type list?', () => { - let modeService = instantiationService.createInstance(ModeServiceImpl); - assert.equal(modeService.getModeId('text/html,text/plain'), 'html'); - }); -}); - diff --git a/src/vs/languages/buildfile.js b/src/vs/languages/buildfile.js deleted file mode 100644 index 9139e44fc81..00000000000 --- a/src/vs/languages/buildfile.js +++ /dev/null @@ -1,50 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -var EntryPoint = (function() { - function toArray(param) { - if (!param) { - return []; - } - if (!Array.isArray(param)) { - return [param]; - } - return param; - } - - function EntryPoint(result, modules) { - this.result = result; - this.modules = toArray(modules); - } - EntryPoint.prototype.define = function(moduleId, excludes) { - excludes = toArray(excludes); - this.result.push({ - name: moduleId, - exclude: ['vs/css', 'vs/nls'].concat(this.modules).concat(excludes) - }); - return new EntryPoint(this.result, this.modules.concat([moduleId].concat(excludes))); - }; - EntryPoint.prototype.combine = function(other) { - return new EntryPoint(this.result, this.modules.concat(other.modules)); - }; - return EntryPoint; -})(); -exports.collectModules = function(args) { - - var result = []; - // var common = new EntryPoint(result, 'vs/editor/common/languages.common'); - // var worker = new EntryPoint(result, ['vs/editor/common/languages.common', 'vs/base/common/worker/workerServer', 'vs/editor/common/worker/editorWorkerServer']); - - // ---- beautify-html (shared btw html and xml) ----------------------------- - // worker.define('vs/languages/lib/common/beautify-html'); - - // // ---- html ---------------------------------- - // common.define('vs/languages/html/common/html') - // .combine(worker) - // .define('vs/languages/html/common/htmlWorker', ['vs/languages/lib/common/beautify-html']); - - return result; -}; \ No newline at end of file diff --git a/src/vs/languages/html/common/OSSREADME.json b/src/vs/languages/html/common/OSSREADME.json deleted file mode 100644 index 7472b3af58e..00000000000 --- a/src/vs/languages/html/common/OSSREADME.json +++ /dev/null @@ -1,88 +0,0 @@ -// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS: -[{ - "name": "HTML 5.1 W3C Working Draft", - "version": "08 October 2015", - "license": "W3C Document License", - "repositoryURL": "http://www.w3.org/TR/2015/WD-html51-20151008/", - "licenseDetail": [ - "Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). This software or document includes material copied ", - "from or derived from HTML 5.1 W3C Working Draft (http://www.w3.org/TR/2015/WD-html51-20151008/.)", - "", - "THIS DOCUMENT IS PROVIDED \"AS IS,\" AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT ", - "NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF ", - "THE DOCUMENT ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY ", - "PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.", - "", - "COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE ", - "DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE CONTENTS THEREOF.", - "", - "The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to this document or its contents", - "without specific, written prior permission. Title to copyright in this document will at all times remain with copyright holders." - ] -}, -{ - "name": "Ionic documentation", - "version": "1.2.4", - "license": "Apache2", - "repositoryURL": "https://github.com/driftyco/ionic-site", - "licenseDetail": [ - "Copyright Drifty Co. http://drifty.com/.", - "", - "Apache License", - "", - "Version 2.0, January 2004", - "", - "http://www.apache.org/licenses/", - "", - "TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION", - "", - "1. Definitions.", - "", - "\"License\" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.", - "", - "\"Licensor\" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.", - "", - "\"Legal Entity\" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, \"control\" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.", - "", - "\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising permissions granted by this License.", - "", - "\"Source\" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.", - "", - "\"Object\" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.", - "", - "\"Work\" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).", - "", - "\"Derivative Works\" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.", - "", - "\"Contribution\" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, \"submitted\" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as \"Not a Contribution.\"", - "", - "\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.", - "", - "2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.", - "", - "3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.", - "", - "4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:", - "", - "You must give any other recipients of the Work or Derivative Works a copy of this License; and", - "", - "You must cause any modified files to carry prominent notices stating that You changed the files; and", - "", - "You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and", - "", - "If the Work includes a \"NOTICE\" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.", - "", - "5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.", - "", - "6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.", - "", - "7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.", - "", - "8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.", - "", - "9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.", - "", - "END OF TERMS AND CONDITIONS" - ] -} -] diff --git a/src/vs/languages/html/common/html.contribution.ts b/src/vs/languages/html/common/html.contribution.ts deleted file mode 100644 index 04bbde21217..00000000000 --- a/src/vs/languages/html/common/html.contribution.ts +++ /dev/null @@ -1,102 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import {ModesRegistry} from 'vs/editor/common/modes/modesRegistry'; -import nls = require('vs/nls'); -import platform = require('vs/platform/platform'); -import ConfigurationRegistry = require('vs/platform/configuration/common/configurationRegistry'); - -ModesRegistry.registerCompatMode({ - id: 'html', - extensions: ['.html', '.htm', '.shtml', '.xhtml', '.mdoc', '.jsp', '.asp', '.aspx', '.jshtm'], - aliases: ['HTML', 'htm', 'html', 'xhtml'], - mimetypes: ['text/html', 'text/x-jshtm', 'text/template', 'text/ng-template'], - moduleId: 'vs/languages/html/common/html', - ctorName: 'HTMLMode', - deps: ['text/css', 'text/javascript'] -}); - -var configurationRegistry = platform.Registry.as(ConfigurationRegistry.Extensions.Configuration); - -export interface IHTMLFormatConfiguration { - wrapLineLength: number; - unformatted: string; - indentInnerHtml: boolean; - preserveNewLines: boolean; - maxPreserveNewLines: number; - indentHandlebars: boolean; - endWithNewline: boolean; - extraLiners: string; -} - -export interface IHTMLConfiguration { - format: IHTMLFormatConfiguration; - suggest: {[providerId:string]:boolean}; -} - -configurationRegistry.registerConfiguration({ - 'id': 'html', - 'order': 20, - 'type': 'object', - 'title': nls.localize('htmlConfigurationTitle', "HTML"), - 'properties': { - 'html.format.wrapLineLength': { - 'type': 'integer', - 'default': 120, - 'description': nls.localize('format.wrapLineLength', "Maximum amount of characters per line (0 = disable)."), - }, - 'html.format.unformatted': { - 'type': ['string', 'null'], - 'default': 'a, abbr, acronym, b, bdo, big, br, button, cite, code, dfn, em, i, img, input, kbd, label, map, object, q, samp, script, select, small, span, strong, sub, sup, textarea, tt, var', - 'description': nls.localize('format.unformatted', "List of tags, comma separated, that shouldn't be reformatted. 'null' defaults to all tags listed at https://www.w3.org/TR/html5/dom.html#phrasing-content."), - }, - 'html.format.indentInnerHtml': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('format.indentInnerHtml', "Indent and sections."), - }, - 'html.format.preserveNewLines': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('format.preserveNewLines', "Whether existing line breaks before elements should be preserved. Only works before elements, not inside tags or for text."), - }, - 'html.format.maxPreserveNewLines': { - 'type': ['number', 'null'], - 'default': null, - 'description': nls.localize('format.maxPreserveNewLines', "Maximum number of line breaks to be preserved in one chunk. Use 'null' for unlimited."), - }, - 'html.format.indentHandlebars': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('format.indentHandlebars', "Format and indent {{#foo}} and {{/foo}}."), - }, - 'html.format.endWithNewline': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('format.endWithNewline', "End with a newline."), - }, - 'html.format.extraLiners': { - 'type': ['string', 'null'], - 'default': 'head, body, /html', - 'description': nls.localize('format.extraLiners', "List of tags, comma separated, that should have an extra newline before them. 'null' defaults to \"head, body, /html\"."), - }, -'html.suggest.angular1': { - 'type': ['boolean'], - 'default': true, - 'description': nls.localize('suggest.angular1', "Configures if the built-in HTML language support suggests Angular V1 tags and properties."), -}, -'html.suggest.ionic': { - 'type': ['boolean'], - 'default': true, - 'description': nls.localize('suggest.ionic', "Configures if the built-in HTML language support suggests Ionic tags, properties and values."), -}, -'html.suggest.html5': { - 'type': ['boolean'], - 'default': true, - 'description': nls.localize('suggest.html5', "Configures if the built-in HTML language support suggests HTML5 tags, properties and values."), -}, - } -}); diff --git a/src/vs/languages/html/common/html.ts b/src/vs/languages/html/common/html.ts deleted file mode 100644 index 0faa53bae8e..00000000000 --- a/src/vs/languages/html/common/html.ts +++ /dev/null @@ -1,473 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import URI from 'vs/base/common/uri'; -import winjs = require('vs/base/common/winjs.base'); -import editorCommon = require('vs/editor/common/editorCommon'); -import modes = require('vs/editor/common/modes'); -import htmlWorker = require('vs/languages/html/common/htmlWorker'); -import { CompatMode, createWordRegExp, ModeWorkerManager } from 'vs/editor/common/modes/abstractMode'; -import { AbstractState } from 'vs/editor/common/modes/abstractState'; -import {IModeService} from 'vs/editor/common/services/modeService'; -import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; -import * as htmlTokenTypes from 'vs/languages/html/common/htmlTokenTypes'; -import {EMPTY_ELEMENTS} from 'vs/languages/html/common/htmlEmptyTagsShared'; -import {LanguageConfigurationRegistry, LanguageConfiguration} from 'vs/editor/common/modes/languageConfigurationRegistry'; -import {TokenizationSupport, IModeLocator, ILeavingNestedModeData, ITokenizationCustomization} from 'vs/editor/common/modes/supports/tokenizationSupport'; -import {wireCancellationToken} from 'vs/base/common/async'; -import {ICompatWorkerService, CompatWorkerAttr} from 'vs/editor/common/services/compatWorkerService'; -import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; -import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; -import {IHTMLConfiguration} from 'vs/languages/html/common/html.contribution'; -import {CharCode} from 'vs/base/common/charCode'; - -export { htmlTokenTypes }; // export to be used by Razor. We are the main module, so Razor should get it from us. -export { EMPTY_ELEMENTS }; // export to be used by Razor. We are the main module, so Razor should get it from us. - -export enum States { - Content, - OpeningStartTag, - OpeningEndTag, - WithinDoctype, - WithinTag, - WithinComment, - WithinEmbeddedContent, - AttributeName, - AttributeValue -} - -// list of elements that embed other content -var tagsEmbeddingContent:string[] = ['script', 'style']; - - - -export class State extends AbstractState { - public kind:States; - public lastTagName:string; - public lastAttributeName:string; - public embeddedContentType:string; - public attributeValueQuote:string; - public attributeValueLength:number; - - constructor(modeId:string, kind:States, lastTagName:string, lastAttributeName:string, embeddedContentType:string, attributeValueQuote:string, attributeValueLength:number) { - super(modeId); - this.kind = kind; - this.lastTagName = lastTagName; - this.lastAttributeName = lastAttributeName; - this.embeddedContentType = embeddedContentType; - this.attributeValueQuote = attributeValueQuote; - this.attributeValueLength = attributeValueLength; - } - - static escapeTagName(s:string):string { - return htmlTokenTypes.getTag(s.replace(/[:_.]/g, '-')); - } - - public makeClone():State { - return new State(this.getModeId(), this.kind, this.lastTagName, this.lastAttributeName, this.embeddedContentType, this.attributeValueQuote, this.attributeValueLength); - } - - public equals(other:modes.IState):boolean { - if (other instanceof State) { - return ( - super.equals(other) && - this.kind === other.kind && - this.lastTagName === other.lastTagName && - this.lastAttributeName === other.lastAttributeName && - this.embeddedContentType === other.embeddedContentType && - this.attributeValueQuote === other.attributeValueQuote && - this.attributeValueLength === other.attributeValueLength - ); - } - return false; - } - - private nextElementName(stream:modes.IStream):string { - return stream.advanceIfRegExp(/^[_:\w][_:\w-.\d]*/).toLowerCase(); - } - - private nextAttributeName(stream:modes.IStream):string { - return stream.advanceIfRegExp(/^[^\s"'>/=\x00-\x0F\x7F\x80-\x9F]*/).toLowerCase(); - } - - public tokenize(stream:modes.IStream) : modes.ITokenizationResult { - - switch(this.kind){ - case States.WithinComment: - if (stream.advanceUntilString2('-->', false)) { - return { type: htmlTokenTypes.COMMENT}; - - } else if(stream.advanceIfString2('-->')) { - this.kind = States.Content; - return { type: htmlTokenTypes.DELIM_COMMENT, dontMergeWithPrev: true }; - } - break; - - case States.WithinDoctype: - if (stream.advanceUntilString2('>', false)) { - return { type: htmlTokenTypes.DOCTYPE}; - } else if(stream.advanceIfString2('>')) { - this.kind = States.Content; - return { type: htmlTokenTypes.DELIM_DOCTYPE, dontMergeWithPrev: true }; - } - break; - - case States.Content: - if (stream.advanceIfCharCode2(CharCode.LessThan)) { - if (!stream.eos() && stream.peek() === '!') { - if (stream.advanceIfString2('!--')) { - this.kind = States.WithinComment; - return { type: htmlTokenTypes.DELIM_COMMENT, dontMergeWithPrev: true }; - } - if (stream.advanceIfStringCaseInsensitive2('!DOCTYPE')) { - this.kind = States.WithinDoctype; - return { type: htmlTokenTypes.DELIM_DOCTYPE, dontMergeWithPrev: true }; - } - } - if (stream.advanceIfCharCode2(CharCode.Slash)) { - this.kind = States.OpeningEndTag; - return { type: htmlTokenTypes.DELIM_END, dontMergeWithPrev: true }; - } - this.kind = States.OpeningStartTag; - return { type: htmlTokenTypes.DELIM_START, dontMergeWithPrev: true }; - } - break; - - case States.OpeningEndTag: - var tagName = this.nextElementName(stream); - if (tagName.length > 0){ - return { - type: State.escapeTagName(tagName), - }; - - } else if (stream.advanceIfString2('>')) { - this.kind = States.Content; - return { type: htmlTokenTypes.DELIM_END, dontMergeWithPrev: true }; - - } else { - stream.advanceUntilString2('>', false); - return { type: '' }; - } - - case States.OpeningStartTag: - this.lastTagName = this.nextElementName(stream); - if (this.lastTagName.length > 0) { - this.lastAttributeName = null; - if ('script' === this.lastTagName || 'style' === this.lastTagName) { - this.lastAttributeName = null; - this.embeddedContentType = null; - } - this.kind = States.WithinTag; - return { - type: State.escapeTagName(this.lastTagName), - }; - } - break; - - case States.WithinTag: - if (stream.skipWhitespace2() || stream.eos()) { - this.lastAttributeName = ''; // remember that we have seen a whitespace - return { type: '' }; - } else { - if (this.lastAttributeName === '') { - var name = this.nextAttributeName(stream); - if (name.length > 0) { - this.lastAttributeName = name; - this.kind = States.AttributeName; - return { type: htmlTokenTypes.ATTRIB_NAME }; - } - } - if (stream.advanceIfString2('/>')) { - this.kind = States.Content; - return { type: htmlTokenTypes.DELIM_START, dontMergeWithPrev: true }; - } - if (stream.advanceIfCharCode2(CharCode.GreaterThan)) { - if (tagsEmbeddingContent.indexOf(this.lastTagName) !== -1) { - this.kind = States.WithinEmbeddedContent; - return { type: htmlTokenTypes.DELIM_START, dontMergeWithPrev: true }; - } else { - this.kind = States.Content; - return { type: htmlTokenTypes.DELIM_START, dontMergeWithPrev: true }; - } - } else { - stream.next2(); - return { type: '' }; - } - } - - case States.AttributeName: - if (stream.skipWhitespace2() || stream.eos()){ - return { type: '' }; - } - - if (stream.advanceIfCharCode2(CharCode.Equals)) { - this.kind = States.AttributeValue; - return { type: htmlTokenTypes.DELIM_ASSIGN }; - } else { - this.kind = States.WithinTag; - this.lastAttributeName = ''; - return this.tokenize(stream); // no advance yet - jump to WithinTag - } - - case States.AttributeValue: - if (stream.eos()) { - return { type: '' }; - } - if(stream.skipWhitespace2()) { - if (this.attributeValueQuote === '"' || this.attributeValueQuote === '\'') { - // We are inside the quotes of an attribute value - return { type: htmlTokenTypes.ATTRIB_VALUE }; - } - return { type: '' }; - } - // We are in a attribute value - if (this.attributeValueQuote === '"' || this.attributeValueQuote === '\'') { - - if (this.attributeValueLength === 1 && ('script' === this.lastTagName || 'style' === this.lastTagName) && 'type' === this.lastAttributeName) { - let attributeValue = stream.advanceUntilString(this.attributeValueQuote, true); - if (attributeValue.length > 0) { - this.embeddedContentType = this.unquote(attributeValue); - this.kind = States.WithinTag; - this.attributeValueLength = 0; - this.attributeValueQuote = ''; - return { type: htmlTokenTypes.ATTRIB_VALUE }; - } - } else { - if (stream.advanceIfCharCode2(this.attributeValueQuote.charCodeAt(0))) { - this.kind = States.WithinTag; - this.attributeValueLength = 0; - this.attributeValueQuote = ''; - this.lastAttributeName = null; - } else { - stream.next(); - this.attributeValueLength++; - } - return { type: htmlTokenTypes.ATTRIB_VALUE }; - } - } else { - let attributeValue = stream.advanceIfRegExp(/^[^\s"'`=<>]+/); - if (attributeValue.length > 0) { - this.kind = States.WithinTag; - this.lastAttributeName = null; - return { type: htmlTokenTypes.ATTRIB_VALUE }; - } - var ch = stream.peek(); - if (ch === '\'' || ch === '"') { - this.attributeValueQuote = ch; - this.attributeValueLength = 1; - stream.next2(); - return { type: htmlTokenTypes.ATTRIB_VALUE }; - } else { - this.kind = States.WithinTag; - this.lastAttributeName = null; - return this.tokenize(stream); // no advance yet - jump to WithinTag - } - } - } - - stream.next2(); - this.kind = States.Content; - return { type: '' }; - } - - private unquote(value:string):string { - var start = 0; - var end = value.length; - if ('"' === value[0]) { - start++; - } - if ('"' === value[end - 1]) { - end--; - } - return value.substring(start, end); - } -} - -export class HTMLMode extends CompatMode implements ITokenizationCustomization { - - public static LANG_CONFIG:LanguageConfiguration = { - wordPattern: createWordRegExp('#-?%'), - - comments: { - blockComment: [''] - }, - - brackets: [ - [''], - ['<', '>'], - ], - - __electricCharacterSupport: { - embeddedElectricCharacters: ['*', '}', ']', ')'] - }, - - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' } - ], - - surroundingPairs: [ - { open: '"', close: '"' }, - { open: '\'', close: '\'' } - ], - - onEnterRules: [ - { - beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))([_:\\w][_:\\w-.\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - afterText: /^<\/([_:\w][_:\w-.\d]*)\s*>$/i, - action: { indentAction: modes.IndentAction.IndentOutdent } - }, - { - beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - action: { indentAction: modes.IndentAction.Indent } - } - ], - }; - - protected _modeService:IModeService; - private _modeWorkerManager: ModeWorkerManager; - - constructor( - descriptor:modes.IModeDescriptor, - @IInstantiationService instantiationService: IInstantiationService, - @IModeService modeService: IModeService, - @ICompatWorkerService compatWorkerService: ICompatWorkerService, - @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, - @IConfigurationService private configurationService: IConfigurationService - ) { - super(descriptor.id, compatWorkerService); - this._modeWorkerManager = this._createModeWorkerManager(descriptor, instantiationService); - - this._modeService = modeService; - - if (this.compatWorkerService && this.compatWorkerService.isInMainThread) { - let updateConfiguration = () => { - let opts = configurationService.getConfiguration('html'); - this._configureWorker(opts); - }; - configurationService.onDidUpdateConfiguration((e) => updateConfiguration()); - updateConfiguration(); - } - - this._registerSupports(); - } - - protected _registerSupports(): void { - if (this.getId() !== 'html') { - throw new Error('This method must be overwritten!'); - } - - modes.SuggestRegistry.register(this.getId(), { - triggerCharacters: ['.', ':', '<', '"', '=', '/'], - provideCompletionItems: (model, position, token): Thenable => { - return wireCancellationToken(token, this._provideCompletionItems(model.uri, position)); - } - }, true); - - modes.DocumentHighlightProviderRegistry.register(this.getId(), { - provideDocumentHighlights: (model, position, token): Thenable => { - return wireCancellationToken(token, this._provideDocumentHighlights(model.uri, position)); - } - }, true); - - modes.DocumentRangeFormattingEditProviderRegistry.register(this.getId(), { - provideDocumentRangeFormattingEdits: (model, range, options, token): Thenable => { - return wireCancellationToken(token, this._provideDocumentRangeFormattingEdits(model.uri, range, options)); - } - }, true); - - modes.LinkProviderRegistry.register(this.getId(), { - provideLinks: (model, token): Thenable => { - return wireCancellationToken(token, this.provideLinks(model.uri)); - } - }, true); - - LanguageConfigurationRegistry.register(this.getId(), HTMLMode.LANG_CONFIG); - - modes.TokenizationRegistry.register(this.getId(), new TokenizationSupport(this._modeService, this.getId(), this, true)); - } - - protected _createModeWorkerManager(descriptor:modes.IModeDescriptor, instantiationService: IInstantiationService): ModeWorkerManager { - return new ModeWorkerManager(descriptor, 'vs/languages/html/common/htmlWorker', 'HTMLWorker', null, instantiationService); - } - - private _worker(runner:(worker:W)=>winjs.TPromise): winjs.TPromise { - return this._modeWorkerManager.worker(runner); - } - - // TokenizationSupport - - public getInitialState():modes.IState { - return new State(this.getId(), States.Content, '', '', '', '', 0); - } - - public enterNestedMode(state:modes.IState):boolean { - return state instanceof State && (state).kind === States.WithinEmbeddedContent; - } - - public getNestedMode(state:modes.IState, locator:IModeLocator): modes.IMode { - let htmlState:State = state; - if (htmlState.embeddedContentType !== null) { - return locator.getMode(htmlState.embeddedContentType); - } - if ('script' === htmlState.lastTagName) { - return locator.getMode('text/javascript'); - } - if ('style' === htmlState.lastTagName) { - return locator.getMode('text/css'); - } - return null; - } - - public getLeavingNestedModeData(line:string, state:modes.IState):ILeavingNestedModeData { - var tagName = (state).lastTagName; - var regexp = new RegExp('<\\/' + tagName + '\\s*>', 'i'); - var match:any = regexp.exec(line); - if (match !== null) { - return { - nestedModeBuffer: line.substring(0, match.index), - bufferAfterNestedMode: line.substring(match.index), - stateAfterNestedMode: new State(this.getId(), States.Content, '', '', '', '', 0) - }; - } - return null; - } - - static $_configureWorker = CompatWorkerAttr(HTMLMode, HTMLMode.prototype._configureWorker); - private _configureWorker(options:any): winjs.TPromise { - return this._worker((w) => w._doConfigure(options)); - } - - protected provideLinks(resource:URI):winjs.TPromise { - let workspace = this.workspaceContextService.getWorkspace(); - let workspaceResource = workspace ? workspace.resource : null; - return this._provideLinks(resource, workspaceResource); - } - - static $_provideLinks = CompatWorkerAttr(HTMLMode, HTMLMode.prototype._provideLinks); - private _provideLinks(resource:URI, workspaceResource:URI):winjs.TPromise { - return this._worker((w) => w.provideLinks(resource, workspaceResource)); - } - - static $_provideDocumentRangeFormattingEdits = CompatWorkerAttr(HTMLMode, HTMLMode.prototype._provideDocumentRangeFormattingEdits); - private _provideDocumentRangeFormattingEdits(resource:URI, range:editorCommon.IRange, options:modes.FormattingOptions):winjs.TPromise { - return this._worker((w) => w.provideDocumentRangeFormattingEdits(resource, range, options)); - } - - static $_provideDocumentHighlights = CompatWorkerAttr(HTMLMode, HTMLMode.prototype._provideDocumentHighlights); - protected _provideDocumentHighlights(resource:URI, position:editorCommon.IPosition, strict:boolean = false): winjs.TPromise { - return this._worker((w) => w.provideDocumentHighlights(resource, position, strict)); - } - - static $_provideCompletionItems = CompatWorkerAttr(HTMLMode, HTMLMode.prototype._provideCompletionItems); - protected _provideCompletionItems(resource:URI, position:editorCommon.IPosition):winjs.TPromise { - return this._worker((w) => w.provideCompletionItems(resource, position)); - } - -} diff --git a/src/vs/languages/html/common/htmlEmptyTagsShared.ts b/src/vs/languages/html/common/htmlEmptyTagsShared.ts deleted file mode 100644 index 112868dad30..00000000000 --- a/src/vs/languages/html/common/htmlEmptyTagsShared.ts +++ /dev/null @@ -1,12 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import arrays = require('vs/base/common/arrays'); - -export const EMPTY_ELEMENTS:string[] = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr']; - -export function isEmptyElement(e: string) : boolean { - return arrays.binarySearch(EMPTY_ELEMENTS, e,(s1: string, s2: string) => s1.localeCompare(s2)) >= 0; -} diff --git a/src/vs/languages/html/common/htmlScanner.ts b/src/vs/languages/html/common/htmlScanner.ts deleted file mode 100644 index f1b6b76832f..00000000000 --- a/src/vs/languages/html/common/htmlScanner.ts +++ /dev/null @@ -1,142 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import {isTag, DELIM_END, DELIM_START, DELIM_ASSIGN, ATTRIB_NAME, ATTRIB_VALUE} from 'vs/languages/html/common/htmlTokenTypes'; - -import EditorCommon = require('vs/editor/common/editorCommon'); - -export interface IHTMLScanner { - getTokenType(): string; - isOpenBrace(): boolean; - isAtTokenStart(): boolean; - isAtTokenEnd(): boolean; - getTokenContent(): string; - scanBack() : boolean; - scanForward() : boolean; - getTokenPosition(): EditorCommon.IPosition; - getTokenRange(): EditorCommon.IRange; - getModel(): EditorCommon.ITokenizedModel; -} - -function isDelimiter(tokenType: string) { - switch (tokenType) { - case DELIM_START: - case DELIM_END: - case DELIM_ASSIGN: - return true; - } - return false; -} - -function isInterestingToken(tokenType: string) { - switch (tokenType) { - case DELIM_START: - case DELIM_END: - case DELIM_ASSIGN: - case ATTRIB_NAME: - case ATTRIB_VALUE: - return true; - } - return isTag(tokenType); -} - -export function getScanner(model: EditorCommon.ITokenizedModel, position:EditorCommon.IPosition) : IHTMLScanner { - - var lineOffset = position.column - 1; - var currentLine = position.lineNumber; - - var tokens = model.getLineTokens(currentLine); - var lineContent = model.getLineContent(currentLine); - var tokenIndex = tokens.findTokenIndexAtOffset(lineOffset); - var tokensOnLine = tokens.getTokenCount(); - - var tokenType = tokens.getTokenType(tokenIndex); - var tokenStart = tokens.getTokenStartOffset(tokenIndex); - var tokenEnd = tokens.getTokenEndOffset(tokenIndex); - - if ((tokenType === '' || isDelimiter(tokenType)) && tokenStart === lineOffset) { - tokenIndex--; - if (tokenIndex >= 0) { - // we are at the end of a different token - tokenType = tokens.getTokenType(tokenIndex); - tokenStart = tokens.getTokenStartOffset(tokenIndex); - tokenEnd = tokens.getTokenEndOffset(tokenIndex); - } else { - tokenType = ''; - tokenStart = tokenEnd = 0; - } - } - - return { - getTokenType: () => tokenType, - isAtTokenEnd: () => lineOffset === tokenEnd, - isAtTokenStart: () => lineOffset === tokenStart, - getTokenContent: () => lineContent.substring(tokenStart, tokenEnd), - isOpenBrace: () => tokenStart < tokenEnd && lineContent.charAt(tokenStart) === '<', - getTokenPosition: () => { lineNumber: currentLine, column: tokenStart + 1 }, - getTokenRange: () => { startLineNumber: currentLine, startColumn: tokenStart + 1, endLineNumber: currentLine, endColumn: tokenEnd + 1 }, - getModel: () => model, - scanBack: () => { - if (currentLine <= 0) { - return false; - } - - tokenIndex--; - do { - while (tokenIndex >= 0) { - tokenType = tokens.getTokenType(tokenIndex); - tokenStart = tokens.getTokenStartOffset(tokenIndex); - tokenEnd = tokens.getTokenEndOffset(tokenIndex); - - if (isInterestingToken(tokenType)) { - return true; - } - tokenIndex--; - } - currentLine--; - if (currentLine > 0) { - tokens = model.getLineTokens(currentLine); - lineContent = model.getLineContent(currentLine); - tokensOnLine = tokens.getTokenCount(); - tokenIndex = tokensOnLine - 1; - } - } while (currentLine > 0); - tokens = null; - tokenType = lineContent = ''; - tokenStart = tokenEnd = tokensOnLine = 0; - return false; - }, - scanForward: () => { - if (currentLine > model.getLineCount()) { - return false; - } - - tokenIndex++; - do { - while (tokenIndex < tokensOnLine) { - tokenType = tokens.getTokenType(tokenIndex); - tokenStart = tokens.getTokenStartOffset(tokenIndex); - tokenEnd = tokens.getTokenEndOffset(tokenIndex); - - if (isInterestingToken(tokenType)) { - return true; - } - tokenIndex++; - } - currentLine++; - tokenIndex = 0; - if (currentLine <= model.getLineCount()) { - tokens = model.getLineTokens(currentLine); - lineContent = model.getLineContent(currentLine); - tokensOnLine = tokens.getTokenCount(); - } - } while (currentLine <= model.getLineCount()); - tokenType = lineContent = ''; - tokenStart = tokenEnd = tokensOnLine = 0; - return false; - } - }; -} \ No newline at end of file diff --git a/src/vs/languages/html/common/htmlTags.ts b/src/vs/languages/html/common/htmlTags.ts deleted file mode 100644 index 5ed5d206960..00000000000 --- a/src/vs/languages/html/common/htmlTags.ts +++ /dev/null @@ -1,628 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -/*! -BEGIN THIRD PARTY -*/ -/*-------------------------------------------------------------------------------------------- - * This file is based on or incorporates material from the projects listed below (Third Party IP). - * The original copyright notice and the license under which Microsoft received such Third Party IP, - * are set forth below. Such licenses and notices are provided for informational purposes only. - * Microsoft licenses the Third Party IP to you under the licensing terms for the Microsoft product. - * Microsoft reserves all other rights not expressly granted under this agreement, whether by implication, - * estoppel or otherwise. - *--------------------------------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------------------------- - * Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). This software or document includes includes material copied - * from or derived from HTML 5.1 W3C Working Draft (http://www.w3.org/TR/2015/WD-html51-20151008/.)" - *--------------------------------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------------------------- - * Ionic Main Site (https://github.com/driftyco/ionic-site). - * Copyright Drifty Co. http://drifty.com/. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED - * WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, - * MERCHANTABLITY OR NON-INFRINGEMENT. - * - * See the Apache Version 2.0 License for specific language governing permissions - * and limitations under the License. - *--------------------------------------------------------------------------------------------*/ - -import strings = require('vs/base/common/strings'); -import nls = require('vs/nls'); - -export interface IHTMLTagProvider { - getId(): string; - collectTags(collector: (tag: string, label: string) => void): void; - collectAttributes(tag: string, collector: (attribute: string, type: string) => void): void; - collectValues(tag: string, attribute: string, collector: (value: string) => void): void; -} - -export interface ITagSet { - [tag: string]: HTMLTagSpecification; -} - -export class HTMLTagSpecification { - constructor(public label: string, public attributes: string[] = []) { } -} - -interface IValueSets { - [tag: string]: string[]; -} - -// HTML tag information sourced from http://www.w3.org/TR/2015/WD-html51-20151008/ -export const HTML_TAGS: ITagSet = { - // The root element - html: new HTMLTagSpecification( - nls.localize('tags.html', 'The html element represents the root of an HTML document.'), - ['manifest']), - // Document metadata - head: new HTMLTagSpecification( - nls.localize('tags.head', 'The head element represents a collection of metadata for the Document.')), - title: new HTMLTagSpecification( - nls.localize('tags.title', 'The title element represents the document\'s title or name. Authors should use titles that identify their documents even when they are used out of context, for example in a user\'s history or bookmarks, or in search results. The document\'s title is often different from its first heading, since the first heading does not have to stand alone when taken out of context.')), - base: new HTMLTagSpecification( - nls.localize('tags.base', 'The base element allows authors to specify the document base URL for the purposes of resolving relative URLs, and the name of the default browsing context for the purposes of following hyperlinks. The element does not represent any content beyond this information.'), - ['href', 'target']), - link: new HTMLTagSpecification( - nls.localize('tags.link', 'The link element allows authors to link their document to other resources.'), - ['href', 'crossorigin:xo', 'rel', 'media', 'hreflang', 'type', 'sizes']), - meta: new HTMLTagSpecification( - nls.localize('tags.meta', 'The meta element represents various kinds of metadata that cannot be expressed using the title, base, link, style, and script elements.'), - ['name', 'http-equiv', 'content', 'charset']), - style: new HTMLTagSpecification( - nls.localize('tags.style', 'The style element allows authors to embed style information in their documents. The style element is one of several inputs to the styling processing model. The element does not represent content for the user.'), - ['media', 'nonce', 'type', 'scoped:v']), - // Sections - body: new HTMLTagSpecification( - nls.localize('tags.body', 'The body element represents the content of the document.'), - ['onafterprint', 'onbeforeprint', 'onbeforeunload', 'onhashchange', 'onlanguagechange', 'onmessage', 'onoffline', 'ononline', 'onpagehide', 'onpageshow', 'onpopstate', 'onstorage', 'onunload']), - article: new HTMLTagSpecification( - nls.localize('tags.article', 'The article element represents a complete, or self-contained, composition in a document, page, application, or site and that is, in principle, independently distributable or reusable, e.g. in syndication. This could be a forum post, a magazine or newspaper article, a blog entry, a user-submitted comment, an interactive widget or gadget, or any other independent item of content. Each article should be identified, typically by including a heading (h1–h6 element) as a child of the article element.')), - section: new HTMLTagSpecification( - nls.localize('tags.section', 'The section element represents a generic section of a document or application. A section, in this context, is a thematic grouping of content. Each section should be identified, typically by including a heading ( h1- h6 element) as a child of the section element.')), - nav: new HTMLTagSpecification( - nls.localize('tags.nav', 'The nav element represents a section of a page that links to other pages or to parts within the page: a section with navigation links.')), - aside: new HTMLTagSpecification( - nls.localize('tags.aside', 'The aside element represents a section of a page that consists of content that is tangentially related to the content around the aside element, and which could be considered separate from that content. Such sections are often represented as sidebars in printed typography.')), - h1: new HTMLTagSpecification( - nls.localize('tags.h1', 'The h1 element represents a section heading.')), - h2: new HTMLTagSpecification( - nls.localize('tags.h2', 'The h2 element represents a section heading.')), - h3: new HTMLTagSpecification( - nls.localize('tags.h3', 'The h3 element represents a section heading.')), - h4: new HTMLTagSpecification( - nls.localize('tags.h4', 'The h4 element represents a section heading.')), - h5: new HTMLTagSpecification( - nls.localize('tags.h5', 'The h5 element represents a section heading.')), - h6: new HTMLTagSpecification( - nls.localize('tags.h6', 'The h6 element represents a section heading.')), - header: new HTMLTagSpecification( - nls.localize('tags.header', 'The header element represents introductory content for its nearest ancestor sectioning content or sectioning root element. A header typically contains a group of introductory or navigational aids. When the nearest ancestor sectioning content or sectioning root element is the body element, then it applies to the whole page.')), - footer: new HTMLTagSpecification( - nls.localize('tags.footer', 'The footer element represents a footer for its nearest ancestor sectioning content or sectioning root element. A footer typically contains information about its section such as who wrote it, links to related documents, copyright data, and the like.')), - address: new HTMLTagSpecification( - nls.localize('tags.address', 'The address element represents the contact information for its nearest article or body element ancestor. If that is the body element, then the contact information applies to the document as a whole.')), - // Grouping content - p: new HTMLTagSpecification( - nls.localize('tags.p', 'The p element represents a paragraph.')), - hr: new HTMLTagSpecification( - nls.localize('tags.hr', 'The hr element represents a paragraph-level thematic break, e.g. a scene change in a story, or a transition to another topic within a section of a reference book.')), - pre: new HTMLTagSpecification( - nls.localize('tags.pre', 'The pre element represents a block of preformatted text, in which structure is represented by typographic conventions rather than by elements.')), - blockquote: new HTMLTagSpecification( - nls.localize('tags.blockquote', 'The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a footer or cite element, and optionally with in-line changes such as annotations and abbreviations.'), - ['cite']), - ol: new HTMLTagSpecification( - nls.localize('tags.ol', 'The ol element represents a list of items, where the items have been intentionally ordered, such that changing the order would change the meaning of the document.'), - ['reversed:v', 'start', 'type:lt']), - ul: new HTMLTagSpecification( - nls.localize('tags.ul', 'The ul element represents a list of items, where the order of the items is not important — that is, where changing the order would not materially change the meaning of the document.')), - li: new HTMLTagSpecification( - nls.localize('tags.li', 'The li element represents a list item. If its parent element is an ol, ul, or menu element, then the element is an item of the parent element\'s list, as defined for those elements. Otherwise, the list item has no defined list-related relationship to any other li element.'), - ['value']), - dl: new HTMLTagSpecification( - nls.localize('tags.dl', 'The dl element represents an association list consisting of zero or more name-value groups (a description list). A name-value group consists of one or more names (dt elements) followed by one or more values (dd elements), ignoring any nodes other than dt and dd elements. Within a single dl element, there should not be more than one dt element for each name.')), - dt: new HTMLTagSpecification( - nls.localize('tags.dt', 'The dt element represents the term, or name, part of a term-description group in a description list (dl element).')), - dd: new HTMLTagSpecification( - nls.localize('tags.dd', 'The dd element represents the description, definition, or value, part of a term-description group in a description list (dl element).')), - figure: new HTMLTagSpecification( - nls.localize('tags.figure', 'The figure element represents some flow content, optionally with a caption, that is self-contained (like a complete sentence) and is typically referenced as a single unit from the main flow of the document.')), - figcaption: new HTMLTagSpecification( - nls.localize('tags.figcaption', 'The figcaption element represents a caption or legend for the rest of the contents of the figcaption element\'s parent figure element, if any.')), - main: new HTMLTagSpecification( - nls.localize('tags.main', 'The main element represents the main content of the body of a document or application. The main content area consists of content that is directly related to or expands upon the central topic of a document or central functionality of an application.')), - div: new HTMLTagSpecification( - nls.localize('tags.div', 'The div element has no special meaning at all. It represents its children. It can be used with the class, lang, and title attributes to mark up semantics common to a group of consecutive elements.')), - // Text-level semantics - a: new HTMLTagSpecification( - nls.localize('tags.a', 'If the a element has an href attribute, then it represents a hyperlink (a hypertext anchor) labeled by its contents.'), - ['href', 'target', 'download', 'ping', 'rel', 'hreflang', 'type']), - em: new HTMLTagSpecification( - nls.localize('tags.em', 'The em element represents stress emphasis of its contents.')), - strong: new HTMLTagSpecification( - nls.localize('tags.strong', 'The strong element represents strong importance, seriousness, or urgency for its contents.')), - small: new HTMLTagSpecification( - nls.localize('tags.small', 'The small element represents side comments such as small print.')), - s: new HTMLTagSpecification( - nls.localize('tags.s', 'The s element represents contents that are no longer accurate or no longer relevant.')), - cite: new HTMLTagSpecification( - nls.localize('tags.cite', 'The cite element represents a reference to a creative work. It must include the title of the work or the name of the author(person, people or organization) or an URL reference, or a reference in abbreviated form as per the conventions used for the addition of citation metadata.')), - q: new HTMLTagSpecification( - nls.localize('tags.q', 'The q element represents some phrasing content quoted from another source.'), - ['cite']), - dfn: new HTMLTagSpecification( - nls.localize('tags.dfn', 'The dfn element represents the defining instance of a term. The paragraph, description list group, or section that is the nearest ancestor of the dfn element must also contain the definition(s) for the term given by the dfn element.')), - abbr: new HTMLTagSpecification( - nls.localize('tags.abbr', 'The abbr element represents an abbreviation or acronym, optionally with its expansion. The title attribute may be used to provide an expansion of the abbreviation. The attribute, if specified, must contain an expansion of the abbreviation, and nothing else.')), - ruby: new HTMLTagSpecification( - nls.localize('tags.ruby', 'The ruby element allows one or more spans of phrasing content to be marked with ruby annotations. Ruby annotations are short runs of text presented alongside base text, primarily used in East Asian typography as a guide for pronunciation or to include other annotations. In Japanese, this form of typography is also known as furigana. Ruby text can appear on either side, and sometimes both sides, of the base text, and it is possible to control its position using CSS. A more complete introduction to ruby can be found in the Use Cases & Exploratory Approaches for Ruby Markup document as well as in CSS Ruby Module Level 1. [RUBY-UC] [CSSRUBY]')), - rb: new HTMLTagSpecification( - nls.localize('tags.rb', 'The rb element marks the base text component of a ruby annotation. When it is the child of a ruby element, it doesn\'t represent anything itself, but its parent ruby element uses it as part of determining what it represents.')), - rt: new HTMLTagSpecification( - nls.localize('tags.rt', 'The rt element marks the ruby text component of a ruby annotation. When it is the child of a ruby element or of an rtc element that is itself the child of a ruby element, it doesn\'t represent anything itself, but its ancestor ruby element uses it as part of determining what it represents.')), - // is not yet supported by 2+ browsers - //rtc: new HTMLTagSpecification( - // nls.localize('tags.rtc', 'The rtc element marks a ruby text container for ruby text components in a ruby annotation. When it is the child of a ruby element it doesn\'t represent anything itself, but its parent ruby element uses it as part of determining what it represents.')), - rp: new HTMLTagSpecification( - nls.localize('tags.rp', 'The rp element is used to provide fallback text to be shown by user agents that don\'t support ruby annotations. One widespread convention is to provide parentheses around the ruby text component of a ruby annotation.')), - // is not yet supported by 2+ browsers - //data: new HTMLTagSpecification( - // nls.localize('tags.data', 'The data element represents its contents, along with a machine-readable form of those contents in the value attribute.')), - time: new HTMLTagSpecification( - nls.localize('tags.time', 'The time element represents its contents, along with a machine-readable form of those contents in the datetime attribute. The kind of content is limited to various kinds of dates, times, time-zone offsets, and durations, as described below.'), - ['datetime']), - code: new HTMLTagSpecification( - nls.localize('tags.code', 'The code element represents a fragment of computer code. This could be an XML element name, a file name, a computer program, or any other string that a computer would recognize.')), - var: new HTMLTagSpecification( - nls.localize('tags.var', 'The var element represents a variable. This could be an actual variable in a mathematical expression or programming context, an identifier representing a constant, a symbol identifying a physical quantity, a function parameter, or just be a term used as a placeholder in prose.')), - samp: new HTMLTagSpecification( - nls.localize('tags.samp', 'The samp element represents sample or quoted output from another program or computing system.')), - kbd: new HTMLTagSpecification( - nls.localize('tags.kbd', 'The kbd element represents user input (typically keyboard input, although it may also be used to represent other input, such as voice commands).')), - sub: new HTMLTagSpecification( - nls.localize('tags.sub', 'The sub element represents a subscript.')), - sup: new HTMLTagSpecification( - nls.localize('tags.sup', 'The sup element represents a superscript.')), - i: new HTMLTagSpecification( - nls.localize('tags.i', 'The i element represents a span of text in an alternate voice or mood, or otherwise offset from the normal prose in a manner indicating a different quality of text, such as a taxonomic designation, a technical term, an idiomatic phrase from another language, transliteration, a thought, or a ship name in Western texts.')), - b: new HTMLTagSpecification( - nls.localize('tags.b', 'The b element represents a span of text to which attention is being drawn for utilitarian purposes without conveying any extra importance and with no implication of an alternate voice or mood, such as key words in a document abstract, product names in a review, actionable words in interactive text-driven software, or an article lede.')), - u: new HTMLTagSpecification( - nls.localize('tags.u', 'The u element represents a span of text with an unarticulated, though explicitly rendered, non-textual annotation, such as labeling the text as being a proper name in Chinese text (a Chinese proper name mark), or labeling the text as being misspelt.')), - mark: new HTMLTagSpecification( - nls.localize('tags.mark', 'The mark element represents a run of text in one document marked or highlighted for reference purposes, due to its relevance in another context. When used in a quotation or other block of text referred to from the prose, it indicates a highlight that was not originally present but which has been added to bring the reader\'s attention to a part of the text that might not have been considered important by the original author when the block was originally written, but which is now under previously unexpected scrutiny. When used in the main prose of a document, it indicates a part of the document that has been highlighted due to its likely relevance to the user\'s current activity.')), - bdi: new HTMLTagSpecification( - nls.localize('tags.bdi', 'The bdi element represents a span of text that is to be isolated from its surroundings for the purposes of bidirectional text formatting. [BIDI]')), - bdo: new HTMLTagSpecification( - nls.localize('tags.dbo', 'The bdo element represents explicit text directionality formatting control for its children. It allows authors to override the Unicode bidirectional algorithm by explicitly specifying a direction override. [BIDI]')), - span: new HTMLTagSpecification( - nls.localize('tags.span', 'The span element doesn\'t mean anything on its own, but can be useful when used together with the global attributes, e.g. class, lang, or dir. It represents its children.')), - br: new HTMLTagSpecification( - nls.localize('tags.br', 'The br element represents a line break.')), - wbr: new HTMLTagSpecification( - nls.localize('tags.wbr', 'The wbr element represents a line break opportunity.')), - // Edits - ins: new HTMLTagSpecification( - nls.localize('tags.ins', 'The ins element represents an addition to the document.')), - del: new HTMLTagSpecification( - nls.localize('tags.del', 'The del element represents a removal from the document.'), - ['cite', 'datetime']), - // Embedded content - picture: new HTMLTagSpecification( - nls.localize('tags.picture', 'The picture element is a container which provides multiple sources to its contained img element to allow authors to declaratively control or give hints to the user agent about which image resource to use, based on the screen pixel density, viewport size, image format, and other factors. It represents its children.')), - img: new HTMLTagSpecification( - nls.localize('tags.img', 'An img element represents an image.'), - ['alt', 'src', 'srcset', 'crossorigin:xo', 'usemap', 'ismap:v', 'width', 'height']), - iframe: new HTMLTagSpecification( - nls.localize('tags.iframe', 'The iframe element represents a nested browsing context.'), - ['src', 'srcdoc', 'name', 'sandbox:sb', 'seamless:v', 'allowfullscreen:v', 'width', 'height']), - embed: new HTMLTagSpecification( - nls.localize('tags.embed', 'The embed element provides an integration point for an external (typically non-HTML) application or interactive content.'), - ['src', 'type', 'width', 'height']), - object: new HTMLTagSpecification( - nls.localize('tags.object', 'The object element can represent an external resource, which, depending on the type of the resource, will either be treated as an image, as a nested browsing context, or as an external resource to be processed by a plugin.'), - ['data', 'type', 'typemustmatch:v', 'name', 'usemap', 'form', 'width', 'height']), - param: new HTMLTagSpecification( - nls.localize('tags.param', 'The param element defines parameters for plugins invoked by object elements. It does not represent anything on its own.'), - ['name', 'value']), - video: new HTMLTagSpecification( - nls.localize('tags.video', 'A video element is used for playing videos or movies, and audio files with captions.'), - ['src', 'crossorigin:xo', 'poster', 'preload:pl', 'autoplay:v', 'mediagroup', 'loop:v', 'muted:v', 'controls:v', 'width', 'height']), - audio: new HTMLTagSpecification( - nls.localize('tags.audio', 'An audio element represents a sound or audio stream.'), - ['src', 'crossorigin:xo', 'preload:pl', 'autoplay:v', 'mediagroup', 'loop:v', 'muted:v', 'controls:v']), - source: new HTMLTagSpecification( - nls.localize('tags.source', 'The source element allows authors to specify multiple alternative media resources for media elements. It does not represent anything on its own.'), - // 'When the source element has a parent that is a picture element, the source element allows authors to specify multiple alternative source sets for img elements.' - ['src', 'type']), - track: new HTMLTagSpecification( - nls.localize('tags.track', 'The track element allows authors to specify explicit external timed text tracks for media elements. It does not represent anything on its own.'), - ['default:v', 'kind:tk', 'label', 'src', 'srclang']), - map: new HTMLTagSpecification( - nls.localize('tags.map', 'The map element, in conjunction with an img element and any area element descendants, defines an image map. The element represents its children.'), - ['name']), - area: new HTMLTagSpecification( - nls.localize('tags.area', 'The area element represents either a hyperlink with some text and a corresponding area on an image map, or a dead area on an image map.'), - ['alt', 'coords', 'shape:sh', 'href', 'target', 'download', 'ping', 'rel', 'hreflang', 'type']), - // Tabular data - table: new HTMLTagSpecification( - nls.localize('tags.table', 'The table element represents data with more than one dimension, in the form of a table.'), - ['sortable:v', 'border']), - caption: new HTMLTagSpecification( - nls.localize('tags.caption', 'The caption element represents the title of the table that is its parent, if it has a parent and that is a table element.')), - colgroup: new HTMLTagSpecification( - nls.localize('tags.colgroup', 'The colgroup element represents a group of one or more columns in the table that is its parent, if it has a parent and that is a table element.'), - ['span']), - col: new HTMLTagSpecification( - nls.localize('tags.col', 'If a col element has a parent and that is a colgroup element that itself has a parent that is a table element, then the col element represents one or more columns in the column group represented by that colgroup.'), - ['span']), - tbody: new HTMLTagSpecification( - nls.localize('tags.tbody', 'The tbody element represents a block of rows that consist of a body of data for the parent table element, if the tbody element has a parent and it is a table.')), - thead: new HTMLTagSpecification( - nls.localize('tags.thead', 'The thead element represents the block of rows that consist of the column labels (headers) for the parent table element, if the thead element has a parent and it is a table.')), - tfoot: new HTMLTagSpecification( - nls.localize('tags.tfoot', 'The tfoot element represents the block of rows that consist of the column summaries (footers) for the parent table element, if the tfoot element has a parent and it is a table.')), - tr: new HTMLTagSpecification( - nls.localize('tags.tr', 'The tr element represents a row of cells in a table.')), - td: new HTMLTagSpecification( - nls.localize('tags.td', 'The td element represents a data cell in a table.'), - ['colspan', 'rowspan', 'headers']), - th: new HTMLTagSpecification( - nls.localize('tags.th', 'The th element represents a header cell in a table.'), - ['colspan', 'rowspan', 'headers', 'scope:s', 'sorted', 'abbr']), - // Forms - form: new HTMLTagSpecification( - nls.localize('tags.form', 'The form element represents a collection of form-associated elements, some of which can represent editable values that can be submitted to a server for processing.'), - ['accept-charset', 'action', 'autocomplete:o', 'enctype:et', 'method:m', 'name', 'novalidate:v', 'target']), - label: new HTMLTagSpecification( - nls.localize('tags.label', 'The label element represents a caption in a user interface. The caption can be associated with a specific form control, known as the label element\'s labeled control, either using the for attribute, or by putting the form control inside the label element itself.'), - ['form', 'for']), - input: new HTMLTagSpecification( - nls.localize('tags.input', 'The input element represents a typed data field, usually with a form control to allow the user to edit the data.'), - ['accept', 'alt', 'autocomplete:inputautocomplete', 'autofocus:v', 'checked:v', 'dirname', 'disabled:v', 'form', 'formaction', 'formenctype:et', 'formmethod:fm', 'formnovalidate:v', 'formtarget', 'height', 'inputmode:im', 'list', 'max', 'maxlength', 'min', 'minlength', 'multiple:v', 'name', 'pattern', 'placeholder', 'readonly:v', 'required:v', 'size', 'src', 'step', 'type:t', 'value', 'width']), - button: new HTMLTagSpecification( - nls.localize('tags.button', 'The button element represents a button labeled by its contents.'), - ['autofocus:v', 'disabled:v', 'form', 'formaction', 'formenctype:et', 'formmethod:fm', 'formnovalidate:v', 'formtarget', 'name', 'type:bt', 'value']), - select: new HTMLTagSpecification( - nls.localize('tags.select', 'The select element represents a control for selecting amongst a set of options.'), - ['autocomplete:inputautocomplete', 'autofocus:v', 'disabled:v', 'form', 'multiple:v', 'name', 'required:v', 'size']), - datalist: new HTMLTagSpecification( - nls.localize('tags.datalist', 'The datalist element represents a set of option elements that represent predefined options for other controls. In the rendering, the datalist element represents nothing and it, along with its children, should be hidden.')), - optgroup: new HTMLTagSpecification( - nls.localize('tags.optgroup', 'The optgroup element represents a group of option elements with a common label.'), - ['disabled:v', 'label']), - option: new HTMLTagSpecification( - nls.localize('tags.option', 'The option element represents an option in a select element or as part of a list of suggestions in a datalist element.'), - ['disabled:v', 'label', 'selected:v', 'value']), - textarea: new HTMLTagSpecification( - nls.localize('tags.textarea', 'The textarea element represents a multiline plain text edit control for the element\'s raw value. The contents of the control represent the control\'s default value.'), - ['autocomplete:inputautocomplete', 'autofocus:v', 'cols', 'dirname', 'disabled:v', 'form', 'inputmode:im', 'maxlength', 'minlength', 'name', 'placeholder', 'readonly:v', 'required:v', 'rows', 'wrap:w']), - output: new HTMLTagSpecification( - nls.localize('tags.output', 'The output element represents the result of a calculation performed by the application, or the result of a user action.'), - ['for', 'form', 'name']), - progress: new HTMLTagSpecification( - nls.localize('tags.progress', 'The progress element represents the completion progress of a task. The progress is either indeterminate, indicating that progress is being made but that it is not clear how much more work remains to be done before the task is complete (e.g. because the task is waiting for a remote host to respond), or the progress is a number in the range zero to a maximum, giving the fraction of work that has so far been completed.'), - ['value', 'max']), - meter: new HTMLTagSpecification( - nls.localize('tags.meter', 'The meter element represents a scalar measurement within a known range, or a fractional value; for example disk usage, the relevance of a query result, or the fraction of a voting population to have selected a particular candidate.'), - ['value', 'min', 'max', 'low', 'high', 'optimum']), - fieldset: new HTMLTagSpecification( - nls.localize('tags.fieldset', 'The fieldset element represents a set of form controls optionally grouped under a common name.'), - ['disabled:v', 'form', 'name']), - legend: new HTMLTagSpecification( - nls.localize('tags.legend', 'The legend element represents a caption for the rest of the contents of the legend element\'s parent fieldset element, if any.')), - // Interactive elements - details: new HTMLTagSpecification( - nls.localize('tags.details', 'The details element represents a disclosure widget from which the user can obtain additional information or controls.'), - ['open:v']), - summary: new HTMLTagSpecification( - nls.localize('tags.summary', 'The summary element represents a summary, caption, or legend for the rest of the contents of the summary element\'s parent details element, if any.')), - // and are not yet supported by 2+ browsers - //menu: new HTMLTagSpecification( - // nls.localize('tags.menu', 'The menu element represents a list of commands.'), - // ['type:mt', 'label']), - //menuitem: new HTMLTagSpecification( - // nls.localize('tags.menuitem', 'The menuitem element represents a command that the user can invoke from a popup menu (either a context menu or the menu of a menu button).')), - dialog: new HTMLTagSpecification( - nls.localize('tags.dialog', 'The dialog element represents a part of an application that a user interacts with to perform a task, for example a dialog box, inspector, or window.')), - // Scripting - script: new HTMLTagSpecification( - nls.localize('tags.script', 'The script element allows authors to include dynamic script and data blocks in their documents. The element does not represent content for the user.'), - ['src', 'type', 'charset', 'async:v', 'defer:v', 'crossorigin:xo', 'nonce']), - noscript: new HTMLTagSpecification( - nls.localize('tags.noscript', 'The noscript element represents nothing if scripting is enabled, and represents its children if scripting is disabled. It is used to present different markup to user agents that support scripting and those that don\'t support scripting, by affecting how the document is parsed.')), - template: new HTMLTagSpecification( - nls.localize('tags.template', 'The template element is used to declare fragments of HTML that can be cloned and inserted in the document by script.')), - canvas: new HTMLTagSpecification( - nls.localize('tags.canvas', 'The canvas element provides scripts with a resolution-dependent bitmap canvas, which can be used for rendering graphs, game graphics, art, or other visual images on the fly.'), - ['width', 'height']) -}; - -// Ionic tag information sourced from Ionic main website (https://github.com/driftyco/ionic-site) -export const IONIC_TAGS: ITagSet = { - 'ion-checkbox': new HTMLTagSpecification(nls.localize('tags.ion.checkbox', 'The checkbox is no different than the HTML checkbox input, except it\'s styled differently. The checkbox behaves like any AngularJS checkbox.'), - ['name', 'ng-false-value', 'ng-model', 'ng-true-value']), - 'ion-content': new HTMLTagSpecification(nls.localize('tags.ion.content', 'The ionContent directive provides an easy to use content area that can be configured to use Ionic\'s custom Scroll View, or the built-in overflow scrolling of the browser.'), - ['delegate-handle', 'direction:scrolldir', 'has-bouncing:b', 'locking:b', 'on-scroll', 'on-scroll-complete', 'overflow-scroll:b', 'padding:b', 'scroll:b', 'scrollbar-x:b', 'scrollbar-y:b', 'start-x', 'start-y']), - 'ion-delete-button': new HTMLTagSpecification(nls.localize('tags.ion.deletebutton', 'Child of ionItem'), - []), - 'ion-footer-bar': new HTMLTagSpecification(nls.localize('tags.ion.footerbar', 'Adds a fixed footer bar below some content. Can also be a subfooter (higher up) if the "bar-subfooter" class is applied.'), - ['align-title:align', 'keyboard-attach:v']), - 'ion-header-bar': new HTMLTagSpecification(nls.localize('tags.ion.headerbar', 'Adds a fixed header bar above some content. Can also be a subheader (lower down) if the "bar-subheader" class is applied.'), - ['align-title:align', 'no-tap-scroll:b']), - 'ion-infinite-scroll': new HTMLTagSpecification(nls.localize('tags.ion.infinitescroll', 'Child of ionContent or ionScroll. The ionInfiniteScroll directive allows you to call a function whenever the user gets to the bottom of the page or near the bottom of the page.'), - ['distance', 'icon', 'immediate-check:b', 'on-infinite', 'spinner']), - 'ion-input': new HTMLTagSpecification(nls.localize('tags.ion.input', 'ionInput is meant for text type inputs only. Ionic uses an actual HTML element within the component, with Ionic wrapping to better handle the user experience and interactivity.'), - ['type:inputtype', 'clearInput:v']), - 'ion-item': new HTMLTagSpecification(nls.localize('tags.ion.item', 'Child of ionList.'), - []), - 'ion-list': new HTMLTagSpecification(nls.localize('tags.ion.list', 'The List is a widely used interface element in almost any mobile app, and can include content ranging from basic text all the way to buttons, toggles, icons, and thumbnails.'), - ['can-swipe:b', 'delegate-handle', 'show-delete:b', 'show-reorder:b', 'type:listtype']), - 'ion-modal-view': new HTMLTagSpecification(nls.localize('tags.ion.modalview', 'The Modal is a content pane that can go over the user\'s main view temporarily. Usually used for making a choice or editing an item.'), - []), - 'ion-nav-back-button': new HTMLTagSpecification(nls.localize('tags.ion.navbackbutton', 'Child of ionNavBar. Creates a back button inside an ionNavBar. The back button will appear when the user is able to go back in the current navigation stack.'), - []), - 'ion-nav-bar': new HTMLTagSpecification(nls.localize('tags.ion.navbar', 'If you have an ionNavView directive, you can also create an , which will create a topbar that updates as the application state changes.'), - ['align-title:align', 'delegate-handle', 'no-tap-scroll:b']), - 'ion-nav-buttons': new HTMLTagSpecification(nls.localize('tags.ion.navbuttons', 'Child of ionNavView. Use ionNavButtons to set the buttons on your ionNavBar from within an ionView.'), - ['side:navsides']), - 'ion-nav-title': new HTMLTagSpecification(nls.localize('tags.ion.navtitle', 'Child of ionNavView. The ionNavTitle directive replaces an ionNavBar title text with custom HTML from within an ionView template.'), - []), - 'ion-nav-view': new HTMLTagSpecification(nls.localize('tags.ion.navview', 'The ionNavView directive is used to render templates in your application. Each template is part of a state. States are usually mapped to a url, and are defined programatically using angular-ui-router.'), - ['name']), - 'ion-option-button': new HTMLTagSpecification(nls.localize('tags.ion.optionbutton', 'Child of ionItem. Creates an option button inside a list item, that is visible when the item is swiped to the left by the user.'), - []), - 'ion-pane': new HTMLTagSpecification(nls.localize('tags.ion.pane', 'A simple container that fits content, with no side effects. Adds the "pane" class to the element.'), - []), - 'ion-popover-view': new HTMLTagSpecification(nls.localize('tags.ion.popoverview', 'The Popover is a view that floats above an app\'s content. Popovers provide an easy way to present or gather information from the user.'), - []), - 'ion-radio': new HTMLTagSpecification(nls.localize('tags.ion.radio', 'The radio ionRirective is no different than the HTML radio input, except it\'s styled differently. The ionRadio behaves like AngularJS radio input.'), - ['disabled:b', 'icon', 'name', 'ng-disabled:b', 'ng-model', 'ng-value', 'value']), - 'ion-refresher': new HTMLTagSpecification(nls.localize('tags.ion.refresher', 'Child of ionContent or ionScroll. Allows you to add pull-to-refresh to a scrollView. Place it as the first child of your ionContent or ionScroll element.'), - ['disable-pulling-rotation:b', 'on-pulling', 'on-refresh', 'pulling-icon', 'pulling-text', 'refreshing-icon', 'spinner']), - 'ion-reorder-button': new HTMLTagSpecification(nls.localize('tags.ion.reorderbutton', 'Child of ionItem.'), - ['on-reorder']), - 'ion-scroll': new HTMLTagSpecification(nls.localize('tags.ion.scroll', 'Creates a scrollable container for all content inside.'), - ['delegate-handle', 'direction:scrolldir', 'has-bouncing:b', 'locking:b', 'max-zoom', 'min-zoom', 'on-refresh', 'on-scroll', 'paging:b', 'scrollbar-x:b', 'scrollbar-y:b', 'zooming:b']), - 'ion-side-menu': new HTMLTagSpecification(nls.localize('tags.ion.sidemenu', 'Child of ionSideMenus. A container for a side menu, sibling to an ionSideMenuContent directive.'), - ['is-enabled:b', 'expose-aside-when', 'side:navsides', 'width']), - 'ion-side-menu-content': new HTMLTagSpecification(nls.localize('tags.ion.sidemenucontent', 'Child of ionSideMenus. A container for the main visible content, sibling to one or more ionSideMenu directives.'), - ['drag-content:b', 'edge-drag-threshold']), - 'ion-side-menus': new HTMLTagSpecification(nls.localize('tags.ion.sidemenus', 'A container element for side menu(s) and the main content. Allows the left and/or right side menu to be toggled by dragging the main content area side to side.'), - ['delegate-handle', 'enable-menu-with-back-views:b']), - 'ion-slide': new HTMLTagSpecification(nls.localize('tags.ion.slide', 'Child of ionSlideBox. Displays a slide inside of a slidebox.'), - []), - 'ion-slide-box': new HTMLTagSpecification(nls.localize('tags.ion.slidebox', 'The Slide Box is a multi-page container where each page can be swiped or dragged between.'), - ['active-slide', 'auto-play:b', 'delegate-handle', 'does-continue:b', 'on-slide-changed', 'pager-click', 'show-pager:b', 'slide-interval']), - 'ion-spinner': new HTMLTagSpecification(nls.localize('tags.ion.spinner', 'The ionSpinner directive provides a variety of animated spinners.'), - ['icon']), - 'ion-tab': new HTMLTagSpecification(nls.localize('tags.ion.tab', 'Child of ionTabs. Contains a tab\'s content. The content only exists while the given tab is selected.'), - ['badge', 'badge-style', 'disabled', 'hidden', 'href', 'icon', 'icon-off', 'icon-on', 'ng-click', 'on-deselect', 'on-select', 'title']), - 'ion-tabs': new HTMLTagSpecification(nls.localize('tags.ion.tabs', 'Powers a multi-tabbed interface with a tab bar and a set of "pages" that can be tabbed through.'), - ['delegate-handle']), - 'ion-title': new HTMLTagSpecification(nls.localize('tags.ion.title', 'ion-title is a component that sets the title of the ionNavbar'), - []), - 'ion-toggle': new HTMLTagSpecification(nls.localize('tags.ion.toggle', 'A toggle is an animated switch which binds a given model to a boolean. Allows dragging of the switch\'s nub. The toggle behaves like any AngularJS checkbox otherwise.'), - ['name', 'ng-false-value', 'ng-model', 'ng-true-value', 'toggle-class']), - 'ion-view ': new HTMLTagSpecification(nls.localize('tags.ion.view', 'Child of ionNavView. A container for view content and any navigational and header bar information.'), - ['cache-view:b', 'can-swipe-back:b', 'hide-back-button:b', 'hide-nav-bar:b', 'view-title']) -}; - -export function getHTML5TagProvider(): IHTMLTagProvider { - var globalAttributes = [ - 'aria-activedescendant', 'aria-atomic:b', 'aria-autocomplete:autocomplete', 'aria-busy:b', 'aria-checked:tristate', 'aria-colcount', 'aria-colindex', 'aria-colspan', 'aria-controls', 'aria-current:current', 'aria-describedat', - 'aria-describedby', 'aria-disabled:b', 'aria-dropeffect:dropeffect', 'aria-errormessage', 'aria-expanded:u', 'aria-flowto', 'aria-grabbed:u', 'aria-haspopup:b', 'aria-hidden:b', 'aria-invalid:invalid', 'aria-kbdshortcuts', - 'aria-label', 'aria-labelledby', 'aria-level', 'aria-live:live', 'aria-modal:b', 'aria-multiline:b', 'aria-multiselectable:b', 'aria-orientation:orientation', 'aria-owns', 'aria-placeholder', 'aria-posinset', 'aria-pressed:tristate', - 'aria-readonly:b', 'aria-relevant:relevant', 'aria-required:b', 'aria-roledescription', 'aria-rowcount', 'aria-rowindex', 'aria-rowspan', 'aria-selected:u', 'aria-setsize', 'aria-sort:sort', 'aria-valuemax', 'aria-valuemin', 'aria-valuenow', 'aria-valuetext', - 'accesskey', 'class', 'contenteditable:b', 'contextmenu', 'dir:d', 'draggable:b', 'dropzone', 'hidden:v', 'id', 'itemid', 'itemprop', 'itemref', 'itemscope:v', 'itemtype', 'lang', 'role:roles', 'spellcheck:b', 'style', 'tabindex', - 'title', 'translate:y']; - - var eventHandlers = ['onabort', 'onblur', 'oncanplay', 'oncanplaythrough', 'onchange', 'onclick', 'oncontextmenu', 'ondblclick', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', - 'ondrop', 'ondurationchange', 'onemptied', 'onended', 'onerror', 'onfocus', 'onformchange', 'onforminput', 'oninput', 'oninvalid', 'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onloadeddata', 'onloadedmetadata', - 'onloadstart', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onpause', 'onplay', 'onplaying', 'onprogress', 'onratechange', 'onreset', 'onresize', 'onreadystatechange', 'onscroll', - 'onseeked', 'onseeking', 'onselect', 'onshow', 'onstalled', 'onsubmit', 'onsuspend', 'ontimeupdate', 'onvolumechange', 'onwaiting']; - - var valueSets: IValueSets = { - b: ['true', 'false'], - u: ['true', 'false', 'undefined'], - o: ['on', 'off'], - y: ['yes', 'no'], - w: ['soft', 'hard'], - d: ['ltr', 'rtl', 'auto'], - m: ['GET', 'POST', 'dialog'], - fm: ['GET', 'POST'], - s: ['row', 'col', 'rowgroup', 'colgroup'], - t: ['hidden', 'text', 'search', 'tel', 'url', 'email', 'password', 'datetime', 'date', 'month', 'week', 'time', 'datetime-local', 'number', 'range', 'color', 'checkbox', 'radio', 'file', 'submit', 'image', 'reset', 'button'], - im: ['verbatim', 'latin', 'latin-name', 'latin-prose', 'full-width-latin', 'kana', 'kana-name', 'katakana', 'numeric', 'tel', 'email', 'url'], - bt: ['button', 'submit', 'reset', 'menu'], - lt: ['1', 'a', 'A', 'i', 'I'], - mt: ['context', 'toolbar'], - mit: ['command', 'checkbox', 'radio'], - et: ['application/x-www-form-urlencoded', 'multipart/form-data', 'text/plain'], - tk: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata'], - pl: ['none', 'metadata', 'auto'], - sh: ['circle', 'default', 'poly', 'rect'], - xo: ['anonymous', 'use-credentials'], - sb: ['allow-forms', 'allow-modals', 'allow-pointer-lock', 'allow-popups', 'allow-popups-to-escape-sandbox', 'allow-same-origin', 'allow-scripts', 'allow-top-navigation'], - tristate: ['true', 'false', 'mixed', 'undefined'], - inputautocomplete: ['additional-name', 'address-level1', 'address-level2', 'address-level3', 'address-level4', 'address-line1', 'address-line2', 'address-line3', 'bday', 'bday-year', 'bday-day', 'bday-month', 'billing', 'cc-additional-name', 'cc-csc', 'cc-exp', 'cc-exp-month', 'cc-exp-year', 'cc-family-name', 'cc-given-name', 'cc-name', 'cc-number', 'cc-type', 'country', 'country-name', 'current-password', 'email', 'family-name', 'fax', 'given-name', 'home', 'honorific-prefix', 'honorific-suffix', 'impp', 'language', 'mobile', 'name', 'new-password', 'nickname', 'organization', 'organization-title', 'pager', 'photo', 'postal-code', 'sex', 'shipping', 'street-address', 'tel-area-code', 'tel', 'tel-country-code', 'tel-extension', 'tel-local', 'tel-local-prefix', 'tel-local-suffix', 'tel-national', 'transaction-amount', 'transaction-currency', 'url', 'username', 'work'], - autocomplete: ['inline', 'list', 'both', 'none'], - current: ['page', 'step', 'location', 'date', 'time', 'true', 'false'], - dropeffect: ['copy', 'move', 'link', 'execute', 'popup', 'none'], - invalid: ['grammar', 'false', 'spelling', 'true'], - live: ['off', 'polite', 'assertive'], - orientation: ['vertical', 'horizontal', 'undefined'], - relevant: ['additions', 'removals', 'text', 'all', 'additions text'], - sort: ['ascending', 'descending', 'none', 'other'], - roles: ['alert', 'alertdialog', 'button', 'checkbox', 'dialog', 'gridcell', 'link', 'log', 'marquee', 'menuitem', 'menuitemcheckbox', 'menuitemradio', 'option', 'progressbar', 'radio', 'scrollbar', 'searchbox', 'slider', - 'spinbutton', 'status', 'switch', 'tab', 'tabpanel', 'textbox', 'timer', 'tooltip', 'treeitem', 'combobox', 'grid', 'listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid', - 'application', 'article', 'cell', 'columnheader', 'definition', 'directory', 'document', 'feed', 'figure', 'group', 'heading', 'img', 'list', 'listitem', 'math', 'none', 'note', 'presentation', 'region', 'row', 'rowgroup', - 'rowheader', 'separator', 'table', 'term', 'text', 'toolbar', - 'banner', 'complementary', 'contentinfo', 'form', 'main', 'navigation', 'region', 'search'] - }; - - return { - getId: () => 'html5', - collectTags: (collector: (tag: string, label: string) => void) => collectTagsDefault(collector, HTML_TAGS), - collectAttributes: (tag: string, collector: (attribute: string, type: string) => void) => { - collectAttributesDefault(tag, collector, HTML_TAGS, globalAttributes); - eventHandlers.forEach(handler => { - collector(handler, 'event'); - }); - }, - collectValues: (tag: string, attribute: string, collector: (value: string) => void) => collectValuesDefault(tag, attribute, collector, HTML_TAGS, globalAttributes, valueSets) - }; -} - - -export function getAngularTagProvider(): IHTMLTagProvider { - var customTags: { [tag: string]: string[] } = { - input: ['ng-model', 'ng-required', 'ng-minlength', 'ng-maxlength', 'ng-pattern', 'ng-trim'], - select: ['ng-model'], - textarea: ['ng-model', 'ng-required', 'ng-minlength', 'ng-maxlength', 'ng-pattern', 'ng-trim'] - }; - - var globalAttributes = ['ng-app', 'ng-bind', 'ng-bind-html', 'ng-bind-template', 'ng-blur', 'ng-change', 'ng-checked', 'ng-class', 'ng-class-even', 'ng-class-odd', - 'ng-click', 'ng-cloak', 'ng-controller', 'ng-copy', 'ng-csp', 'ng-cut', 'ng-dblclick', 'ng-disabled', 'ng-focus', 'ng-form', 'ng-hide', 'ng-href', 'ng-if', - 'ng-include', 'ng-init', 'ng-jq', 'ng-keydown', 'ng-keypress', 'ng-keyup', 'ng-list', 'ng-model-options', 'ng-mousedown', 'ng-mouseenter', 'ng-mouseleave', - 'ng-mousemove', 'ng-mouseover', 'ng-mouseup', 'ng-non-bindable', 'ng-open', 'ng-options', 'ng-paste', 'ng-pluralize', 'ng-readonly', 'ng-repeat', 'ng-selected', - 'ng-show', 'ng-src', 'ng-srcset', 'ng-style', 'ng-submit', 'ng-switch', 'ng-transclude', 'ng-value' - ]; - - return { - getId: () => 'angular1', - collectTags: (collector: (tag: string) => void) => { - // no extra tags - }, - collectAttributes: (tag: string, collector: (attribute: string, type: string) => void) => { - if (tag) { - var attributes = customTags[tag]; - if (attributes) { - attributes.forEach((a) => { - collector(a, null); - collector('data-' + a, null); - }); - } - } - globalAttributes.forEach((a) => { - collector(a, null); - collector('data-' + a, null); - }); - }, - collectValues: (tag: string, attribute: string, collector: (value: string) => void) => { - // no values - } - }; -} - -export function getIonicTagProvider(): IHTMLTagProvider { - var customTags: { [tag: string]: string[] } = { - a: ['nav-direction:navdir', 'nav-transition:trans'], - button: ['menu-toggle:menusides'] - }; - - var globalAttributes = ['collection-repeat', 'force-refresh-images:b', 'ion-stop-event', 'item-height', 'item-render-buffer', 'item-width', 'menu-close:v', - 'on-double-tap', 'on-drag', 'on-drag-down', 'on-drag-left', 'on-drag-right', 'on-drag-up', 'on-hold', 'on-release', 'on-swipe', 'on-swipe-down', 'on-swipe-left', - 'on-swipe-right', 'on-swipe-up', 'on-tap', 'on-touch']; - - var valueSets: IValueSets = { - align: ['center', 'left', 'right'], - b: ['true', 'false'], - inputtype: ['email', 'number', 'password', 'search', 'tel', 'text', 'url'], - listtype: ['card', 'list-inset'], - menusides: ['left', 'right'], - navdir: ['back', 'enter', 'exit', 'forward', 'swap'], - navsides: ['left', 'primary', 'right', 'secondary'], - scrolldir: ['x', 'xy', 'y'], - trans: ['android', 'ios', 'none'] - }; - - return { - getId: () => 'ionic', - collectTags: (collector: (tag: string, label: string) => void) => collectTagsDefault(collector, IONIC_TAGS), - collectAttributes: (tag: string, collector: (attribute: string, type: string) => void) => { - collectAttributesDefault(tag, collector, IONIC_TAGS, globalAttributes); - if (tag) { - var attributes = customTags[tag]; - if (attributes) { - attributes.forEach((a) => { - var segments = a.split(':'); - collector(segments[0], segments[1]); - }); - } - } - }, - collectValues: (tag: string, attribute: string, collector: (value: string) => void) => collectValuesDefault(tag, attribute, collector, IONIC_TAGS, globalAttributes, valueSets, customTags) - }; -} - -function collectTagsDefault(collector: (tag: string, label: string) => void, tagSet: ITagSet): void { - for (var tag in tagSet) { - collector(tag, tagSet[tag].label); - } -} - -function collectAttributesDefault(tag: string, collector: (attribute: string, type: string) => void, tagSet: ITagSet, globalAttributes: string[]): void { - globalAttributes.forEach(attr => { - var segments = attr.split(':'); - collector(segments[0], segments[1]); - }); - if (tag) { - var tags = tagSet[tag]; - if (tags) { - var attributes = tags.attributes; - if (attributes) { - attributes.forEach(attr => { - var segments = attr.split(':'); - collector(segments[0], segments[1]); - }); - } - } - } -} - -function collectValuesDefault(tag: string, attribute: string, collector: (value: string) => void, tagSet: ITagSet, globalAttributes: string[], valueSets: IValueSets, customTags?: { [tag: string]: string[] }): void { - var prefix = attribute + ':'; - var processAttributes = (attributes: string[]) => { - attributes.forEach((attr) => { - if (attr.length > prefix.length && strings.startsWith(attr, prefix)) { - var typeInfo = attr.substr(prefix.length); - if (typeInfo === 'v') { - collector(attribute); - } else { - var values = valueSets[typeInfo]; - if (values) { - values.forEach(collector); - } - } - } - }); - }; - if (tag) { - var tags = tagSet[tag]; - if (tags) { - var attributes = tags.attributes; - if (attributes) { - processAttributes(attributes); - } - } - } - processAttributes(globalAttributes); - if (customTags) { - var customTagAttributes = customTags[tag]; - if (customTagAttributes) { - processAttributes(customTagAttributes); - } - } -} -/*! -END THIRD PARTY -*/ \ No newline at end of file diff --git a/src/vs/languages/html/common/htmlTokenTypes.ts b/src/vs/languages/html/common/htmlTokenTypes.ts deleted file mode 100644 index 9fecc05e85b..00000000000 --- a/src/vs/languages/html/common/htmlTokenTypes.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import strings = require('vs/base/common/strings'); - -export const DELIM_END = 'punctuation.definition.meta.tag.end.html'; -export const DELIM_START = 'punctuation.definition.meta.tag.begin.html'; -export const DELIM_ASSIGN = 'meta.tag.assign.html'; -export const ATTRIB_NAME = 'entity.other.attribute-name.html'; -export const ATTRIB_VALUE = 'string.html'; -export const COMMENT = 'comment.html.content'; -export const DELIM_COMMENT = 'comment.html'; -export const DOCTYPE = 'entity.other.attribute-name.html'; -export const DELIM_DOCTYPE = 'entity.name.tag.html'; - -const TAG_PREFIX = 'entity.name.tag.tag-'; - -export function isTag(tokenType: string) { - return strings.startsWith(tokenType, TAG_PREFIX); -} - -export function getTag(name: string) { - return TAG_PREFIX + name; -} \ No newline at end of file diff --git a/src/vs/languages/html/common/htmlWorker.ts b/src/vs/languages/html/common/htmlWorker.ts deleted file mode 100644 index 559c0daf443..00000000000 --- a/src/vs/languages/html/common/htmlWorker.ts +++ /dev/null @@ -1,609 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import URI from 'vs/base/common/uri'; -import winjs = require('vs/base/common/winjs.base'); -import beautifyHTML = require('vs/languages/lib/common/beautify-html'); -import htmlTags = require('vs/languages/html/common/htmlTags'); -import network = require('vs/base/common/network'); -import editorCommon = require('vs/editor/common/editorCommon'); -import modes = require('vs/editor/common/modes'); -import strings = require('vs/base/common/strings'); -import {IResourceService, ICompatMirrorModel} from 'vs/editor/common/services/resourceService'; -import {getScanner, IHTMLScanner} from 'vs/languages/html/common/htmlScanner'; -import {isTag, DELIM_END, DELIM_START, DELIM_ASSIGN, ATTRIB_NAME, ATTRIB_VALUE} from 'vs/languages/html/common/htmlTokenTypes'; -import {isEmptyElement} from 'vs/languages/html/common/htmlEmptyTagsShared'; -import {filterSuggestions} from 'vs/editor/common/modes/supports/suggestSupport'; -import paths = require('vs/base/common/paths'); -import {IHTMLConfiguration, IHTMLFormatConfiguration} from 'vs/languages/html/common/html.contribution'; -import {LineTokens} from 'vs/editor/common/core/lineTokens'; - -enum LinkDetectionState { - LOOKING_FOR_HREF_OR_SRC = 1, - AFTER_HREF_OR_SRC = 2 -} - -interface IColorRange { - range:editorCommon.IRange; - value:string; -} - -export class HTMLWorker { - - private resourceService:IResourceService; - private _modeId: string; - private _tagProviders: htmlTags.IHTMLTagProvider[]; - private _formatSettings: IHTMLFormatConfiguration; - private _providerConfiguration: {[providerId:string]:boolean}; - - constructor( - modeId: string, - @IResourceService resourceService: IResourceService - ) { - - this._modeId = modeId; - this.resourceService = resourceService; - - this._tagProviders = []; - this._tagProviders.push(htmlTags.getHTML5TagProvider()); - - this.addCustomTagProviders(this._tagProviders); - - this._providerConfiguration = null; - } - - protected addCustomTagProviders(providers: htmlTags.IHTMLTagProvider[]): void { - providers.push(htmlTags.getAngularTagProvider()); - providers.push(htmlTags.getIonicTagProvider()); - } - - private getTagProviders(): htmlTags.IHTMLTagProvider[] { - if (this._modeId !== 'html' || !this._providerConfiguration) { - return this._tagProviders; - } - return this._tagProviders.filter(p => !!this._providerConfiguration[p.getId()]); - } - - public provideDocumentRangeFormattingEdits(resource: URI, range: editorCommon.IRange, options: modes.FormattingOptions): winjs.TPromise { - return this.formatHTML(resource, range, options); - } - - private formatHTML(resource: URI, range: editorCommon.IRange, options: modes.FormattingOptions): winjs.TPromise { - let model = this.resourceService.get(resource); - let value = range ? model.getValueInRange(range) : model.getValue(); - - let htmlOptions : beautifyHTML.IBeautifyHTMLOptions = { - indent_size: options.insertSpaces ? options.tabSize : 1, - indent_char: options.insertSpaces ? ' ' : '\t', - wrap_line_length: this.getFormatOption('wrapLineLength', 120), - unformatted: this.getTagsFormatOption('unformatted', void 0), - indent_inner_html: this.getFormatOption('indentInnerHtml', false), - preserve_newlines: this.getFormatOption('preserveNewLines', false), - max_preserve_newlines: this.getFormatOption('maxPreserveNewLines', void 0), - indent_handlebars: this.getFormatOption('indentHandlebars', false), - end_with_newline: this.getFormatOption('endWithNewline', false), - extra_liners: this.getTagsFormatOption('extraLiners', void 0), - }; - - let result = beautifyHTML.html_beautify(value, htmlOptions); - - return winjs.TPromise.as([{ - range: range, - text: result - }]); - } - - private getFormatOption(key: string, dflt: any): any { - if (this._formatSettings && this._formatSettings.hasOwnProperty(key)) { - let value = this._formatSettings[key]; - if (value !== null) { - return value; - } - } - return dflt; - } - - private getTagsFormatOption(key: string, dflt: string[]): string[] { - let list = this.getFormatOption(key, null); - if (typeof list === 'string') { - if (list.length > 0) { - return list.split(',').map(t => t.trim().toLowerCase()); - } - return []; - } - return dflt; - } - - _doConfigure(options: IHTMLConfiguration): winjs.TPromise { - this._formatSettings = options && options.format; - if (options && options.suggest) { - this._providerConfiguration = options.suggest; - } - return winjs.TPromise.as(null); - } - - private findMatchingOpenTag(scanner: IHTMLScanner) : string { - let closedTags : { [name:string]: number } = {}; - let tagClosed = false; - while (scanner.scanBack()) { - if (isTag(scanner.getTokenType()) && !tagClosed) { - let tag = scanner.getTokenContent(); - scanner.scanBack(); - if (scanner.getTokenType() === DELIM_END) { - closedTags[tag] = (closedTags[tag] || 0) + 1; - } else if (!isEmptyElement(tag)) { - if (closedTags[tag]) { - closedTags[tag]--; - } else { - return tag; - } - } - } else if (scanner.getTokenType() === DELIM_START) { - tagClosed = scanner.getTokenContent() === '/>'; - } - } - return null; - } - - private collectTagSuggestions(scanner: IHTMLScanner, position: editorCommon.IPosition, suggestions: modes.ISuggestResult): void { - let model = scanner.getModel(); - let currentLine = model.getLineContent(position.lineNumber); - let contentAfter = currentLine.substr(position.column - 1); - let closeTag = isWhiteSpace(contentAfter) || strings.startsWith(contentAfter, '<') ? '>' : ''; - - let collectClosingTagSuggestion = (overwriteBefore: number) => { - let endPosition = scanner.getTokenPosition(); - let matchingTag = this.findMatchingOpenTag(scanner); - if (matchingTag) { - let suggestion : modes.ISuggestion = { - label: '/' + matchingTag, - insertText: '/' + matchingTag + closeTag, - overwriteBefore: overwriteBefore, - type: 'property' - }; - suggestions.suggestions.push(suggestion); - - // use indent from start tag - let startPosition = scanner.getTokenPosition(); - if (endPosition.lineNumber !== startPosition.lineNumber) { - let startIndent = model.getLineContent(startPosition.lineNumber).substring(0, startPosition.column - 1); - let endIndent = model.getLineContent(endPosition.lineNumber).substring(0, endPosition.column - 1); - if (isWhiteSpace(startIndent) && isWhiteSpace(endIndent)) { - suggestion.overwriteBefore = position.column - 1; // replace from start of line - suggestion.insertText = startIndent + ' { - provider.collectTags((tag, label) => { - suggestions.suggestions.push({ - label: '/' + tag, - overwriteBefore: suggestions.currentWord.length + 1, - insertText: '/' + tag + closeTag, - type: 'property', - documentation: label, - filterText: ' { - provider.collectTags((tag, label) => { - suggestions.suggestions.push({ - label: tag, - insertText: tag, - type: 'property', - documentation: label, - overwriteBefore: suggestions.currentWord.length - }); - }); - }); - } - - } - - private collectContentSuggestions(suggestions: modes.ISuggestResult): void { - // disable the simple snippets in favor of the emmet templates - } - - private collectAttributeSuggestions(scanner: IHTMLScanner, suggestions: modes.ISuggestResult): void { - let parentTag: string = null; - do { - if (isTag(scanner.getTokenType())) { - parentTag = scanner.getTokenContent(); - break; - } - if (scanner.getTokenType() === DELIM_START) { - break; - } - } while (scanner.scanBack()); - - this.getTagProviders().forEach((provider) => { - provider.collectAttributes(parentTag,(attribute, type) => { - let codeSnippet = attribute; - if (type !== 'v') { - codeSnippet = codeSnippet + '="{{}}"'; - } - suggestions.suggestions.push({ - label: attribute, - insertText: codeSnippet, - type: type === 'handler' ? 'function' : 'value', - overwriteBefore: suggestions.currentWord.length - }); - }); - }); - } - - private collectAttributeValueSuggestions(scanner: IHTMLScanner, suggestions: modes.ISuggestResult): void { - let needsQuotes = scanner.getTokenType() === DELIM_ASSIGN; - - let attribute: string = null; - let parentTag: string = null; - while (scanner.scanBack()) { - if (scanner.getTokenType() === ATTRIB_NAME) { - attribute = scanner.getTokenContent(); - break; - } - } - while (scanner.scanBack()) { - if (isTag(scanner.getTokenType())) { - parentTag = scanner.getTokenContent(); - break; - } - if (scanner.getTokenType() === DELIM_START) { - return; - } - } - - this.getTagProviders().forEach((provider) => { - provider.collectValues(parentTag, attribute,(value) => { - suggestions.suggestions.push({ - label: value, - insertText: needsQuotes ? '"' + value + '"' : value, - type: 'unit', - overwriteBefore: suggestions.currentWord.length - }); - }); - }); - } - - public provideCompletionItems(resource:URI, position:editorCommon.IPosition):winjs.TPromise { - let model = this.resourceService.get(resource); - let modeIdAtPosition = model.getModeIdAtPosition(position.lineNumber, position.column); - if (modeIdAtPosition === this._modeId) { - return this.suggestHTML(resource, position); - } - } - - private suggestHTML(resource:URI, position:editorCommon.IPosition):winjs.TPromise { - return this.doSuggest(resource, position).then(value => filterSuggestions(value)); - } - - private doSuggest(resource: URI, position: editorCommon.IPosition): winjs.TPromise { - - let model = this.resourceService.get(resource), - currentWord = model.getWordUntilPosition(position).word; - - let suggestions: modes.ISuggestResult = { - currentWord: currentWord, - suggestions: [], - }; - - let scanner = getScanner(model, position); - switch (scanner.getTokenType()) { - case DELIM_START: - case DELIM_END: - if (scanner.isOpenBrace()) { - this.collectTagSuggestions(scanner, position, suggestions); - } else { - this.collectContentSuggestions(suggestions); - } - break; - case ATTRIB_NAME: - this.collectAttributeSuggestions(scanner, suggestions); - break; - case ATTRIB_VALUE: - this.collectAttributeValueSuggestions(scanner, suggestions); - break; - case DELIM_ASSIGN: - if (scanner.isAtTokenEnd()) { - this.collectAttributeValueSuggestions(scanner, suggestions); - } - break; - case '': - if (isWhiteSpace(scanner.getTokenContent()) && scanner.scanBack()) { // go one back - switch (scanner.getTokenType()) { - case ATTRIB_VALUE: - case ATTRIB_NAME: - this.collectAttributeSuggestions(scanner, suggestions); - break; - case DELIM_ASSIGN: - this.collectAttributeValueSuggestions(scanner, suggestions); - break; - case DELIM_START: - case DELIM_END: - if (scanner.isOpenBrace()) { - this.collectTagSuggestions(scanner, position, suggestions); - } else { - this.collectContentSuggestions(suggestions); - } - break; - default: - if (isTag(scanner.getTokenType())) { - this.collectAttributeSuggestions(scanner, suggestions); - } - } - } else { - this.collectContentSuggestions(suggestions); - } - break; - default: - if (isTag(scanner.getTokenType())) { - scanner.scanBack(); // one back to the end/start bracket - this.collectTagSuggestions(scanner, position, suggestions); - } - } - return winjs.TPromise.as(suggestions); - } - - private findMatchingBracket(tagname: string, scanner: IHTMLScanner) : editorCommon.IRange { - if (isEmptyElement(tagname)) { - return null; - } - let tagCount = 0; - scanner.scanBack(); // one back to the end/start bracket - if (scanner.getTokenType() === DELIM_END) { - // find the opening tag - let tagClosed = false; - while (scanner.scanBack()) { - if (isTag(scanner.getTokenType()) && scanner.getTokenContent() === tagname && !tagClosed) { - let range = scanner.getTokenRange(); - scanner.scanBack(); // one back to the end/start bracket - if (scanner.getTokenType() === DELIM_START) { - if (tagCount === 0) { - return range; - } else { - tagCount--; - } - } else { - tagCount++; - } - } else if (scanner.getTokenType() === DELIM_START) { - tagClosed = scanner.getTokenContent() === '/>'; - } - } - } else { - let isTagEnd = false; - while (scanner.scanForward()) { - if (isTag(scanner.getTokenType()) && scanner.getTokenContent() === tagname) { - if (!isTagEnd) { - scanner.scanForward(); - if (scanner.getTokenType() === DELIM_START && scanner.getTokenContent() === '/>') { - if (tagCount <= 0) { - return null; - } - } else { - tagCount++; - } - } else { - tagCount--; - if (tagCount <= 0) { - return scanner.getTokenRange(); - } - } - } else if (scanner.getTokenType() === DELIM_START) { - isTagEnd = false; - } else if (scanner.getTokenType() === DELIM_END) { - isTagEnd = true; - } - } - } - return null; - - } - - public provideDocumentHighlights(resource:URI, position:editorCommon.IPosition, strict:boolean = false): winjs.TPromise { - let model = this.resourceService.get(resource), - wordAtPosition = model.getWordAtPosition(position), - result:modes.DocumentHighlight[] = []; - - - let scanner = getScanner(model, position); - if (isTag(scanner.getTokenType())) { - let tagname = scanner.getTokenContent(); - result.push({ - range: scanner.getTokenRange(), - kind: modes.DocumentHighlightKind.Read - }); - let range = this.findMatchingBracket(tagname, scanner); - if (range) { - result.push({ - range: range, - kind: modes.DocumentHighlightKind.Read - }); - } - } else { - if (wordAtPosition) { - let results = model.findMatches(wordAtPosition.word, false, false, true, true); - for (let i = 0, len = results.length; i < len; i++) { - result.push({ - range: results[i], - kind: modes.DocumentHighlightKind.Read - }); - } - } - } - return winjs.TPromise.as(result); - } - - private static _stripQuotes(url: string): string { - return url - .replace(/^'([^']+)'$/,(substr, match1) => match1) - .replace(/^"([^"]+)"$/,(substr, match1) => match1); - } - - public static _getWorkspaceUrl(modelAbsoluteUri: URI, rootAbsoluteUri: URI, tokenContent: string): string { - tokenContent = HTMLWorker._stripQuotes(tokenContent); - - if (/^\s*javascript\:/i.test(tokenContent) || /^\s*\#/i.test(tokenContent)) { - return null; - } - - if (/^\s*https?:\/\//i.test(tokenContent) || /^\s*file:\/\//i.test(tokenContent)) { - // Absolute link that needs no treatment - return tokenContent.replace(/^\s*/g, ''); - } - - if (/^\s*\/\//i.test(tokenContent)) { - // Absolute link (that does not name the protocol) - let pickedScheme = network.Schemas.http; - if (modelAbsoluteUri.scheme === network.Schemas.https) { - pickedScheme = network.Schemas.https; - } - return pickedScheme + ':' + tokenContent.replace(/^\s*/g, ''); - } - - let modelPath = paths.dirname(modelAbsoluteUri.path); - let alternativeResultPath: string = null; - if (tokenContent.length > 0 && tokenContent.charAt(0) === '/') { - alternativeResultPath = tokenContent; - } else { - alternativeResultPath = paths.join(modelPath, tokenContent); - alternativeResultPath = alternativeResultPath.replace(/^(\/\.\.)+/, ''); - } - let potentialResult = modelAbsoluteUri.with({ path: alternativeResultPath }).toString(); - - let rootAbsoluteUrlStr = (rootAbsoluteUri ? rootAbsoluteUri.toString() : null); - if (rootAbsoluteUrlStr && strings.startsWith(modelAbsoluteUri.toString(), rootAbsoluteUrlStr)) { - // The `rootAbsoluteUrl` is set and matches our current model - // We need to ensure that this `potentialResult` does not escape `rootAbsoluteUrl` - - let commonPrefixLength = strings.commonPrefixLength(rootAbsoluteUrlStr, potentialResult); - if (strings.endsWith(rootAbsoluteUrlStr, '/')) { - commonPrefixLength = potentialResult.lastIndexOf('/', commonPrefixLength) + 1; - } - return rootAbsoluteUrlStr + potentialResult.substr(commonPrefixLength); - } - - return potentialResult; - } - - private createLink(modelAbsoluteUrl: URI, rootAbsoluteUrl: URI, tokenContent: string, lineNumber: number, startColumn: number, endColumn: number): modes.ILink { - let workspaceUrl = HTMLWorker._getWorkspaceUrl(modelAbsoluteUrl, rootAbsoluteUrl, tokenContent); - if (!workspaceUrl) { - return null; - } - // console.info('workspaceUrl: ' + workspaceUrl); - - return { - range: { - startLineNumber: lineNumber, - startColumn: startColumn, - endLineNumber: lineNumber, - endColumn: endColumn - }, - url: workspaceUrl - }; - } - - private _computeHTMLLinks(model: ICompatMirrorModel, modelAbsoluteUrl:URI, workspaceResource:URI): modes.ILink[] { - let lineCount = model.getLineCount(), - newLinks: modes.ILink[] = [], - state: LinkDetectionState = LinkDetectionState.LOOKING_FOR_HREF_OR_SRC, - lineNumber: number, - lineContent: string, - lineContentLength: number, - tokens: LineTokens, - tokenType: string, - tokensLength: number, - i: number, - nextTokenEndIndex: number, - tokenContent: string, - link: modes.ILink; - - let rootAbsoluteUrl: URI = null; - if (workspaceResource) { - // The workspace can be null in the no folder opened case - let strRootAbsoluteUrl = String(workspaceResource); - if (strRootAbsoluteUrl.charAt(strRootAbsoluteUrl.length - 1) === '/') { - rootAbsoluteUrl = URI.parse(strRootAbsoluteUrl); - } else { - rootAbsoluteUrl = URI.parse(strRootAbsoluteUrl + '/'); - } - } - - for (lineNumber = 1; lineNumber <= lineCount; lineNumber++) { - lineContent = model.getLineContent(lineNumber); - lineContentLength = lineContent.length; - tokens = model.getLineTokens(lineNumber); - - for (i = 0, tokensLength = tokens.getTokenCount(); i < tokensLength; i++) { - - tokenType = tokens.getTokenType(i); - - switch (tokenType) { - case DELIM_ASSIGN: - case '': - break; - - case ATTRIB_NAME: - nextTokenEndIndex = tokens.getTokenEndOffset(i); - tokenContent = lineContent.substring(tokens.getTokenStartOffset(i), nextTokenEndIndex).toLowerCase(); - - if (tokenContent === 'src' || tokenContent === 'href') { - state = LinkDetectionState.AFTER_HREF_OR_SRC; - } else { - state = LinkDetectionState.LOOKING_FOR_HREF_OR_SRC; - } - break; - - case ATTRIB_VALUE: - if (state === LinkDetectionState.AFTER_HREF_OR_SRC) { - nextTokenEndIndex = tokens.getTokenEndOffset(i); - tokenContent = lineContent.substring(tokens.getTokenStartOffset(i), nextTokenEndIndex); - - link = this.createLink(modelAbsoluteUrl, rootAbsoluteUrl, tokenContent, lineNumber, tokens.getTokenStartOffset(i) + 2, nextTokenEndIndex); - if (link) { - newLinks.push(link); - } - - state = LinkDetectionState.LOOKING_FOR_HREF_OR_SRC; - } - - default: - if (isTag(tokenType)) { - state = LinkDetectionState.LOOKING_FOR_HREF_OR_SRC; - } else if (state === LinkDetectionState.AFTER_HREF_OR_SRC) { - state = LinkDetectionState.LOOKING_FOR_HREF_OR_SRC; - } - } - } - } - - return newLinks; - } - - public provideLinks(resource: URI, workspaceResource:URI): winjs.TPromise { - let model = this.resourceService.get(resource); - return winjs.TPromise.as(this._computeHTMLLinks(model, resource, workspaceResource)); - } -} - -function isWhiteSpace(s:string) : boolean { - return /^\s*$/.test(s); -} diff --git a/src/vs/languages/html/test/common/html-worker.test.ts b/src/vs/languages/html/test/common/html-worker.test.ts deleted file mode 100644 index 51b6039de8d..00000000000 --- a/src/vs/languages/html/test/common/html-worker.test.ts +++ /dev/null @@ -1,445 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import assert = require('assert'); -import mm = require('vs/editor/common/model/compatMirrorModel'); -import htmlWorker = require('vs/languages/html/common/htmlWorker'); -import URI from 'vs/base/common/uri'; -import ResourceService = require('vs/editor/common/services/resourceServiceImpl'); -import Modes = require('vs/editor/common/modes'); -import WinJS = require('vs/base/common/winjs.base'); -import {HTMLMode} from 'vs/languages/html/common/html'; -import {MockModeService} from 'vs/editor/test/common/mocks/mockModeService'; -import {TextModel} from 'vs/editor/common/model/textModel'; - -function createTestMirrorModelFromString(value:string, mode:Modes.IMode, associatedResource:URI): mm.CompatMirrorModel { - return new mm.CompatMirrorModel(0, TextModel.toRawText(value, TextModel.DEFAULT_CREATION_OPTIONS), mode.getId(), associatedResource); -} - -suite('HTML - worker', () => { - - var mode: Modes.IMode; - - (function() { - mode = new HTMLMode( - { id: 'html' }, - null, - new MockModeService(), - null, - null, - null - ); - })(); - - var mockHtmlWorkerEnv = function (url: URI, content: string): { worker: htmlWorker.HTMLWorker; model: mm.CompatMirrorModel; } { - var resourceService = new ResourceService.ResourceService(); - - var model = createTestMirrorModelFromString(content, mode, url); - resourceService.insert(url, model); - - var worker = new htmlWorker.HTMLWorker(mode.getId(), resourceService); - - return { worker: worker, model: model }; - }; - - var testSuggestionsFor = function(value:string):WinJS.TPromise { - - var idx = value.indexOf('|'); - var content = value.substr(0, idx) + value.substr(idx + 1); - - var url = URI.parse('test://1'); - var env = mockHtmlWorkerEnv(url, content); - - var position = env.model.getPositionAt(idx); - return env.worker.provideCompletionItems(url, position); - }; - - var assertSuggestion = function(completion: Modes.ISuggestResult, label: string, type?: string, codeSnippet?: string) { - var proposalsFound = completion.suggestions.filter(function(suggestion: Modes.ISuggestion) { - return suggestion.label === label && (!type || suggestion.type === type) && (!codeSnippet || suggestion.insertText === codeSnippet); - }); - if (proposalsFound.length !== 1) { - assert.fail('Suggestion not found: ' + label + ', has ' + completion.suggestions.map(s => s.label).join(', ')); - } - }; - - test('Intellisense', function(testDone): any { - WinJS.Promise.join([ - testSuggestionsFor('<|').then((completion) => { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'iframe'); - assertSuggestion(completion, 'h1'); - assertSuggestion(completion, 'div'); - }), - - testSuggestionsFor('< |').then((completion) => { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'iframe'); - assertSuggestion(completion, 'h1'); - assertSuggestion(completion, 'div'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 'h'); - assertSuggestion(completion, 'html'); - assertSuggestion(completion, 'h1'); - assertSuggestion(completion, 'header'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 'input'); - assertSuggestion(completion, 'input'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'type'); - assertSuggestion(completion, 'style'); - assertSuggestion(completion, 'onmousemove'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 't'); - assertSuggestion(completion, 'type'); - assertSuggestion(completion, 'tabindex'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'style'); - assertSuggestion(completion, 'type'); - assertSuggestion(completion, 'size'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 's'); - assertSuggestion(completion, 'style'); - assertSuggestion(completion, 'src'); - assertSuggestion(completion, 'size'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 'di'); - assertSuggestion(completion, 'disabled', null, 'disabled'); - assertSuggestion(completion, 'dir', null, 'dir="{{}}"'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'dir', null, 'dir="{{}}"'); - assertSuggestion(completion, 'style'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'text', null, '"text"'); - assertSuggestion(completion, 'checkbox', null, '"checkbox"'); - }), - - testSuggestionsFor(' { - assert.equal(completion.currentWord, 'color'); - assertSuggestion(completion, 'color', null, 'color'); - }), - testSuggestionsFor(' { - assert.equal(completion.currentWord, 'color'); - assertSuggestion(completion, 'color', null, 'color'); - }), - testSuggestionsFor('
').then((completion) => { - assert.equal(completion.currentWord, ''); - assertSuggestion(completion, 'ltr', null, '"ltr"'); - assertSuggestion(completion, 'rtl', null, '"rtl"'); - }), - testSuggestionsFor('