Merge from vscode b12f623603e2fc1c5b3037115fa37c1a6acc4165 (#6760)
@@ -53,6 +53,7 @@ const buildfile = require('../src/buildfile');
|
|||||||
const vscodeWebEntryPoints = [
|
const vscodeWebEntryPoints = [
|
||||||
buildfile.workbenchWeb,
|
buildfile.workbenchWeb,
|
||||||
buildfile.serviceWorker,
|
buildfile.serviceWorker,
|
||||||
|
buildfile.workerExtensionHost,
|
||||||
buildfile.keyboardMaps,
|
buildfile.keyboardMaps,
|
||||||
buildfile.base
|
buildfile.base
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ Compression=lzma
|
|||||||
SolidCompression=yes
|
SolidCompression=yes
|
||||||
AppMutex={code:GetAppMutex}
|
AppMutex={code:GetAppMutex}
|
||||||
SetupMutex={#AppMutex}setup
|
SetupMutex={#AppMutex}setup
|
||||||
WizardImageFile={#RepoDir}\resources\win32\inno-big.bmp
|
WizardImageFile="{#RepoDir}\resources\win32\inno-big-100.bmp,{#RepoDir}\resources\win32\inno-big-125.bmp,{#RepoDir}\resources\win32\inno-big-150.bmp,{#RepoDir}\resources\win32\inno-big-175.bmp,{#RepoDir}\resources\win32\inno-big-200.bmp,{#RepoDir}\resources\win32\inno-big-225.bmp,{#RepoDir}\resources\win32\inno-big-250.bmp"
|
||||||
WizardSmallImageFile={#RepoDir}\resources\win32\inno-small.bmp
|
WizardSmallImageFile="{#RepoDir}\resources\win32\inno-small-100.bmp,{#RepoDir}\resources\win32\inno-small-125.bmp,{#RepoDir}\resources\win32\inno-small-150.bmp,{#RepoDir}\resources\win32\inno-small-175.bmp,{#RepoDir}\resources\win32\inno-small-200.bmp,{#RepoDir}\resources\win32\inno-small-225.bmp,{#RepoDir}\resources\win32\inno-small-250.bmp"
|
||||||
SetupIconFile={#RepoDir}\resources\win32\code.ico
|
SetupIconFile={#RepoDir}\resources\win32\code.ico
|
||||||
UninstallDisplayIcon={app}\{#ExeBasename}.exe
|
UninstallDisplayIcon={app}\{#ExeBasename}.exe
|
||||||
ChangesEnvironment=true
|
ChangesEnvironment=true
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||||
"Once accepted there, we are happy to receive an update request."
|
"Once accepted there, we are happy to receive an update request."
|
||||||
],
|
],
|
||||||
"version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/a595d8ba2ae9ce8864435d33db2afa0fe68b1487",
|
"version": "https://github.com/microsoft/vscode-markdown-tm-grammar/commit/05ccfa3db6edbd357390431f9e316adb38ba41d8",
|
||||||
"name": "Markdown",
|
"name": "Markdown",
|
||||||
"scopeName": "text.html.markdown",
|
"scopeName": "text.html.markdown",
|
||||||
"patterns": [
|
"patterns": [
|
||||||
@@ -716,7 +716,7 @@
|
|||||||
{
|
{
|
||||||
"begin": "(^|\\G)(\\s*)(.*)",
|
"begin": "(^|\\G)(\\s*)(.*)",
|
||||||
"while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)",
|
"while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)",
|
||||||
"contentName": "meta.embedded.block.cpp source.cpp",
|
"contentName": "meta.embedded.block.cpp",
|
||||||
"patterns": [
|
"patterns": [
|
||||||
{
|
{
|
||||||
"include": "source.cpp"
|
"include": "source.cpp"
|
||||||
@@ -1987,8 +1987,29 @@
|
|||||||
"name": "comment.block.html"
|
"name": "comment.block.html"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"begin": "(^|\\G)\\s*(?=<(script|style|pre)(\\s|$|>)(?!.*?</(script|style|pre)>))",
|
"begin": "(?i)(^|\\G)\\s*(?=<(script|style|pre)(\\s|$|>)(?!.*?</(script|style|pre)>))",
|
||||||
"end": "(?=.*</(script|style|pre)>)",
|
"end": "(?i)(.*)((</)(script|style|pre)(>))",
|
||||||
|
"endCaptures": {
|
||||||
|
"1": {
|
||||||
|
"patterns": [
|
||||||
|
{
|
||||||
|
"include": "text.html.basic"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"name": "meta.tag.structure.$4.end.html"
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"name": "punctuation.definition.tag.begin.html"
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"name": "entity.name.tag.html"
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"name": "punctuation.definition.tag.end.html"
|
||||||
|
}
|
||||||
|
},
|
||||||
"patterns": [
|
"patterns": [
|
||||||
{
|
{
|
||||||
"begin": "(\\s*|$)",
|
"begin": "(\\s*|$)",
|
||||||
@@ -1997,12 +2018,12 @@
|
|||||||
"include": "text.html.basic"
|
"include": "text.html.basic"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"while": "^(?!.*</(script|style|pre)>)"
|
"while": "(?i)^(?!.*</(script|style|pre)>)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"begin": "(^|\\G)\\s*(?=</?(address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h1|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul)(\\s|$|/?>))",
|
"begin": "(?i)(^|\\G)\\s*(?=</?(address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h1|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul)(\\s|$|/?>))",
|
||||||
"patterns": [
|
"patterns": [
|
||||||
{
|
{
|
||||||
"include": "text.html.basic"
|
"include": "text.html.basic"
|
||||||
@@ -2275,7 +2296,7 @@
|
|||||||
},
|
},
|
||||||
"bracket": {
|
"bracket": {
|
||||||
"comment": "Markdown will convert this for us. We match it so that the HTML grammar will not mark it up as invalid.",
|
"comment": "Markdown will convert this for us. We match it so that the HTML grammar will not mark it up as invalid.",
|
||||||
"match": "<(?![a-z/?\\$!])",
|
"match": "<(?![a-zA-Z/?\\$!])",
|
||||||
"name": "meta.other.valid-bracket.markdown"
|
"name": "meta.other.valid-bracket.markdown"
|
||||||
},
|
},
|
||||||
"escape": {
|
"escape": {
|
||||||
|
|||||||
@@ -111,7 +111,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "</",
|
"c": "</",
|
||||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.inline.code.end.html punctuation.definition.tag.begin.html",
|
"t": "text.html.markdown meta.tag.inline.code.end.html punctuation.definition.tag.begin.html",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": "punctuation.definition.tag: #808080",
|
"dark_plus": "punctuation.definition.tag: #808080",
|
||||||
"light_plus": "punctuation.definition.tag: #800000",
|
"light_plus": "punctuation.definition.tag: #800000",
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "code",
|
"c": "code",
|
||||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.inline.code.end.html entity.name.tag.html",
|
"t": "text.html.markdown meta.tag.inline.code.end.html entity.name.tag.html",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": "entity.name.tag: #569CD6",
|
"dark_plus": "entity.name.tag: #569CD6",
|
||||||
"light_plus": "entity.name.tag: #800000",
|
"light_plus": "entity.name.tag: #800000",
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": ">",
|
"c": ">",
|
||||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.inline.code.end.html punctuation.definition.tag.end.html",
|
"t": "text.html.markdown meta.tag.inline.code.end.html punctuation.definition.tag.end.html",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": "punctuation.definition.tag: #808080",
|
"dark_plus": "punctuation.definition.tag: #808080",
|
||||||
"light_plus": "punctuation.definition.tag: #800000",
|
"light_plus": "punctuation.definition.tag: #800000",
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "</",
|
"c": "</",
|
||||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.structure.pre.end.html punctuation.definition.tag.begin.html",
|
"t": "text.html.markdown meta.tag.structure.pre.end.html punctuation.definition.tag.begin.html",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": "punctuation.definition.tag: #808080",
|
"dark_plus": "punctuation.definition.tag: #808080",
|
||||||
"light_plus": "punctuation.definition.tag: #800000",
|
"light_plus": "punctuation.definition.tag: #800000",
|
||||||
@@ -155,7 +155,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "pre",
|
"c": "pre",
|
||||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.structure.pre.end.html entity.name.tag.html",
|
"t": "text.html.markdown meta.tag.structure.pre.end.html entity.name.tag.html",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": "entity.name.tag: #569CD6",
|
"dark_plus": "entity.name.tag: #569CD6",
|
||||||
"light_plus": "entity.name.tag: #800000",
|
"light_plus": "entity.name.tag: #800000",
|
||||||
@@ -166,7 +166,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": ">",
|
"c": ">",
|
||||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.structure.pre.end.html punctuation.definition.tag.end.html",
|
"t": "text.html.markdown meta.tag.structure.pre.end.html punctuation.definition.tag.end.html",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": "punctuation.definition.tag: #808080",
|
"dark_plus": "punctuation.definition.tag: #808080",
|
||||||
"light_plus": "punctuation.definition.tag: #800000",
|
"light_plus": "punctuation.definition.tag: #800000",
|
||||||
@@ -254,7 +254,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "a",
|
"c": "a",
|
||||||
"t": "text.html.markdown meta.paragraph.markdown",
|
"t": "text.html.markdown",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": "default: #D4D4D4",
|
"dark_plus": "default: #D4D4D4",
|
||||||
"light_plus": "default: #000000",
|
"light_plus": "default: #000000",
|
||||||
@@ -265,7 +265,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "</",
|
"c": "</",
|
||||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.structure.pre.end.html punctuation.definition.tag.begin.html",
|
"t": "text.html.markdown meta.tag.structure.pre.end.html punctuation.definition.tag.begin.html",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": "punctuation.definition.tag: #808080",
|
"dark_plus": "punctuation.definition.tag: #808080",
|
||||||
"light_plus": "punctuation.definition.tag: #800000",
|
"light_plus": "punctuation.definition.tag: #800000",
|
||||||
@@ -276,7 +276,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": "pre",
|
"c": "pre",
|
||||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.structure.pre.end.html entity.name.tag.html",
|
"t": "text.html.markdown meta.tag.structure.pre.end.html entity.name.tag.html",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": "entity.name.tag: #569CD6",
|
"dark_plus": "entity.name.tag: #569CD6",
|
||||||
"light_plus": "entity.name.tag: #800000",
|
"light_plus": "entity.name.tag: #800000",
|
||||||
@@ -287,7 +287,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"c": ">",
|
"c": ">",
|
||||||
"t": "text.html.markdown meta.paragraph.markdown meta.tag.structure.pre.end.html punctuation.definition.tag.end.html",
|
"t": "text.html.markdown meta.tag.structure.pre.end.html punctuation.definition.tag.end.html",
|
||||||
"r": {
|
"r": {
|
||||||
"dark_plus": "punctuation.definition.tag: #808080",
|
"dark_plus": "punctuation.definition.tag: #808080",
|
||||||
"light_plus": "punctuation.definition.tag: #800000",
|
"light_plus": "punctuation.definition.tag: #800000",
|
||||||
|
|||||||
@@ -131,7 +131,7 @@
|
|||||||
"gulp-shell": "^0.6.5",
|
"gulp-shell": "^0.6.5",
|
||||||
"gulp-tsb": "2.0.7",
|
"gulp-tsb": "2.0.7",
|
||||||
"gulp-tslint": "^8.1.3",
|
"gulp-tslint": "^8.1.3",
|
||||||
"gulp-uglify": "^3.0.0",
|
"gulp-uglify": "^3.0.2",
|
||||||
"gulp-untar": "^0.0.7",
|
"gulp-untar": "^0.0.7",
|
||||||
"gulp-vinyl-zip": "^2.1.2",
|
"gulp-vinyl-zip": "^2.1.2",
|
||||||
"http-server": "^0.11.1",
|
"http-server": "^0.11.1",
|
||||||
@@ -168,7 +168,7 @@
|
|||||||
"typemoq": "^0.3.2",
|
"typemoq": "^0.3.2",
|
||||||
"typescript": "3.5.2",
|
"typescript": "3.5.2",
|
||||||
"typescript-formatter": "7.1.0",
|
"typescript-formatter": "7.1.0",
|
||||||
"uglify-es": "^3.0.18",
|
"uglify-es": "^3.3.9",
|
||||||
"vinyl": "^2.0.0",
|
"vinyl": "^2.0.0",
|
||||||
"vinyl-fs": "^3.0.0",
|
"vinyl-fs": "^3.0.0",
|
||||||
"vsce": "1.48.0",
|
"vsce": "1.48.0",
|
||||||
|
|||||||
|
After Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 201 KiB |
|
After Width: | Height: | Size: 332 KiB |
|
After Width: | Height: | Size: 445 KiB |
|
After Width: | Height: | Size: 580 KiB |
|
After Width: | Height: | Size: 730 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 12 KiB |
@@ -3,7 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
function entrypoint (name) {
|
function entrypoint(name) {
|
||||||
return [{ name: name, include: [], exclude: ['vs/css', 'vs/nls'] }];
|
return [{ name: name, include: [], exclude: ['vs/css', 'vs/nls'] }];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,6 +23,14 @@ exports.serviceWorker = [{
|
|||||||
dest: 'vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.js'
|
dest: 'vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.js'
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
exports.workerExtensionHost = [{
|
||||||
|
name: 'vs/workbench/services/extensions/worker/extensionHostWorker',
|
||||||
|
// include: [],
|
||||||
|
prepend: ['vs/loader.js'],
|
||||||
|
append: ['vs/workbench/services/extensions/worker/extensionHostWorkerMain'],
|
||||||
|
dest: 'vs/workbench/services/extensions/worker/extensionHostWorkerMain.js'
|
||||||
|
}];
|
||||||
|
|
||||||
exports.workbench = require('./vs/workbench/buildfile').collectModules(['vs/workbench/workbench.desktop.main']);
|
exports.workbench = require('./vs/workbench/buildfile').collectModules(['vs/workbench/workbench.desktop.main']);
|
||||||
exports.workbenchWeb = entrypoint('vs/workbench/workbench.web.api');
|
exports.workbenchWeb = entrypoint('vs/workbench/workbench.web.api');
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import { IMessage, MessageType, defaultOpts } from 'vs/base/browser/ui/inputbox/
|
|||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
import { IContextViewProvider, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
import { IContextViewProvider, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||||
import { RenderOptions, renderFormattedText, renderText } from 'vs/base/browser/htmlContentRenderer';
|
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
|
import { renderFormattedText, renderText, FormattedTextRenderOptions } from 'vs/base/browser/formattedTextRenderer';
|
||||||
|
|
||||||
const $ = dom.$;
|
const $ = dom.$;
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ export class ListBox extends SelectBox {
|
|||||||
div = dom.append(container, $('.monaco-inputbox-container'));
|
div = dom.append(container, $('.monaco-inputbox-container'));
|
||||||
layout();
|
layout();
|
||||||
|
|
||||||
const renderOptions: RenderOptions = {
|
const renderOptions: FormattedTextRenderOptions = {
|
||||||
inline: true,
|
inline: true,
|
||||||
className: 'monaco-inputbox-message'
|
className: 'monaco-inputbox-message'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import { SelectBox as vsSelectBox, ISelectBoxStyles as vsISelectBoxStyles, ISele
|
|||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
import { IContextViewProvider, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
import { IContextViewProvider, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { RenderOptions, renderFormattedText, renderText } from 'vs/base/browser/htmlContentRenderer';
|
|
||||||
import { IMessage, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
import { IMessage, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
|
import { renderFormattedText, renderText, FormattedTextRenderOptions } from 'vs/base/browser/formattedTextRenderer';
|
||||||
|
|
||||||
const $ = dom.$;
|
const $ = dom.$;
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ export class SelectBox extends vsSelectBox {
|
|||||||
div = dom.append(container, $('.monaco-inputbox-container'));
|
div = dom.append(container, $('.monaco-inputbox-container'));
|
||||||
layout();
|
layout();
|
||||||
|
|
||||||
const renderOptions: RenderOptions = {
|
const renderOptions: FormattedTextRenderOptions = {
|
||||||
inline: true,
|
inline: true,
|
||||||
className: 'monaco-inputbox-message'
|
className: 'monaco-inputbox-message'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import { timeout } from 'vs/base/common/async';
|
|||||||
import { editorFindMatchHighlight, editorFindMatchHighlightBorder, textLinkForeground, textCodeBlockBackground, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
import { editorFindMatchHighlight, editorFindMatchHighlightBorder, textLinkForeground, textCodeBlockBackground, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { isString } from 'vs/base/common/types';
|
import { isString } from 'vs/base/common/types';
|
||||||
import { renderMarkdown, RenderOptions } from 'vs/base/browser/htmlContentRenderer';
|
import { renderMarkdown, MarkdownRenderOptions } from 'vs/base/browser/markdownRenderer';
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
import { IMarkdownRenderResult } from 'vs/editor/contrib/markdown/markdownRenderer';
|
import { IMarkdownRenderResult } from 'vs/editor/contrib/markdown/markdownRenderer';
|
||||||
@@ -934,7 +934,7 @@ class MarkdownRenderer {
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private getOptions(disposeables: DisposableStore): RenderOptions {
|
private getOptions(disposeables: DisposableStore): MarkdownRenderOptions {
|
||||||
return {
|
return {
|
||||||
actionHandler: {
|
actionHandler: {
|
||||||
callback: (content) => {
|
callback: (content) => {
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import * as fs from 'fs';
|
|||||||
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
import { RenderOptions } from 'vs/base/browser/htmlContentRenderer';
|
|
||||||
import { IMarkdownString, removeMarkdownEscapes } from 'vs/base/common/htmlContent';
|
import { IMarkdownString, removeMarkdownEscapes } from 'vs/base/common/htmlContent';
|
||||||
import { IMarkdownRenderResult } from 'vs/editor/contrib/markdown/markdownRenderer';
|
import { IMarkdownRenderResult } from 'vs/editor/contrib/markdown/markdownRenderer';
|
||||||
import * as marked from 'vs/base/common/marked/marked';
|
import * as marked from 'vs/base/common/marked/marked';
|
||||||
import { defaultGenerator } from 'vs/base/common/idGenerator';
|
import { defaultGenerator } from 'vs/base/common/idGenerator';
|
||||||
import { revive } from 'vs/base/common/marshalling';
|
import { revive } from 'vs/base/common/marshalling';
|
||||||
|
import { MarkdownRenderOptions } from 'vs/base/browser/markdownRenderer';
|
||||||
|
|
||||||
// Based off of HtmlContentRenderer
|
// Based off of HtmlContentRenderer
|
||||||
export class NotebookMarkdownRenderer {
|
export class NotebookMarkdownRenderer {
|
||||||
@@ -30,7 +30,7 @@ export class NotebookMarkdownRenderer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
createElement(options: RenderOptions): HTMLElement {
|
createElement(options: MarkdownRenderOptions): HTMLElement {
|
||||||
const tagName = options.inline ? 'span' : 'div';
|
const tagName = options.inline ? 'span' : 'div';
|
||||||
const element = document.createElement(tagName);
|
const element = document.createElement(tagName);
|
||||||
if (options.className) {
|
if (options.className) {
|
||||||
@@ -52,7 +52,7 @@ export class NotebookMarkdownRenderer {
|
|||||||
* respects the trusted state of a notebook, and allows command links to
|
* respects the trusted state of a notebook, and allows command links to
|
||||||
* be clickable.
|
* be clickable.
|
||||||
*/
|
*/
|
||||||
renderMarkdown(markdown: IMarkdownString, options: RenderOptions = {}): HTMLElement {
|
renderMarkdown(markdown: IMarkdownString, options: MarkdownRenderOptions = {}): HTMLElement {
|
||||||
const element = this.createElement(options);
|
const element = this.createElement(options);
|
||||||
|
|
||||||
// signal to code-block render that the element has been created
|
// signal to code-block render that the element has been created
|
||||||
|
|||||||
@@ -0,0 +1,220 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
|
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||||
|
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
|
export interface IContentActionHandler {
|
||||||
|
callback: (content: string, event?: IMouseEvent) => void;
|
||||||
|
readonly disposeables: DisposableStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FormattedTextRenderOptions {
|
||||||
|
readonly className?: string;
|
||||||
|
readonly inline?: boolean;
|
||||||
|
readonly actionHandler?: IContentActionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderText(text: string, options: FormattedTextRenderOptions = {}): HTMLElement {
|
||||||
|
const element = createElement(options);
|
||||||
|
element.textContent = text;
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function renderFormattedText(formattedText: string, options: FormattedTextRenderOptions = {}): HTMLElement {
|
||||||
|
const element = createElement(options);
|
||||||
|
_renderFormattedText(element, parseFormattedText(formattedText), options.actionHandler);
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createElement(options: FormattedTextRenderOptions): HTMLElement {
|
||||||
|
const tagName = options.inline ? 'span' : 'div';
|
||||||
|
const element = document.createElement(tagName);
|
||||||
|
if (options.className) {
|
||||||
|
element.className = options.className;
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
class StringStream {
|
||||||
|
private source: string;
|
||||||
|
private index: number;
|
||||||
|
|
||||||
|
constructor(source: string) {
|
||||||
|
this.source = source;
|
||||||
|
this.index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public eos(): boolean {
|
||||||
|
return this.index >= this.source.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public next(): string {
|
||||||
|
const next = this.peek();
|
||||||
|
this.advance();
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public peek(): string {
|
||||||
|
return this.source[this.index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public advance(): void {
|
||||||
|
this.index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum FormatType {
|
||||||
|
Invalid,
|
||||||
|
Root,
|
||||||
|
Text,
|
||||||
|
Bold,
|
||||||
|
Italics,
|
||||||
|
Action,
|
||||||
|
ActionClose,
|
||||||
|
NewLine
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IFormatParseTree {
|
||||||
|
type: FormatType;
|
||||||
|
content?: string;
|
||||||
|
index?: number;
|
||||||
|
children?: IFormatParseTree[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function _renderFormattedText(element: Node, treeNode: IFormatParseTree, actionHandler?: IContentActionHandler) {
|
||||||
|
let child: Node | undefined;
|
||||||
|
|
||||||
|
if (treeNode.type === FormatType.Text) {
|
||||||
|
child = document.createTextNode(treeNode.content || '');
|
||||||
|
} else if (treeNode.type === FormatType.Bold) {
|
||||||
|
child = document.createElement('b');
|
||||||
|
} else if (treeNode.type === FormatType.Italics) {
|
||||||
|
child = document.createElement('i');
|
||||||
|
} else if (treeNode.type === FormatType.Action && actionHandler) {
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = '#';
|
||||||
|
actionHandler.disposeables.add(DOM.addStandardDisposableListener(a, 'click', (event) => {
|
||||||
|
actionHandler.callback(String(treeNode.index), event);
|
||||||
|
}));
|
||||||
|
|
||||||
|
child = a;
|
||||||
|
} else if (treeNode.type === FormatType.NewLine) {
|
||||||
|
child = document.createElement('br');
|
||||||
|
} else if (treeNode.type === FormatType.Root) {
|
||||||
|
child = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child && element !== child) {
|
||||||
|
element.appendChild(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child && Array.isArray(treeNode.children)) {
|
||||||
|
treeNode.children.forEach((nodeChild) => {
|
||||||
|
_renderFormattedText(child!, nodeChild, actionHandler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseFormattedText(content: string): IFormatParseTree {
|
||||||
|
|
||||||
|
const root: IFormatParseTree = {
|
||||||
|
type: FormatType.Root,
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
|
||||||
|
let actionViewItemIndex = 0;
|
||||||
|
let current = root;
|
||||||
|
const stack: IFormatParseTree[] = [];
|
||||||
|
const stream = new StringStream(content);
|
||||||
|
|
||||||
|
while (!stream.eos()) {
|
||||||
|
let next = stream.next();
|
||||||
|
|
||||||
|
const isEscapedFormatType = (next === '\\' && formatTagType(stream.peek()) !== FormatType.Invalid);
|
||||||
|
if (isEscapedFormatType) {
|
||||||
|
next = stream.next(); // unread the backslash if it escapes a format tag type
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEscapedFormatType && isFormatTag(next) && next === stream.peek()) {
|
||||||
|
stream.advance();
|
||||||
|
|
||||||
|
if (current.type === FormatType.Text) {
|
||||||
|
current = stack.pop()!;
|
||||||
|
}
|
||||||
|
|
||||||
|
const type = formatTagType(next);
|
||||||
|
if (current.type === type || (current.type === FormatType.Action && type === FormatType.ActionClose)) {
|
||||||
|
current = stack.pop()!;
|
||||||
|
} else {
|
||||||
|
const newCurrent: IFormatParseTree = {
|
||||||
|
type: type,
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type === FormatType.Action) {
|
||||||
|
newCurrent.index = actionViewItemIndex;
|
||||||
|
actionViewItemIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
current.children!.push(newCurrent);
|
||||||
|
stack.push(current);
|
||||||
|
current = newCurrent;
|
||||||
|
}
|
||||||
|
} else if (next === '\n') {
|
||||||
|
if (current.type === FormatType.Text) {
|
||||||
|
current = stack.pop()!;
|
||||||
|
}
|
||||||
|
|
||||||
|
current.children!.push({
|
||||||
|
type: FormatType.NewLine
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (current.type !== FormatType.Text) {
|
||||||
|
const textCurrent: IFormatParseTree = {
|
||||||
|
type: FormatType.Text,
|
||||||
|
content: next
|
||||||
|
};
|
||||||
|
current.children!.push(textCurrent);
|
||||||
|
stack.push(current);
|
||||||
|
current = textCurrent;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
current.content += next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current.type === FormatType.Text) {
|
||||||
|
current = stack.pop()!;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack.length) {
|
||||||
|
// incorrectly formatted string literal
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFormatTag(char: string): boolean {
|
||||||
|
return formatTagType(char) !== FormatType.Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatTagType(char: string): FormatType {
|
||||||
|
switch (char) {
|
||||||
|
case '*':
|
||||||
|
return FormatType.Bold;
|
||||||
|
case '_':
|
||||||
|
return FormatType.Italics;
|
||||||
|
case '[':
|
||||||
|
return FormatType.Action;
|
||||||
|
case ']':
|
||||||
|
return FormatType.ActionClose;
|
||||||
|
default:
|
||||||
|
return FormatType.Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,55 +4,25 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as DOM from 'vs/base/browser/dom';
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
import { defaultGenerator } from 'vs/base/common/idGenerator';
|
import { createElement, FormattedTextRenderOptions } from 'vs/base/browser/formattedTextRenderer';
|
||||||
import { escape } from 'vs/base/common/strings';
|
|
||||||
import { removeMarkdownEscapes, IMarkdownString, parseHrefAndDimensions } from 'vs/base/common/htmlContent';
|
|
||||||
import * as marked from 'vs/base/common/marked/marked';
|
|
||||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
|
||||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { IMarkdownString, parseHrefAndDimensions, removeMarkdownEscapes } from 'vs/base/common/htmlContent';
|
||||||
|
import { defaultGenerator } from 'vs/base/common/idGenerator';
|
||||||
|
import * as marked from 'vs/base/common/marked/marked';
|
||||||
import { parse } from 'vs/base/common/marshalling';
|
import { parse } from 'vs/base/common/marshalling';
|
||||||
import { cloneAndChange } from 'vs/base/common/objects';
|
import { cloneAndChange } from 'vs/base/common/objects';
|
||||||
|
import { escape } from 'vs/base/common/strings';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
export interface IContentActionHandler {
|
export interface MarkdownRenderOptions extends FormattedTextRenderOptions {
|
||||||
callback: (content: string, event?: IMouseEvent) => void;
|
|
||||||
readonly disposeables: DisposableStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RenderOptions {
|
|
||||||
className?: string;
|
|
||||||
inline?: boolean;
|
|
||||||
actionHandler?: IContentActionHandler;
|
|
||||||
codeBlockRenderer?: (modeId: string, value: string) => Promise<string>;
|
codeBlockRenderer?: (modeId: string, value: string) => Promise<string>;
|
||||||
codeBlockRenderCallback?: () => void;
|
codeBlockRenderCallback?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createElement(options: RenderOptions): HTMLElement {
|
|
||||||
const tagName = options.inline ? 'span' : 'div';
|
|
||||||
const element = document.createElement(tagName);
|
|
||||||
if (options.className) {
|
|
||||||
element.className = options.className;
|
|
||||||
}
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function renderText(text: string, options: RenderOptions = {}): HTMLElement {
|
|
||||||
const element = createElement(options);
|
|
||||||
element.textContent = text;
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function renderFormattedText(formattedText: string, options: RenderOptions = {}): HTMLElement {
|
|
||||||
const element = createElement(options);
|
|
||||||
_renderFormattedText(element, parseFormattedText(formattedText), options.actionHandler);
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create html nodes for the given content element.
|
* Create html nodes for the given content element.
|
||||||
*/
|
*/
|
||||||
export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions = {}): HTMLElement {
|
export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRenderOptions = {}): HTMLElement {
|
||||||
const element = createElement(options);
|
const element = createElement(options);
|
||||||
|
|
||||||
const _uriMassage = function (part: string): string {
|
const _uriMassage = function (part: string): string {
|
||||||
@@ -219,190 +189,3 @@ export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions
|
|||||||
|
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- formatted string parsing
|
|
||||||
|
|
||||||
class StringStream {
|
|
||||||
private source: string;
|
|
||||||
private index: number;
|
|
||||||
|
|
||||||
constructor(source: string) {
|
|
||||||
this.source = source;
|
|
||||||
this.index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public eos(): boolean {
|
|
||||||
return this.index >= this.source.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public next(): string {
|
|
||||||
const next = this.peek();
|
|
||||||
this.advance();
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
public peek(): string {
|
|
||||||
return this.source[this.index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public advance(): void {
|
|
||||||
this.index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enum FormatType {
|
|
||||||
Invalid,
|
|
||||||
Root,
|
|
||||||
Text,
|
|
||||||
Bold,
|
|
||||||
Italics,
|
|
||||||
Action,
|
|
||||||
ActionClose,
|
|
||||||
NewLine
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IFormatParseTree {
|
|
||||||
type: FormatType;
|
|
||||||
content?: string;
|
|
||||||
index?: number;
|
|
||||||
children?: IFormatParseTree[];
|
|
||||||
}
|
|
||||||
|
|
||||||
function _renderFormattedText(element: Node, treeNode: IFormatParseTree, actionHandler?: IContentActionHandler) {
|
|
||||||
let child: Node | undefined;
|
|
||||||
|
|
||||||
if (treeNode.type === FormatType.Text) {
|
|
||||||
child = document.createTextNode(treeNode.content || '');
|
|
||||||
}
|
|
||||||
else if (treeNode.type === FormatType.Bold) {
|
|
||||||
child = document.createElement('b');
|
|
||||||
}
|
|
||||||
else if (treeNode.type === FormatType.Italics) {
|
|
||||||
child = document.createElement('i');
|
|
||||||
}
|
|
||||||
else if (treeNode.type === FormatType.Action && actionHandler) {
|
|
||||||
const a = document.createElement('a');
|
|
||||||
a.href = '#';
|
|
||||||
actionHandler.disposeables.add(DOM.addStandardDisposableListener(a, 'click', (event) => {
|
|
||||||
actionHandler.callback(String(treeNode.index), event);
|
|
||||||
}));
|
|
||||||
|
|
||||||
child = a;
|
|
||||||
}
|
|
||||||
else if (treeNode.type === FormatType.NewLine) {
|
|
||||||
child = document.createElement('br');
|
|
||||||
}
|
|
||||||
else if (treeNode.type === FormatType.Root) {
|
|
||||||
child = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (child && element !== child) {
|
|
||||||
element.appendChild(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (child && Array.isArray(treeNode.children)) {
|
|
||||||
treeNode.children.forEach((nodeChild) => {
|
|
||||||
_renderFormattedText(child!, nodeChild, actionHandler);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseFormattedText(content: string): IFormatParseTree {
|
|
||||||
|
|
||||||
const root: IFormatParseTree = {
|
|
||||||
type: FormatType.Root,
|
|
||||||
children: []
|
|
||||||
};
|
|
||||||
|
|
||||||
let actionViewItemIndex = 0;
|
|
||||||
let current = root;
|
|
||||||
const stack: IFormatParseTree[] = [];
|
|
||||||
const stream = new StringStream(content);
|
|
||||||
|
|
||||||
while (!stream.eos()) {
|
|
||||||
let next = stream.next();
|
|
||||||
|
|
||||||
const isEscapedFormatType = (next === '\\' && formatTagType(stream.peek()) !== FormatType.Invalid);
|
|
||||||
if (isEscapedFormatType) {
|
|
||||||
next = stream.next(); // unread the backslash if it escapes a format tag type
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isEscapedFormatType && isFormatTag(next) && next === stream.peek()) {
|
|
||||||
stream.advance();
|
|
||||||
|
|
||||||
if (current.type === FormatType.Text) {
|
|
||||||
current = stack.pop()!;
|
|
||||||
}
|
|
||||||
|
|
||||||
const type = formatTagType(next);
|
|
||||||
if (current.type === type || (current.type === FormatType.Action && type === FormatType.ActionClose)) {
|
|
||||||
current = stack.pop()!;
|
|
||||||
} else {
|
|
||||||
const newCurrent: IFormatParseTree = {
|
|
||||||
type: type,
|
|
||||||
children: []
|
|
||||||
};
|
|
||||||
|
|
||||||
if (type === FormatType.Action) {
|
|
||||||
newCurrent.index = actionViewItemIndex;
|
|
||||||
actionViewItemIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
current.children!.push(newCurrent);
|
|
||||||
stack.push(current);
|
|
||||||
current = newCurrent;
|
|
||||||
}
|
|
||||||
} else if (next === '\n') {
|
|
||||||
if (current.type === FormatType.Text) {
|
|
||||||
current = stack.pop()!;
|
|
||||||
}
|
|
||||||
|
|
||||||
current.children!.push({
|
|
||||||
type: FormatType.NewLine
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (current.type !== FormatType.Text) {
|
|
||||||
const textCurrent: IFormatParseTree = {
|
|
||||||
type: FormatType.Text,
|
|
||||||
content: next
|
|
||||||
};
|
|
||||||
current.children!.push(textCurrent);
|
|
||||||
stack.push(current);
|
|
||||||
current = textCurrent;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
current.content += next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current.type === FormatType.Text) {
|
|
||||||
current = stack.pop()!;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stack.length) {
|
|
||||||
// incorrectly formatted string literal
|
|
||||||
}
|
|
||||||
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isFormatTag(char: string): boolean {
|
|
||||||
return formatTagType(char) !== FormatType.Invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatTagType(char: string): FormatType {
|
|
||||||
switch (char) {
|
|
||||||
case '*':
|
|
||||||
return FormatType.Bold;
|
|
||||||
case '_':
|
|
||||||
return FormatType.Italics;
|
|
||||||
case '[':
|
|
||||||
return FormatType.Action;
|
|
||||||
case ']':
|
|
||||||
return FormatType.ActionClose;
|
|
||||||
default:
|
|
||||||
return FormatType.Invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,8 @@ import 'vs/css!./inputBox';
|
|||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import * as Bal from 'vs/base/browser/browser';
|
import * as Bal from 'vs/base/browser/browser';
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { RenderOptions, renderFormattedText, renderText } from 'vs/base/browser/htmlContentRenderer';
|
import { MarkdownRenderOptions } from 'vs/base/browser/markdownRenderer';
|
||||||
|
import { renderFormattedText, renderText } from 'vs/base/browser/formattedTextRenderer';
|
||||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||||
import { IAction } from 'vs/base/common/actions';
|
import { IAction } from 'vs/base/common/actions';
|
||||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||||
@@ -472,7 +473,7 @@ export class InputBox extends Widget {
|
|||||||
div = dom.append(container, $('.monaco-inputbox-container'));
|
div = dom.append(container, $('.monaco-inputbox-container'));
|
||||||
layout();
|
layout();
|
||||||
|
|
||||||
const renderOptions: RenderOptions = {
|
const renderOptions: MarkdownRenderOptions = {
|
||||||
inline: true,
|
inline: true,
|
||||||
className: 'monaco-inputbox-message'
|
className: 'monaco-inputbox-message'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { domEvent } from 'vs/base/browser/event';
|
|||||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||||
import { ISelectBoxDelegate, ISelectOptionItem, ISelectBoxOptions, ISelectBoxStyles, ISelectData } from 'vs/base/browser/ui/selectBox/selectBox';
|
import { ISelectBoxDelegate, ISelectOptionItem, ISelectBoxOptions, ISelectBoxStyles, ISelectData } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||||
import { isMacintosh } from 'vs/base/common/platform';
|
import { isMacintosh } from 'vs/base/common/platform';
|
||||||
import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer';
|
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}} import color
|
// {{SQL CARBON EDIT}} import color
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
|
|||||||
@@ -729,3 +729,18 @@ export function getNLines(str: string, n = 1): string {
|
|||||||
str.substr(0, idx) :
|
str.substr(0, idx) :
|
||||||
str;
|
str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces 'a'-'z', followed by 'A'-'Z'... followed by 'a'-'z', etc.
|
||||||
|
*/
|
||||||
|
export function singleLetterHash(n: number): string {
|
||||||
|
const LETTERS_CNT = (CharCode.Z - CharCode.A + 1);
|
||||||
|
|
||||||
|
n = n % (2 * LETTERS_CNT);
|
||||||
|
|
||||||
|
if (n < LETTERS_CNT) {
|
||||||
|
return String.fromCharCode(CharCode.a + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.fromCharCode(CharCode.A + n - LETTERS_CNT);
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import * as marked from 'vs/base/common/marked/marked';
|
import { renderText, renderFormattedText } from 'vs/base/browser/formattedTextRenderer';
|
||||||
import { renderMarkdown, renderText, renderFormattedText } from 'vs/base/browser/htmlContentRenderer';
|
|
||||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
suite('HtmlContent', () => {
|
suite('FormattedTextRenderer', () => {
|
||||||
const store = new DisposableStore();
|
const store = new DisposableStore();
|
||||||
|
|
||||||
setup(() => {
|
setup(() => {
|
||||||
@@ -101,36 +101,4 @@ suite('HtmlContent', () => {
|
|||||||
assert.strictEqual(result.children.length, 0);
|
assert.strictEqual(result.children.length, 0);
|
||||||
assert.strictEqual(result.innerHTML, '**bold**');
|
assert.strictEqual(result.innerHTML, '**bold**');
|
||||||
});
|
});
|
||||||
test('image rendering conforms to default', () => {
|
|
||||||
const markdown = { value: `` };
|
|
||||||
const result: HTMLElement = renderMarkdown(markdown);
|
|
||||||
const renderer = new marked.Renderer();
|
|
||||||
const imageFromMarked = marked(markdown.value, {
|
|
||||||
sanitize: true,
|
|
||||||
renderer
|
|
||||||
}).trim();
|
|
||||||
assert.strictEqual(result.innerHTML, imageFromMarked);
|
|
||||||
});
|
|
||||||
test('image rendering conforms to default without title', () => {
|
|
||||||
const markdown = { value: `` };
|
|
||||||
const result: HTMLElement = renderMarkdown(markdown);
|
|
||||||
const renderer = new marked.Renderer();
|
|
||||||
const imageFromMarked = marked(markdown.value, {
|
|
||||||
sanitize: true,
|
|
||||||
renderer
|
|
||||||
}).trim();
|
|
||||||
assert.strictEqual(result.innerHTML, imageFromMarked);
|
|
||||||
});
|
|
||||||
test('image width from title params', () => {
|
|
||||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
|
||||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100"></p>`);
|
|
||||||
});
|
|
||||||
test('image height from title params', () => {
|
|
||||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
|
||||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" height="100"></p>`);
|
|
||||||
});
|
|
||||||
test('image width and height from title params', () => {
|
|
||||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
|
||||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100" height="200"></p>`);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import * as marked from 'vs/base/common/marked/marked';
|
||||||
|
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
||||||
|
|
||||||
|
suite('MarkdownRenderer', () => {
|
||||||
|
test('image rendering conforms to default', () => {
|
||||||
|
const markdown = { value: `` };
|
||||||
|
const result: HTMLElement = renderMarkdown(markdown);
|
||||||
|
const renderer = new marked.Renderer();
|
||||||
|
const imageFromMarked = marked(markdown.value, {
|
||||||
|
sanitize: true,
|
||||||
|
renderer
|
||||||
|
}).trim();
|
||||||
|
assert.strictEqual(result.innerHTML, imageFromMarked);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('image rendering conforms to default without title', () => {
|
||||||
|
const markdown = { value: `` };
|
||||||
|
const result: HTMLElement = renderMarkdown(markdown);
|
||||||
|
const renderer = new marked.Renderer();
|
||||||
|
const imageFromMarked = marked(markdown.value, {
|
||||||
|
sanitize: true,
|
||||||
|
renderer
|
||||||
|
}).trim();
|
||||||
|
assert.strictEqual(result.innerHTML, imageFromMarked);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('image width from title params', () => {
|
||||||
|
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||||
|
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100"></p>`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('image height from title params', () => {
|
||||||
|
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||||
|
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" height="100"></p>`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('image width and height from title params', () => {
|
||||||
|
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||||
|
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100" height="200"></p>`);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -19,26 +19,31 @@ function getWorker(workerId: string, label: string): Worker | Promise<Worker> {
|
|||||||
// ESM-comment-begin
|
// ESM-comment-begin
|
||||||
if (typeof require === 'function') {
|
if (typeof require === 'function') {
|
||||||
// check if the JS lives on a different origin
|
// check if the JS lives on a different origin
|
||||||
|
|
||||||
const workerMain = require.toUrl('./' + workerId);
|
const workerMain = require.toUrl('./' + workerId);
|
||||||
if (/^(http:)|(https:)|(file:)/.test(workerMain)) {
|
const workerUrl = getWorkerBootstrapUrl(workerMain, label);
|
||||||
const currentUrl = String(window.location);
|
return new Worker(workerUrl, { name: label });
|
||||||
const currentOrigin = currentUrl.substr(0, currentUrl.length - window.location.hash.length - window.location.search.length - window.location.pathname.length);
|
|
||||||
if (workerMain.substring(0, currentOrigin.length) !== currentOrigin) {
|
|
||||||
// this is the cross-origin case
|
|
||||||
// i.e. the webpage is running at a different origin than where the scripts are loaded from
|
|
||||||
const workerBaseUrl = workerMain.substr(0, workerMain.length - 'vs/base/worker/workerMain.js'.length);
|
|
||||||
const js = `/*${label}*/self.MonacoEnvironment={baseUrl: '${workerBaseUrl}'};importScripts('${workerMain}');/*${label}*/`;
|
|
||||||
const url = `data:text/javascript;charset=utf-8,${encodeURIComponent(js)}`;
|
|
||||||
return new Worker(url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Worker(workerMain + '#' + label);
|
|
||||||
}
|
}
|
||||||
// ESM-comment-end
|
// ESM-comment-end
|
||||||
throw new Error(`You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker`);
|
throw new Error(`You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getWorkerBootstrapUrl(scriptPath: string, label: string): string {
|
||||||
|
if (/^(http:)|(https:)|(file:)/.test(scriptPath)) {
|
||||||
|
const currentUrl = String(window.location);
|
||||||
|
const currentOrigin = currentUrl.substr(0, currentUrl.length - window.location.hash.length - window.location.search.length - window.location.pathname.length);
|
||||||
|
if (scriptPath.substring(0, currentOrigin.length) !== currentOrigin) {
|
||||||
|
// this is the cross-origin case
|
||||||
|
// i.e. the webpage is running at a different origin than where the scripts are loaded from
|
||||||
|
const myPath = 'vs/base/worker/defaultWorkerFactory.js';
|
||||||
|
const workerBaseUrl = require.toUrl(myPath).slice(0, -myPath.length);
|
||||||
|
const js = `/*${label}*/self.MonacoEnvironment={baseUrl: '${workerBaseUrl}'};importScripts('${scriptPath}');/*${label}*/`;
|
||||||
|
const url = `data:text/javascript;charset=utf-8,${encodeURIComponent(js)}`;
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return scriptPath + '#' + label;
|
||||||
|
}
|
||||||
|
|
||||||
function isPromiseLike<T>(obj: any): obj is PromiseLike<T> {
|
function isPromiseLike<T>(obj: any): obj is PromiseLike<T> {
|
||||||
if (typeof obj.then === 'function') {
|
if (typeof obj.then === 'function') {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { app, ipcMain as ipc, systemPreferences, shell, Event, contentTracing, p
|
|||||||
import { IProcessEnvironment, isWindows, isMacintosh } from 'vs/base/common/platform';
|
import { IProcessEnvironment, isWindows, isMacintosh } from 'vs/base/common/platform';
|
||||||
import { WindowsManager } from 'vs/code/electron-main/windows';
|
import { WindowsManager } from 'vs/code/electron-main/windows';
|
||||||
import { IWindowsService, OpenContext, ActiveWindowManager, IURIToOpen } from 'vs/platform/windows/common/windows';
|
import { IWindowsService, OpenContext, ActiveWindowManager, IURIToOpen } from 'vs/platform/windows/common/windows';
|
||||||
import { WindowsChannel } from 'vs/platform/windows/node/windowsIpc';
|
import { WindowsChannel } from 'vs/platform/windows/common/windowsIpc';
|
||||||
import { WindowsService } from 'vs/platform/windows/electron-main/windowsService';
|
import { WindowsService } from 'vs/platform/windows/electron-main/windowsService';
|
||||||
import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
|
import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
|
||||||
import { getShellEnvironment } from 'vs/code/node/shellEnv';
|
import { getShellEnvironment } from 'vs/code/node/shellEnv';
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export interface IPointerHandlerHelper {
|
|||||||
*/
|
*/
|
||||||
getLastViewCursorsRenderData(): IViewCursorRenderData[];
|
getLastViewCursorsRenderData(): IViewCursorRenderData[];
|
||||||
|
|
||||||
shouldSuppressMouseDownOnViewZone(viewZoneId: number): boolean;
|
shouldSuppressMouseDownOnViewZone(viewZoneId: string): boolean;
|
||||||
shouldSuppressMouseDownOnWidget(widgetId: string): boolean;
|
shouldSuppressMouseDownOnWidget(widgetId: string): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { IViewModel } from 'vs/editor/common/viewModel/viewModel';
|
|||||||
import { CursorColumns } from 'vs/editor/common/controller/cursorCommon';
|
import { CursorColumns } from 'vs/editor/common/controller/cursorCommon';
|
||||||
|
|
||||||
export interface IViewZoneData {
|
export interface IViewZoneData {
|
||||||
viewZoneId: number;
|
viewZoneId: string;
|
||||||
positionBefore: Position | null;
|
positionBefore: Position | null;
|
||||||
positionAfter: Position | null;
|
positionAfter: Position | null;
|
||||||
position: Position;
|
position: Position;
|
||||||
|
|||||||
@@ -83,17 +83,17 @@ export interface IViewZoneChangeAccessor {
|
|||||||
* @param zone Zone to create
|
* @param zone Zone to create
|
||||||
* @return A unique identifier to the view zone.
|
* @return A unique identifier to the view zone.
|
||||||
*/
|
*/
|
||||||
addZone(zone: IViewZone): number;
|
addZone(zone: IViewZone): string;
|
||||||
/**
|
/**
|
||||||
* Remove a zone
|
* Remove a zone
|
||||||
* @param id A unique identifier to the view zone, as returned by the `addZone` call.
|
* @param id A unique identifier to the view zone, as returned by the `addZone` call.
|
||||||
*/
|
*/
|
||||||
removeZone(id: number): void;
|
removeZone(id: string): void;
|
||||||
/**
|
/**
|
||||||
* Change a zone's position.
|
* Change a zone's position.
|
||||||
* The editor will rescan the `afterLineNumber` and `afterColumn` properties of a view zone.
|
* The editor will rescan the `afterLineNumber` and `afterColumn` properties of a view zone.
|
||||||
*/
|
*/
|
||||||
layoutZone(id: number): void;
|
layoutZone(id: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -399,7 +399,7 @@ export interface ICodeEditor extends editorCommon.IEditor {
|
|||||||
*/
|
*/
|
||||||
onWillType(listener: (text: string) => void): IDisposable;
|
onWillType(listener: (text: string) => void): IDisposable;
|
||||||
/**
|
/**
|
||||||
* An event emitted before interpreting typed characters (on the keyboard).
|
* An event emitted after interpreting typed characters (on the keyboard).
|
||||||
* @event
|
* @event
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -55,8 +55,7 @@ export class OpenerService implements IOpenerService {
|
|||||||
|
|
||||||
if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https) || equalsIgnoreCase(scheme, Schemas.mailto)) {
|
if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https) || equalsIgnoreCase(scheme, Schemas.mailto)) {
|
||||||
// open http or default mail application
|
// open http or default mail application
|
||||||
dom.windowOpenNoOpener(encodeURI(resource.toString(true)));
|
return this.openExternal(resource);
|
||||||
return Promise.resolve(true);
|
|
||||||
|
|
||||||
} else if (equalsIgnoreCase(scheme, Schemas.command)) {
|
} else if (equalsIgnoreCase(scheme, Schemas.command)) {
|
||||||
// run command or bail out if command isn't known
|
// run command or bail out if command isn't known
|
||||||
@@ -100,4 +99,10 @@ export class OpenerService implements IOpenerService {
|
|||||||
).then(() => true);
|
).then(() => true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openExternal(resource: URI): Promise<boolean> {
|
||||||
|
dom.windowOpenNoOpener(encodeURI(resource.toString(true)));
|
||||||
|
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ export class View extends ViewEventHandler {
|
|||||||
getLastViewCursorsRenderData: () => {
|
getLastViewCursorsRenderData: () => {
|
||||||
return this.viewCursors.getLastRenderData() || [];
|
return this.viewCursors.getLastRenderData() || [];
|
||||||
},
|
},
|
||||||
shouldSuppressMouseDownOnViewZone: (viewZoneId: number) => {
|
shouldSuppressMouseDownOnViewZone: (viewZoneId: string) => {
|
||||||
return this.viewZones.shouldSuppressMouseDownOnViewZone(viewZoneId);
|
return this.viewZones.shouldSuppressMouseDownOnViewZone(viewZoneId);
|
||||||
},
|
},
|
||||||
shouldSuppressMouseDownOnWidget: (widgetId: string) => {
|
shouldSuppressMouseDownOnWidget: (widgetId: string) => {
|
||||||
@@ -473,17 +473,17 @@ export class View extends ViewEventHandler {
|
|||||||
|
|
||||||
this._renderOnce(() => {
|
this._renderOnce(() => {
|
||||||
const changeAccessor: editorBrowser.IViewZoneChangeAccessor = {
|
const changeAccessor: editorBrowser.IViewZoneChangeAccessor = {
|
||||||
addZone: (zone: editorBrowser.IViewZone): number => {
|
addZone: (zone: editorBrowser.IViewZone): string => {
|
||||||
zonesHaveChanged = true;
|
zonesHaveChanged = true;
|
||||||
return this.viewZones.addZone(zone);
|
return this.viewZones.addZone(zone);
|
||||||
},
|
},
|
||||||
removeZone: (id: number): void => {
|
removeZone: (id: string): void => {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
zonesHaveChanged = this.viewZones.removeZone(id) || zonesHaveChanged;
|
zonesHaveChanged = this.viewZones.removeZone(id) || zonesHaveChanged;
|
||||||
},
|
},
|
||||||
layoutZone: (id: number): void => {
|
layoutZone: (id: string): void => {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import * as viewEvents from 'vs/editor/common/view/viewEvents';
|
|||||||
import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel';
|
import { IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel';
|
||||||
|
|
||||||
export interface IMyViewZone {
|
export interface IMyViewZone {
|
||||||
whitespaceId: number;
|
whitespaceId: string;
|
||||||
delegate: IViewZone;
|
delegate: IViewZone;
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
domNode: FastDomNode<HTMLElement>;
|
domNode: FastDomNode<HTMLElement>;
|
||||||
@@ -74,7 +74,7 @@ export class ViewZones extends ViewPart {
|
|||||||
const id = keys[i];
|
const id = keys[i];
|
||||||
const zone = this._zones[id];
|
const zone = this._zones[id];
|
||||||
const props = this._computeWhitespaceProps(zone.delegate);
|
const props = this._computeWhitespaceProps(zone.delegate);
|
||||||
if (this._context.viewLayout.changeWhitespace(parseInt(id, 10), props.afterViewLineNumber, props.heightInPx)) {
|
if (this._context.viewLayout.changeWhitespace(id, props.afterViewLineNumber, props.heightInPx)) {
|
||||||
this._safeCallOnComputedHeight(zone.delegate, props.heightInPx);
|
this._safeCallOnComputedHeight(zone.delegate, props.heightInPx);
|
||||||
hadAChange = true;
|
hadAChange = true;
|
||||||
}
|
}
|
||||||
@@ -183,7 +183,7 @@ export class ViewZones extends ViewPart {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public addZone(zone: IViewZone): number {
|
public addZone(zone: IViewZone): string {
|
||||||
const props = this._computeWhitespaceProps(zone);
|
const props = this._computeWhitespaceProps(zone);
|
||||||
const whitespaceId = this._context.viewLayout.addWhitespace(props.afterViewLineNumber, this._getZoneOrdinal(zone), props.heightInPx, props.minWidthInPx);
|
const whitespaceId = this._context.viewLayout.addWhitespace(props.afterViewLineNumber, this._getZoneOrdinal(zone), props.heightInPx, props.minWidthInPx);
|
||||||
|
|
||||||
@@ -200,18 +200,18 @@ export class ViewZones extends ViewPart {
|
|||||||
myZone.domNode.setPosition('absolute');
|
myZone.domNode.setPosition('absolute');
|
||||||
myZone.domNode.domNode.style.width = '100%';
|
myZone.domNode.domNode.style.width = '100%';
|
||||||
myZone.domNode.setDisplay('none');
|
myZone.domNode.setDisplay('none');
|
||||||
myZone.domNode.setAttribute('monaco-view-zone', myZone.whitespaceId.toString());
|
myZone.domNode.setAttribute('monaco-view-zone', myZone.whitespaceId);
|
||||||
this.domNode.appendChild(myZone.domNode);
|
this.domNode.appendChild(myZone.domNode);
|
||||||
|
|
||||||
if (myZone.marginDomNode) {
|
if (myZone.marginDomNode) {
|
||||||
myZone.marginDomNode.setPosition('absolute');
|
myZone.marginDomNode.setPosition('absolute');
|
||||||
myZone.marginDomNode.domNode.style.width = '100%';
|
myZone.marginDomNode.domNode.style.width = '100%';
|
||||||
myZone.marginDomNode.setDisplay('none');
|
myZone.marginDomNode.setDisplay('none');
|
||||||
myZone.marginDomNode.setAttribute('monaco-view-zone', myZone.whitespaceId.toString());
|
myZone.marginDomNode.setAttribute('monaco-view-zone', myZone.whitespaceId);
|
||||||
this.marginDomNode.appendChild(myZone.marginDomNode);
|
this.marginDomNode.appendChild(myZone.marginDomNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._zones[myZone.whitespaceId.toString()] = myZone;
|
this._zones[myZone.whitespaceId] = myZone;
|
||||||
|
|
||||||
|
|
||||||
this.setShouldRender();
|
this.setShouldRender();
|
||||||
@@ -219,10 +219,10 @@ export class ViewZones extends ViewPart {
|
|||||||
return myZone.whitespaceId;
|
return myZone.whitespaceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeZone(id: number): boolean {
|
public removeZone(id: string): boolean {
|
||||||
if (this._zones.hasOwnProperty(id.toString())) {
|
if (this._zones.hasOwnProperty(id)) {
|
||||||
const zone = this._zones[id.toString()];
|
const zone = this._zones[id];
|
||||||
delete this._zones[id.toString()];
|
delete this._zones[id];
|
||||||
this._context.viewLayout.removeWhitespace(zone.whitespaceId);
|
this._context.viewLayout.removeWhitespace(zone.whitespaceId);
|
||||||
|
|
||||||
zone.domNode.removeAttribute('monaco-visible-view-zone');
|
zone.domNode.removeAttribute('monaco-visible-view-zone');
|
||||||
@@ -242,10 +242,10 @@ export class ViewZones extends ViewPart {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public layoutZone(id: number): boolean {
|
public layoutZone(id: string): boolean {
|
||||||
let changed = false;
|
let changed = false;
|
||||||
if (this._zones.hasOwnProperty(id.toString())) {
|
if (this._zones.hasOwnProperty(id)) {
|
||||||
const zone = this._zones[id.toString()];
|
const zone = this._zones[id];
|
||||||
const props = this._computeWhitespaceProps(zone.delegate);
|
const props = this._computeWhitespaceProps(zone.delegate);
|
||||||
// const newOrdinal = this._getZoneOrdinal(zone.delegate);
|
// const newOrdinal = this._getZoneOrdinal(zone.delegate);
|
||||||
changed = this._context.viewLayout.changeWhitespace(zone.whitespaceId, props.afterViewLineNumber, props.heightInPx) || changed;
|
changed = this._context.viewLayout.changeWhitespace(zone.whitespaceId, props.afterViewLineNumber, props.heightInPx) || changed;
|
||||||
@@ -259,9 +259,9 @@ export class ViewZones extends ViewPart {
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public shouldSuppressMouseDownOnViewZone(id: number): boolean {
|
public shouldSuppressMouseDownOnViewZone(id: string): boolean {
|
||||||
if (this._zones.hasOwnProperty(id.toString())) {
|
if (this._zones.hasOwnProperty(id)) {
|
||||||
const zone = this._zones[id.toString()];
|
const zone = this._zones[id];
|
||||||
return Boolean(zone.delegate.suppressMouseDown);
|
return Boolean(zone.delegate.suppressMouseDown);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -314,7 +314,7 @@ export class ViewZones extends ViewPart {
|
|||||||
|
|
||||||
let hasVisibleZone = false;
|
let hasVisibleZone = false;
|
||||||
for (let i = 0, len = visibleWhitespaces.length; i < len; i++) {
|
for (let i = 0, len = visibleWhitespaces.length; i < len; i++) {
|
||||||
visibleZones[visibleWhitespaces[i].id.toString()] = visibleWhitespaces[i];
|
visibleZones[visibleWhitespaces[i].id] = visibleWhitespaces[i];
|
||||||
hasVisibleZone = true;
|
hasVisibleZone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ interface IDiffEditorWidgetStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class VisualEditorState {
|
class VisualEditorState {
|
||||||
private _zones: number[];
|
private _zones: string[];
|
||||||
private _zonesMap: { [zoneId: string]: boolean; };
|
private _zonesMap: { [zoneId: string]: boolean; };
|
||||||
private _decorations: string[];
|
private _decorations: string[];
|
||||||
|
|
||||||
|
|||||||
@@ -110,21 +110,6 @@ export function createTextBuffer(value: string | model.ITextBufferFactory, defau
|
|||||||
|
|
||||||
let MODEL_ID = 0;
|
let MODEL_ID = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Produces 'a'-'z', followed by 'A'-'Z'... followed by 'a'-'z', etc.
|
|
||||||
*/
|
|
||||||
function singleLetter(result: number): string {
|
|
||||||
const LETTERS_CNT = (CharCode.Z - CharCode.A + 1);
|
|
||||||
|
|
||||||
result = result % (2 * LETTERS_CNT);
|
|
||||||
|
|
||||||
if (result < LETTERS_CNT) {
|
|
||||||
return String.fromCharCode(CharCode.a + result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return String.fromCharCode(CharCode.A + result - LETTERS_CNT);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LIMIT_FIND_COUNT = 999;
|
const LIMIT_FIND_COUNT = 999;
|
||||||
export const LONG_LINE_BOUNDARY = 10000;
|
export const LONG_LINE_BOUNDARY = 10000;
|
||||||
|
|
||||||
@@ -343,7 +328,7 @@ export class TextModel extends Disposable implements model.ITextModel {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this._instanceId = singleLetter(MODEL_ID);
|
this._instanceId = strings.singleLetterHash(MODEL_ID);
|
||||||
this._lastDecorationId = 0;
|
this._lastDecorationId = 0;
|
||||||
this._decorations = Object.create(null);
|
this._decorations = Object.create(null);
|
||||||
this._decorationsTree = new DecorationsTrees();
|
this._decorationsTree = new DecorationsTrees();
|
||||||
|
|||||||
@@ -63,14 +63,14 @@ export class LinesLayout {
|
|||||||
* @param heightInPx The height of the whitespace, in pixels.
|
* @param heightInPx The height of the whitespace, in pixels.
|
||||||
* @return An id that can be used later to mutate or delete the whitespace
|
* @return An id that can be used later to mutate or delete the whitespace
|
||||||
*/
|
*/
|
||||||
public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): number {
|
public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string {
|
||||||
return this._whitespaces.insertWhitespace(afterLineNumber, ordinal, heightInPx, minWidth);
|
return this._whitespaces.insertWhitespace(afterLineNumber, ordinal, heightInPx, minWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change properties associated with a certain whitespace.
|
* Change properties associated with a certain whitespace.
|
||||||
*/
|
*/
|
||||||
public changeWhitespace(id: number, newAfterLineNumber: number, newHeight: number): boolean {
|
public changeWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean {
|
||||||
return this._whitespaces.changeWhitespace(id, newAfterLineNumber, newHeight);
|
return this._whitespaces.changeWhitespace(id, newAfterLineNumber, newHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ export class LinesLayout {
|
|||||||
* @param id The whitespace to remove
|
* @param id The whitespace to remove
|
||||||
* @return Returns true if the whitespace is found and it is removed.
|
* @return Returns true if the whitespace is found and it is removed.
|
||||||
*/
|
*/
|
||||||
public removeWhitespace(id: number): boolean {
|
public removeWhitespace(id: string): boolean {
|
||||||
return this._whitespaces.removeWhitespace(id);
|
return this._whitespaces.removeWhitespace(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -173,13 +173,13 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
|||||||
|
|
||||||
// ---- IVerticalLayoutProvider
|
// ---- IVerticalLayoutProvider
|
||||||
|
|
||||||
public addWhitespace(afterLineNumber: number, ordinal: number, height: number, minWidth: number): number {
|
public addWhitespace(afterLineNumber: number, ordinal: number, height: number, minWidth: number): string {
|
||||||
return this._linesLayout.insertWhitespace(afterLineNumber, ordinal, height, minWidth);
|
return this._linesLayout.insertWhitespace(afterLineNumber, ordinal, height, minWidth);
|
||||||
}
|
}
|
||||||
public changeWhitespace(id: number, newAfterLineNumber: number, newHeight: number): boolean {
|
public changeWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean {
|
||||||
return this._linesLayout.changeWhitespace(id, newAfterLineNumber, newHeight);
|
return this._linesLayout.changeWhitespace(id, newAfterLineNumber, newHeight);
|
||||||
}
|
}
|
||||||
public removeWhitespace(id: number): boolean {
|
public removeWhitespace(id: string): boolean {
|
||||||
return this._linesLayout.removeWhitespace(id);
|
return this._linesLayout.removeWhitespace(id);
|
||||||
}
|
}
|
||||||
public getVerticalOffsetForLineNumber(lineNumber: number): number {
|
public getVerticalOffsetForLineNumber(lineNumber: number): number {
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as strings from 'vs/base/common/strings';
|
||||||
|
|
||||||
export interface IEditorWhitespace {
|
export interface IEditorWhitespace {
|
||||||
readonly id: number;
|
readonly id: string;
|
||||||
readonly afterLineNumber: number;
|
readonly afterLineNumber: number;
|
||||||
readonly heightInLines: number;
|
readonly heightInLines: number;
|
||||||
}
|
}
|
||||||
@@ -15,6 +17,10 @@ export interface IEditorWhitespace {
|
|||||||
*/
|
*/
|
||||||
export class WhitespaceComputer {
|
export class WhitespaceComputer {
|
||||||
|
|
||||||
|
private static INSTANCE_COUNT = 0;
|
||||||
|
|
||||||
|
private readonly _instanceId: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* heights[i] is the height in pixels for whitespace at index i
|
* heights[i] is the height in pixels for whitespace at index i
|
||||||
*/
|
*/
|
||||||
@@ -48,7 +54,7 @@ export class WhitespaceComputer {
|
|||||||
/**
|
/**
|
||||||
* ids[i] is the whitespace id of whitespace at index i
|
* ids[i] is the whitespace id of whitespace at index i
|
||||||
*/
|
*/
|
||||||
private readonly _ids: number[];
|
private readonly _ids: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* index at which a whitespace is positioned (inside heights, afterLineNumbers, prefixSum members)
|
* index at which a whitespace is positioned (inside heights, afterLineNumbers, prefixSum members)
|
||||||
@@ -65,6 +71,7 @@ export class WhitespaceComputer {
|
|||||||
private _minWidth: number;
|
private _minWidth: number;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this._instanceId = strings.singleLetterHash(++WhitespaceComputer.INSTANCE_COUNT);
|
||||||
this._heights = [];
|
this._heights = [];
|
||||||
this._minWidths = [];
|
this._minWidths = [];
|
||||||
this._ids = [];
|
this._ids = [];
|
||||||
@@ -113,21 +120,20 @@ export class WhitespaceComputer {
|
|||||||
* @param heightInPx The height of the whitespace, in pixels.
|
* @param heightInPx The height of the whitespace, in pixels.
|
||||||
* @return An id that can be used later to mutate or delete the whitespace
|
* @return An id that can be used later to mutate or delete the whitespace
|
||||||
*/
|
*/
|
||||||
public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): number {
|
public insertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string {
|
||||||
afterLineNumber = afterLineNumber | 0;
|
afterLineNumber = afterLineNumber | 0;
|
||||||
ordinal = ordinal | 0;
|
ordinal = ordinal | 0;
|
||||||
heightInPx = heightInPx | 0;
|
heightInPx = heightInPx | 0;
|
||||||
minWidth = minWidth | 0;
|
minWidth = minWidth | 0;
|
||||||
|
|
||||||
let id = (++this._lastWhitespaceId);
|
let id = this._instanceId + (++this._lastWhitespaceId);
|
||||||
let insertionIndex = WhitespaceComputer.findInsertionIndex(this._afterLineNumbers, afterLineNumber, this._ordinals, ordinal);
|
let insertionIndex = WhitespaceComputer.findInsertionIndex(this._afterLineNumbers, afterLineNumber, this._ordinals, ordinal);
|
||||||
this._insertWhitespaceAtIndex(id, insertionIndex, afterLineNumber, ordinal, heightInPx, minWidth);
|
this._insertWhitespaceAtIndex(id, insertionIndex, afterLineNumber, ordinal, heightInPx, minWidth);
|
||||||
this._minWidth = -1; /* marker for not being computed */
|
this._minWidth = -1; /* marker for not being computed */
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _insertWhitespaceAtIndex(id: number, insertIndex: number, afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): void {
|
private _insertWhitespaceAtIndex(id: string, insertIndex: number, afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): void {
|
||||||
id = id | 0;
|
|
||||||
insertIndex = insertIndex | 0;
|
insertIndex = insertIndex | 0;
|
||||||
afterLineNumber = afterLineNumber | 0;
|
afterLineNumber = afterLineNumber | 0;
|
||||||
ordinal = ordinal | 0;
|
ordinal = ordinal | 0;
|
||||||
@@ -150,15 +156,14 @@ export class WhitespaceComputer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._whitespaceId2Index[id.toString()] = insertIndex;
|
this._whitespaceId2Index[id] = insertIndex;
|
||||||
this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, insertIndex - 1);
|
this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, insertIndex - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change properties associated with a certain whitespace.
|
* Change properties associated with a certain whitespace.
|
||||||
*/
|
*/
|
||||||
public changeWhitespace(id: number, newAfterLineNumber: number, newHeight: number): boolean {
|
public changeWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean {
|
||||||
id = id | 0;
|
|
||||||
newAfterLineNumber = newAfterLineNumber | 0;
|
newAfterLineNumber = newAfterLineNumber | 0;
|
||||||
newHeight = newHeight | 0;
|
newHeight = newHeight | 0;
|
||||||
|
|
||||||
@@ -175,13 +180,11 @@ export class WhitespaceComputer {
|
|||||||
* @param newHeightInPx The new height of the whitespace, in pixels
|
* @param newHeightInPx The new height of the whitespace, in pixels
|
||||||
* @return Returns true if the whitespace is found and if the new height is different than the old height
|
* @return Returns true if the whitespace is found and if the new height is different than the old height
|
||||||
*/
|
*/
|
||||||
public changeWhitespaceHeight(id: number, newHeightInPx: number): boolean {
|
public changeWhitespaceHeight(id: string, newHeightInPx: number): boolean {
|
||||||
id = id | 0;
|
|
||||||
newHeightInPx = newHeightInPx | 0;
|
newHeightInPx = newHeightInPx | 0;
|
||||||
|
|
||||||
let sid = id.toString();
|
if (this._whitespaceId2Index.hasOwnProperty(id)) {
|
||||||
if (this._whitespaceId2Index.hasOwnProperty(sid)) {
|
let index = this._whitespaceId2Index[id];
|
||||||
let index = this._whitespaceId2Index[sid];
|
|
||||||
if (this._heights[index] !== newHeightInPx) {
|
if (this._heights[index] !== newHeightInPx) {
|
||||||
this._heights[index] = newHeightInPx;
|
this._heights[index] = newHeightInPx;
|
||||||
this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, index - 1);
|
this._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, index - 1);
|
||||||
@@ -198,13 +201,11 @@ export class WhitespaceComputer {
|
|||||||
* @param newAfterLineNumber The new line number the whitespace will follow
|
* @param newAfterLineNumber The new line number the whitespace will follow
|
||||||
* @return Returns true if the whitespace is found and if the new line number is different than the old line number
|
* @return Returns true if the whitespace is found and if the new line number is different than the old line number
|
||||||
*/
|
*/
|
||||||
public changeWhitespaceAfterLineNumber(id: number, newAfterLineNumber: number): boolean {
|
public changeWhitespaceAfterLineNumber(id: string, newAfterLineNumber: number): boolean {
|
||||||
id = id | 0;
|
|
||||||
newAfterLineNumber = newAfterLineNumber | 0;
|
newAfterLineNumber = newAfterLineNumber | 0;
|
||||||
|
|
||||||
let sid = id.toString();
|
if (this._whitespaceId2Index.hasOwnProperty(id)) {
|
||||||
if (this._whitespaceId2Index.hasOwnProperty(sid)) {
|
let index = this._whitespaceId2Index[id];
|
||||||
let index = this._whitespaceId2Index[sid];
|
|
||||||
if (this._afterLineNumbers[index] !== newAfterLineNumber) {
|
if (this._afterLineNumbers[index] !== newAfterLineNumber) {
|
||||||
// `afterLineNumber` changed for this whitespace
|
// `afterLineNumber` changed for this whitespace
|
||||||
|
|
||||||
@@ -236,14 +237,10 @@ export class WhitespaceComputer {
|
|||||||
* @param id The whitespace to remove
|
* @param id The whitespace to remove
|
||||||
* @return Returns true if the whitespace is found and it is removed.
|
* @return Returns true if the whitespace is found and it is removed.
|
||||||
*/
|
*/
|
||||||
public removeWhitespace(id: number): boolean {
|
public removeWhitespace(id: string): boolean {
|
||||||
id = id | 0;
|
if (this._whitespaceId2Index.hasOwnProperty(id)) {
|
||||||
|
let index = this._whitespaceId2Index[id];
|
||||||
let sid = id.toString();
|
delete this._whitespaceId2Index[id];
|
||||||
|
|
||||||
if (this._whitespaceId2Index.hasOwnProperty(sid)) {
|
|
||||||
let index = this._whitespaceId2Index[sid];
|
|
||||||
delete this._whitespaceId2Index[sid];
|
|
||||||
this._removeWhitespaceAtIndex(index);
|
this._removeWhitespaceAtIndex(index);
|
||||||
this._minWidth = -1; /* marker for not being computed */
|
this._minWidth = -1; /* marker for not being computed */
|
||||||
return true;
|
return true;
|
||||||
@@ -459,7 +456,7 @@ export class WhitespaceComputer {
|
|||||||
* @param index The index of the whitespace.
|
* @param index The index of the whitespace.
|
||||||
* @return `id` of whitespace at `index`.
|
* @return `id` of whitespace at `index`.
|
||||||
*/
|
*/
|
||||||
public getIdForWhitespaceIndex(index: number): number {
|
public getIdForWhitespaceIndex(index: number): string {
|
||||||
index = index | 0;
|
index = index | 0;
|
||||||
|
|
||||||
return this._ids[index];
|
return this._ids[index];
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceCompute
|
|||||||
import { ITheme } from 'vs/platform/theme/common/themeService';
|
import { ITheme } from 'vs/platform/theme/common/themeService';
|
||||||
|
|
||||||
export interface IViewWhitespaceViewportData {
|
export interface IViewWhitespaceViewportData {
|
||||||
readonly id: number;
|
readonly id: string;
|
||||||
readonly afterLineNumber: number;
|
readonly afterLineNumber: number;
|
||||||
readonly verticalOffset: number;
|
readonly verticalOffset: number;
|
||||||
readonly height: number;
|
readonly height: number;
|
||||||
@@ -74,15 +74,15 @@ export interface IViewLayout {
|
|||||||
* Reserve rendering space.
|
* Reserve rendering space.
|
||||||
* @return an identifier that can be later used to remove or change the whitespace.
|
* @return an identifier that can be later used to remove or change the whitespace.
|
||||||
*/
|
*/
|
||||||
addWhitespace(afterLineNumber: number, ordinal: number, height: number, minWidth: number): number;
|
addWhitespace(afterLineNumber: number, ordinal: number, height: number, minWidth: number): string;
|
||||||
/**
|
/**
|
||||||
* Change the properties of a whitespace.
|
* Change the properties of a whitespace.
|
||||||
*/
|
*/
|
||||||
changeWhitespace(id: number, newAfterLineNumber: number, newHeight: number): boolean;
|
changeWhitespace(id: string, newAfterLineNumber: number, newHeight: number): boolean;
|
||||||
/**
|
/**
|
||||||
* Remove rendering space
|
* Remove rendering space
|
||||||
*/
|
*/
|
||||||
removeWhitespace(id: number): boolean;
|
removeWhitespace(id: string): boolean;
|
||||||
/**
|
/**
|
||||||
* Get the layout information for whitespaces currently in the viewport
|
* Get the layout information for whitespaces currently in the viewport
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ export class CodeLensWidget {
|
|||||||
|
|
||||||
private readonly _editor: editorBrowser.ICodeEditor;
|
private readonly _editor: editorBrowser.ICodeEditor;
|
||||||
private readonly _viewZone!: CodeLensViewZone;
|
private readonly _viewZone!: CodeLensViewZone;
|
||||||
private readonly _viewZoneId!: number;
|
private readonly _viewZoneId!: string;
|
||||||
private readonly _contentWidget!: CodeLensContentWidget;
|
private readonly _contentWidget!: CodeLensContentWidget;
|
||||||
private _decorationIds: string[];
|
private _decorationIds: string[];
|
||||||
private _data: CodeLensItem[];
|
private _data: CodeLensItem[];
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
private readonly _replaceFocusTracker: dom.IFocusTracker;
|
private readonly _replaceFocusTracker: dom.IFocusTracker;
|
||||||
private readonly _replaceInputFocused: IContextKey<boolean>;
|
private readonly _replaceInputFocused: IContextKey<boolean>;
|
||||||
private _viewZone?: FindWidgetViewZone;
|
private _viewZone?: FindWidgetViewZone;
|
||||||
private _viewZoneId?: number;
|
private _viewZoneId?: string;
|
||||||
|
|
||||||
private _resizeSash!: Sash;
|
private _resizeSash!: Sash;
|
||||||
private _resized!: boolean;
|
private _resized!: boolean;
|
||||||
@@ -224,15 +224,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
if (!this._isVisible) {
|
if (!this._isVisible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this._viewZoneId === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._codeEditor.changeViewZones((accessor) => {
|
|
||||||
if (this._viewZoneId) {
|
|
||||||
accessor.removeZone(this._viewZoneId);
|
|
||||||
}
|
|
||||||
this._viewZoneId = undefined;
|
this._viewZoneId = undefined;
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
import { IMarkdownString } from 'vs/base/common/htmlContent';
|
||||||
import { renderMarkdown, RenderOptions } from 'vs/base/browser/htmlContentRenderer';
|
import { renderMarkdown, MarkdownRenderOptions } from 'vs/base/browser/markdownRenderer';
|
||||||
import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener';
|
import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
@@ -33,7 +33,7 @@ export class MarkdownRenderer extends Disposable {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
private getOptions(disposeables: DisposableStore): RenderOptions {
|
private getOptions(disposeables: DisposableStore): MarkdownRenderOptions {
|
||||||
return {
|
return {
|
||||||
codeBlockRenderer: (languageAlias, value) => {
|
codeBlockRenderer: (languageAlias, value) => {
|
||||||
// In markdown,
|
// In markdown,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export const KnownSnippetVariableNames: { [key: string]: true } = Object.freeze(
|
|||||||
'CURRENT_DAY_NAME_SHORT': true,
|
'CURRENT_DAY_NAME_SHORT': true,
|
||||||
'CURRENT_MONTH_NAME': true,
|
'CURRENT_MONTH_NAME': true,
|
||||||
'CURRENT_MONTH_NAME_SHORT': true,
|
'CURRENT_MONTH_NAME_SHORT': true,
|
||||||
|
'CURRENT_SECONDS_UNIX': true,
|
||||||
'SELECTION': true,
|
'SELECTION': true,
|
||||||
'CLIPBOARD': true,
|
'CLIPBOARD': true,
|
||||||
'TM_SELECTED_TEXT': true,
|
'TM_SELECTED_TEXT': true,
|
||||||
@@ -245,6 +246,8 @@ export class TimeBasedVariableResolver implements VariableResolver {
|
|||||||
return TimeBasedVariableResolver.monthNames[new Date().getMonth()];
|
return TimeBasedVariableResolver.monthNames[new Date().getMonth()];
|
||||||
} else if (name === 'CURRENT_MONTH_NAME_SHORT') {
|
} else if (name === 'CURRENT_MONTH_NAME_SHORT') {
|
||||||
return TimeBasedVariableResolver.monthNamesShort[new Date().getMonth()];
|
return TimeBasedVariableResolver.monthNamesShort[new Date().getMonth()];
|
||||||
|
} else if (name === 'CURRENT_SECONDS_UNIX') {
|
||||||
|
return String(Math.floor(Date.now() / 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@@ -281,6 +281,7 @@ suite('Snippet Variables Resolver', function () {
|
|||||||
assertVariableResolve3(resolver, 'CURRENT_DAY_NAME_SHORT');
|
assertVariableResolve3(resolver, 'CURRENT_DAY_NAME_SHORT');
|
||||||
assertVariableResolve3(resolver, 'CURRENT_MONTH_NAME');
|
assertVariableResolve3(resolver, 'CURRENT_MONTH_NAME');
|
||||||
assertVariableResolve3(resolver, 'CURRENT_MONTH_NAME_SHORT');
|
assertVariableResolve3(resolver, 'CURRENT_MONTH_NAME_SHORT');
|
||||||
|
assertVariableResolve3(resolver, 'CURRENT_SECONDS_UNIX');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('creating snippet - format-condition doesn\'t work #53617', function () {
|
test('creating snippet - format-condition doesn\'t work #53617', function () {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const WIDGET_ID = 'vs.editor.contrib.zoneWidget';
|
|||||||
export class ViewZoneDelegate implements IViewZone {
|
export class ViewZoneDelegate implements IViewZone {
|
||||||
|
|
||||||
public domNode: HTMLElement;
|
public domNode: HTMLElement;
|
||||||
public id: number = 0; // A valid zone id should be greater than 0
|
public id: string = ''; // A valid zone id should be greater than 0
|
||||||
public afterLineNumber: number;
|
public afterLineNumber: number;
|
||||||
public afterColumn: number;
|
public afterColumn: number;
|
||||||
public heightInLines: number;
|
public heightInLines: number;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'vs/css!./accessibilityHelp';
|
|||||||
import * as browser from 'vs/base/browser/browser';
|
import * as browser from 'vs/base/browser/browser';
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
|
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
|
||||||
import { renderFormattedText } from 'vs/base/browser/htmlContentRenderer';
|
import { renderFormattedText } from 'vs/base/browser/formattedTextRenderer';
|
||||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||||
import { Widget } from 'vs/base/browser/ui/widget';
|
import { Widget } from 'vs/base/browser/ui/widget';
|
||||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||||
|
|||||||
@@ -3609,17 +3609,17 @@ declare namespace monaco.editor {
|
|||||||
* @param zone Zone to create
|
* @param zone Zone to create
|
||||||
* @return A unique identifier to the view zone.
|
* @return A unique identifier to the view zone.
|
||||||
*/
|
*/
|
||||||
addZone(zone: IViewZone): number;
|
addZone(zone: IViewZone): string;
|
||||||
/**
|
/**
|
||||||
* Remove a zone
|
* Remove a zone
|
||||||
* @param id A unique identifier to the view zone, as returned by the `addZone` call.
|
* @param id A unique identifier to the view zone, as returned by the `addZone` call.
|
||||||
*/
|
*/
|
||||||
removeZone(id: number): void;
|
removeZone(id: string): void;
|
||||||
/**
|
/**
|
||||||
* Change a zone's position.
|
* Change a zone's position.
|
||||||
* The editor will rescan the `afterLineNumber` and `afterColumn` properties of a view zone.
|
* The editor will rescan the `afterLineNumber` and `afterColumn` properties of a view zone.
|
||||||
*/
|
*/
|
||||||
layoutZone(id: number): void;
|
layoutZone(id: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -392,10 +392,10 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
@IProductService private readonly productService: IProductService,
|
@IProductService private readonly productService: IProductService,
|
||||||
@optional(IStorageService) private readonly storageService: IStorageService,
|
@optional(IStorageService) private readonly storageService: IStorageService,
|
||||||
) {
|
) {
|
||||||
const config = productService.extensionsGallery;
|
const config = productService.productConfiguration.extensionsGallery;
|
||||||
this.extensionsGalleryUrl = config && config.serviceUrl;
|
this.extensionsGalleryUrl = config && config.serviceUrl;
|
||||||
this.extensionsControlUrl = config && config.controlUrl;
|
this.extensionsControlUrl = config && config.controlUrl;
|
||||||
this.commonHeadersPromise = resolveMarketplaceHeaders(productService.version, this.environmentService, this.fileService, this.storageService);
|
this.commonHeadersPromise = resolveMarketplaceHeaders(productService.productConfiguration.version, this.environmentService, this.fileService, this.storageService);
|
||||||
}
|
}
|
||||||
|
|
||||||
private api(path = ''): string {
|
private api(path = ''): string {
|
||||||
@@ -440,7 +440,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
const versionAsset = rawExtension.versions.filter(v => v.version === version)[0];
|
const versionAsset = rawExtension.versions.filter(v => v.version === version)[0];
|
||||||
if (versionAsset) {
|
if (versionAsset) {
|
||||||
const extension = toExtension(rawExtension, versionAsset, 0, query);
|
const extension = toExtension(rawExtension, versionAsset, 0, query);
|
||||||
if (extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version)) {
|
if (extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.productConfiguration.version)) {
|
||||||
return extension;
|
return extension;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -788,7 +788,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
return this.queryGallery(query, CancellationToken.None).then(({ galleryExtensions }) => {
|
return this.queryGallery(query, CancellationToken.None).then(({ galleryExtensions }) => {
|
||||||
if (galleryExtensions.length) {
|
if (galleryExtensions.length) {
|
||||||
if (compatible) {
|
if (compatible) {
|
||||||
return Promise.all(galleryExtensions[0].versions.map(v => this.getEngine(v).then(engine => isEngineValid(engine, this.productService.version) ? v : null)))
|
return Promise.all(galleryExtensions[0].versions.map(v => this.getEngine(v).then(engine => isEngineValid(engine, this.productService.productConfiguration.version) ? v : null)))
|
||||||
.then(versions => versions
|
.then(versions => versions
|
||||||
.filter(v => !!v)
|
.filter(v => !!v)
|
||||||
.map(v => ({ version: v!.version, date: v!.lastUpdated })));
|
.map(v => ({ version: v!.version, date: v!.lastUpdated })));
|
||||||
@@ -874,7 +874,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
if (!engine) {
|
if (!engine) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (isEngineValid(engine, this.productService.version)) {
|
if (isEngineValid(engine, this.productService.productConfiguration.version)) {
|
||||||
return Promise.resolve(version);
|
return Promise.resolve(version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -906,7 +906,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||||||
const version = versions[0];
|
const version = versions[0];
|
||||||
return this.getEngine(version)
|
return this.getEngine(version)
|
||||||
.then(engine => {
|
.then(engine => {
|
||||||
if (!isEngineValid(engine, this.productService.version)) {
|
if (!isEngineValid(engine, this.productService.productConfiguration.version)) {
|
||||||
return this.getLastValidExtensionVersionRecursively(extension, versions.slice(1));
|
return this.getLastValidExtensionVersionRecursively(extension, versions.slice(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ export interface IExtensionContributions {
|
|||||||
localizations?: ILocalization[];
|
localizations?: ILocalization[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExtensionKind = 'ui' | 'workspace';
|
export type ExtensionKind = 'ui' | 'workspace' | 'web';
|
||||||
|
|
||||||
export function isIExtensionIdentifier(thing: any): thing is IExtensionIdentifier {
|
export function isIExtensionIdentifier(thing: any): thing is IExtensionIdentifier {
|
||||||
return thing
|
return thing
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
|||||||
|
|
||||||
export const IOpenerService = createDecorator<IOpenerService>('openerService');
|
export const IOpenerService = createDecorator<IOpenerService>('openerService');
|
||||||
|
|
||||||
|
|
||||||
export interface IOpener {
|
export interface IOpener {
|
||||||
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean>;
|
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean>;
|
||||||
}
|
}
|
||||||
@@ -18,6 +17,9 @@ export interface IOpenerService {
|
|||||||
|
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a participant that can handle the open() call.
|
||||||
|
*/
|
||||||
registerOpener(opener: IOpener): IDisposable;
|
registerOpener(opener: IOpener): IDisposable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,10 +29,18 @@ export interface IOpenerService {
|
|||||||
* @return A promise that resolves when the opening is done.
|
* @return A promise that resolves when the opening is done.
|
||||||
*/
|
*/
|
||||||
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean>;
|
open(resource: URI, options?: { openToSide?: boolean }): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a URL externally.
|
||||||
|
*
|
||||||
|
* @param url A resource to open externally.
|
||||||
|
*/
|
||||||
|
openExternal(resource: URI): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NullOpenerService: IOpenerService = Object.freeze({
|
export const NullOpenerService: IOpenerService = Object.freeze({
|
||||||
_serviceBrand: undefined,
|
_serviceBrand: undefined,
|
||||||
registerOpener() { return { dispose() { } }; },
|
registerOpener() { return { dispose() { } }; },
|
||||||
open() { return Promise.resolve(false); }
|
open() { return Promise.resolve(false); },
|
||||||
|
openExternal() { return Promise.resolve(false); }
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,44 +10,18 @@ export class ProductService implements IProductService {
|
|||||||
|
|
||||||
_serviceBrand!: ServiceIdentifier<IProductService>;
|
_serviceBrand!: ServiceIdentifier<IProductService>;
|
||||||
|
|
||||||
private readonly productConfiguration: IProductConfiguration | null;
|
readonly productConfiguration: IProductConfiguration;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const element = document.getElementById('vscode-remote-product-configuration');
|
const element = document.getElementById('vscode-remote-product-configuration');
|
||||||
this.productConfiguration = element ? JSON.parse(element.getAttribute('data-settings')!) : null;
|
this.productConfiguration = {
|
||||||
|
...element ? JSON.parse(element.getAttribute('data-settings')!) : {
|
||||||
|
version: '1.38.0-unknown',
|
||||||
|
nameLong: 'Unknown',
|
||||||
|
extensionAllowedProposedApi: [],
|
||||||
|
}, ...{ urlProtocol: '', enableTelemetry: false },
|
||||||
|
...{ vscodeVersion: '1.35.0' } // {{SQL CARBON EDIT}} add vscodeversion
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get version(): string { return this.productConfiguration && this.productConfiguration.version ? this.productConfiguration.version : '1.38.0-unknown'; }
|
|
||||||
|
|
||||||
get vscodeVersion(): string { return '1.35.0'; } // {{SQL CARBON EDIT}} add vscodeversion
|
|
||||||
|
|
||||||
get recommendedExtensionsByScenario(): { [area: string]: Array<string> } { return this.productConfiguration ? this.productConfiguration.recommendedExtensionsByScenario : {}; }// {{SQL CARBON EDIT}} add getter
|
|
||||||
|
|
||||||
get commit(): string | undefined { return this.productConfiguration ? this.productConfiguration.commit : undefined; }
|
|
||||||
|
|
||||||
get nameLong(): string { return this.productConfiguration ? this.productConfiguration.nameLong : 'Unknown'; }
|
|
||||||
|
|
||||||
get urlProtocol(): string { return ''; }
|
|
||||||
|
|
||||||
get extensionAllowedProposedApi(): readonly string[] { return this.productConfiguration ? this.productConfiguration.extensionAllowedProposedApi : []; }
|
|
||||||
|
|
||||||
get uiExtensions(): readonly string[] | undefined { return this.productConfiguration ? this.productConfiguration.uiExtensions : undefined; }
|
|
||||||
|
|
||||||
get enableTelemetry(): boolean { return false; }
|
|
||||||
|
|
||||||
get sendASmile(): { reportIssueUrl: string, requestFeatureUrl: string } | undefined { return this.productConfiguration ? this.productConfiguration.sendASmile : undefined; }
|
|
||||||
|
|
||||||
get extensionsGallery() { return this.productConfiguration ? this.productConfiguration.extensionsGallery : undefined; }
|
|
||||||
|
|
||||||
get settingsSearchBuildId(): number | undefined { return this.productConfiguration ? this.productConfiguration.settingsSearchBuildId : undefined; }
|
|
||||||
|
|
||||||
get settingsSearchUrl(): string | undefined { return this.productConfiguration ? this.productConfiguration.settingsSearchUrl : undefined; }
|
|
||||||
|
|
||||||
get experimentsUrl(): string | undefined { return this.productConfiguration ? this.productConfiguration.experimentsUrl : undefined; }
|
|
||||||
|
|
||||||
get extensionKeywords(): { [extension: string]: readonly string[]; } | undefined { return this.productConfiguration ? this.productConfiguration.extensionKeywords : undefined; }
|
|
||||||
|
|
||||||
get extensionAllowedBadgeProviders(): readonly string[] | undefined { return this.productConfiguration ? this.productConfiguration.extensionAllowedBadgeProviders : undefined; }
|
|
||||||
|
|
||||||
get aiConfig() { return this.productConfiguration ? this.productConfiguration.aiConfig : undefined; }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,40 +11,7 @@ export interface IProductService {
|
|||||||
|
|
||||||
_serviceBrand: ServiceIdentifier<any>;
|
_serviceBrand: ServiceIdentifier<any>;
|
||||||
|
|
||||||
readonly version: string;
|
readonly productConfiguration: IProductConfiguration;
|
||||||
readonly vscodeVersion: string; // {{SQL CARBON EDIT}} add vscode version
|
|
||||||
readonly recommendedExtensionsByScenario: { [area: string]: Array<string> }; // {{SQL CARBON EDIT}} add getter
|
|
||||||
readonly commit?: string;
|
|
||||||
readonly date?: string;
|
|
||||||
|
|
||||||
readonly nameLong: string;
|
|
||||||
readonly urlProtocol: string;
|
|
||||||
readonly extensionAllowedProposedApi: readonly string[];
|
|
||||||
readonly uiExtensions?: readonly string[];
|
|
||||||
|
|
||||||
readonly enableTelemetry: boolean;
|
|
||||||
readonly extensionsGallery?: {
|
|
||||||
readonly serviceUrl: string;
|
|
||||||
readonly itemUrl: string;
|
|
||||||
readonly controlUrl: string;
|
|
||||||
readonly recommendationsUrl: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
readonly sendASmile?: {
|
|
||||||
readonly reportIssueUrl: string;
|
|
||||||
readonly requestFeatureUrl: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
readonly settingsSearchBuildId?: number;
|
|
||||||
readonly settingsSearchUrl?: string;
|
|
||||||
|
|
||||||
readonly experimentsUrl?: string;
|
|
||||||
readonly extensionKeywords?: { [extension: string]: readonly string[]; };
|
|
||||||
readonly extensionAllowedBadgeProviders?: readonly string[];
|
|
||||||
|
|
||||||
readonly aiConfig?: {
|
|
||||||
readonly asimovKey: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IProductConfiguration {
|
export interface IProductConfiguration {
|
||||||
@@ -76,10 +43,12 @@ export interface IProductConfiguration {
|
|||||||
readonly controlUrl: string;
|
readonly controlUrl: string;
|
||||||
readonly recommendationsUrl: string;
|
readonly recommendationsUrl: string;
|
||||||
};
|
};
|
||||||
extensionTips: { [id: string]: string; };
|
readonly extensionTips: { [id: string]: string; };
|
||||||
recommendedExtensions: string[]; // {{SQL CARBON EDIT}}
|
readonly recommendedExtensions: string[]; // {{SQL CARBON EDIT}}
|
||||||
recommendedExtensionsByScenario: { [area: string]: Array<string> }; // {{SQL CARBON EDIT}}
|
readonly recommendedExtensionsByScenario: { [area: string]: Array<string> }; // {{SQL CARBON EDIT}}
|
||||||
extensionImportantTips: { [id: string]: { name: string; pattern: string; isExtensionPack?: boolean }; };
|
readonly vscodeVersion: string; // {{SQL CARBON EDIT}} add vscode version
|
||||||
|
readonly gettingStartedUrl: string; // {SQL CARBON EDIT}
|
||||||
|
readonly extensionImportantTips: { [id: string]: { name: string; pattern: string; isExtensionPack?: boolean }; };
|
||||||
readonly exeBasedExtensionTips: { [id: string]: IExeBasedExtensionTip; };
|
readonly exeBasedExtensionTips: { [id: string]: IExeBasedExtensionTip; };
|
||||||
readonly extensionKeywords: { [extension: string]: readonly string[]; };
|
readonly extensionKeywords: { [extension: string]: readonly string[]; };
|
||||||
readonly extensionAllowedBadgeProviders: readonly string[];
|
readonly extensionAllowedBadgeProviders: readonly string[];
|
||||||
@@ -100,8 +69,6 @@ export interface IProductConfiguration {
|
|||||||
};
|
};
|
||||||
readonly documentationUrl: string;
|
readonly documentationUrl: string;
|
||||||
readonly releaseNotesUrl: string;
|
readonly releaseNotesUrl: string;
|
||||||
readonly gettingStartedUrl: string; // {SQL CARBON EDIT}
|
|
||||||
readonly vscodeVersion: string; // {SQL CARBON EDIT}
|
|
||||||
readonly keyboardShortcutsUrlMac: string;
|
readonly keyboardShortcutsUrlMac: string;
|
||||||
readonly keyboardShortcutsUrlLinux: string;
|
readonly keyboardShortcutsUrlLinux: string;
|
||||||
readonly keyboardShortcutsUrlWin: string;
|
readonly keyboardShortcutsUrlWin: string;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { IProductService } from 'vs/platform/product/common/product';
|
import { IProductService, IProductConfiguration } from 'vs/platform/product/common/product';
|
||||||
import product from 'vs/platform/product/node/product';
|
import product from 'vs/platform/product/node/product';
|
||||||
import pkg from 'vs/platform/product/node/package';
|
import pkg from 'vs/platform/product/node/package';
|
||||||
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||||
@@ -12,35 +12,12 @@ export class ProductService implements IProductService {
|
|||||||
|
|
||||||
_serviceBrand!: ServiceIdentifier<IProductService>;
|
_serviceBrand!: ServiceIdentifier<IProductService>;
|
||||||
|
|
||||||
get version(): string { return pkg.version; }
|
readonly productConfiguration: IProductConfiguration;
|
||||||
|
|
||||||
get vscodeVersion(): string { return '1.35.0'; } // {{SQL CARBON EDIT}} add vscodeversion
|
constructor() {
|
||||||
|
this.productConfiguration = {
|
||||||
|
...product, ...{ version: pkg.version }, ...{ vscodeVersion: '1.35.0' } // {{SQL CARBON EDIT}} add vscodeversion}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
get recommendedExtensionsByScenario(): { [area: string]: Array<string> } { return product.recommendedExtensionsByScenario; }// {{SQL CARBON EDIT}} add getter
|
|
||||||
|
|
||||||
get commit(): string | undefined { return product.commit; }
|
|
||||||
|
|
||||||
get nameLong(): string { return product.nameLong; }
|
|
||||||
|
|
||||||
get urlProtocol(): string { return product.urlProtocol; }
|
|
||||||
|
|
||||||
get extensionAllowedProposedApi(): readonly string[] { return product.extensionAllowedProposedApi; }
|
|
||||||
|
|
||||||
get uiExtensions(): readonly string[] | undefined { return product.uiExtensions; }
|
|
||||||
|
|
||||||
get enableTelemetry(): boolean { return product.enableTelemetry; }
|
|
||||||
|
|
||||||
get sendASmile(): { reportIssueUrl: string, requestFeatureUrl: string } { return product.sendASmile; }
|
|
||||||
|
|
||||||
get extensionsGallery() { return product.extensionsGallery; }
|
|
||||||
|
|
||||||
get settingsSearchBuildId(): number | undefined { return product.settingsSearchBuildId; }
|
|
||||||
|
|
||||||
get settingsSearchUrl(): string | undefined { return product.settingsSearchUrl; }
|
|
||||||
|
|
||||||
get experimentsUrl(): string | undefined { return product.experimentsUrl; }
|
|
||||||
|
|
||||||
get extensionKeywords(): { [extension: string]: readonly string[]; } | undefined { return product.extensionKeywords; }
|
|
||||||
|
|
||||||
get extensionAllowedBadgeProviders(): readonly string[] | undefined { return product.extensionAllowedBadgeProviders; }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,8 +144,10 @@ export class BrowserStorageService extends Disposable implements IStorageService
|
|||||||
// Signal as event so that clients can still store data
|
// Signal as event so that clients can still store data
|
||||||
this._onWillSaveState.fire({ reason: WillSaveStateReason.SHUTDOWN });
|
this._onWillSaveState.fire({ reason: WillSaveStateReason.SHUTDOWN });
|
||||||
|
|
||||||
// Close DBs
|
// We explicitly do not close our DBs because writing data onBeforeUnload()
|
||||||
this.globalStorage.close();
|
// can result in unexpected results. Namely, it seems that - even though this
|
||||||
this.workspaceStorage.close();
|
// operation is async - sometimes it is being triggered on unload and
|
||||||
|
// succeeds. Often though, the DBs turn out to be empty because the write
|
||||||
|
// never had a chance to complete.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,17 +13,14 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||||
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
|
import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService';
|
||||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||||
|
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
|
||||||
export class WindowsService implements IWindowsService {
|
export class WindowsService implements IWindowsService {
|
||||||
|
|
||||||
_serviceBrand: any;
|
_serviceBrand!: ServiceIdentifier<any>;
|
||||||
|
|
||||||
private channel: IChannel;
|
private channel: IChannel;
|
||||||
|
|
||||||
constructor(@IMainProcessService mainProcessService: IMainProcessService) {
|
|
||||||
this.channel = mainProcessService.getChannel('windows');
|
|
||||||
}
|
|
||||||
|
|
||||||
get onWindowOpen(): Event<number> { return this.channel.listen('onWindowOpen'); }
|
get onWindowOpen(): Event<number> { return this.channel.listen('onWindowOpen'); }
|
||||||
get onWindowFocus(): Event<number> { return this.channel.listen('onWindowFocus'); }
|
get onWindowFocus(): Event<number> { return this.channel.listen('onWindowFocus'); }
|
||||||
get onWindowBlur(): Event<number> { return this.channel.listen('onWindowBlur'); }
|
get onWindowBlur(): Event<number> { return this.channel.listen('onWindowBlur'); }
|
||||||
@@ -31,6 +28,10 @@ export class WindowsService implements IWindowsService {
|
|||||||
get onWindowUnmaximize(): Event<number> { return this.channel.listen('onWindowUnmaximize'); }
|
get onWindowUnmaximize(): Event<number> { return this.channel.listen('onWindowUnmaximize'); }
|
||||||
get onRecentlyOpenedChange(): Event<void> { return this.channel.listen('onRecentlyOpenedChange'); }
|
get onRecentlyOpenedChange(): Event<void> { return this.channel.listen('onRecentlyOpenedChange'); }
|
||||||
|
|
||||||
|
constructor(@IMainProcessService mainProcessService: IMainProcessService) {
|
||||||
|
this.channel = mainProcessService.getChannel('windows');
|
||||||
|
}
|
||||||
|
|
||||||
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void> {
|
||||||
return this.channel.call('pickFileFolderAndOpen', options);
|
return this.channel.call('pickFileFolderAndOpen', options);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class EditorWebviewZone implements IViewZone {
|
|||||||
readonly afterColumn: number;
|
readonly afterColumn: number;
|
||||||
readonly heightInLines: number;
|
readonly heightInLines: number;
|
||||||
|
|
||||||
private _id?: number;
|
private _id?: string;
|
||||||
// suppressMouseDown?: boolean | undefined;
|
// suppressMouseDown?: boolean | undefined;
|
||||||
// heightInPx?: number | undefined;
|
// heightInPx?: number | undefined;
|
||||||
// minWidthInPx?: number | undefined;
|
// minWidthInPx?: number | undefined;
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
if (MainThreadWebviews.standardSupportedLinkSchemes.has(link.scheme)) {
|
if (MainThreadWebviews.standardSupportedLinkSchemes.has(link.scheme)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (this._productService.urlProtocol === link.scheme) {
|
if (this._productService.productConfiguration.urlProtocol === link.scheme) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return !!webview.webview.contentOptions.enableCommandUris && link.scheme === 'command';
|
return !!webview.webview.contentOptions.enableCommandUris && link.scheme === 'command';
|
||||||
|
|||||||
@@ -6,12 +6,13 @@
|
|||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||||
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
|
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||||
import { ExtHostContext, ExtHostWindowShape, IExtHostContext, MainContext, MainThreadWindowShape, IOpenUriOptions } from '../common/extHost.protocol';
|
import { ExtHostContext, ExtHostWindowShape, IExtHostContext, MainContext, MainThreadWindowShape, IOpenUriOptions } from '../common/extHost.protocol';
|
||||||
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
|
||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
import { extractLocalHostUriMetaDataForPortMapping } from 'vs/workbench/contrib/webview/common/portMapping';
|
import { extractLocalHostUriMetaDataForPortMapping } from 'vs/workbench/contrib/webview/common/portMapping';
|
||||||
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
|
|
||||||
@extHostNamedCustomer(MainContext.MainThreadWindow)
|
@extHostNamedCustomer(MainContext.MainThreadWindow)
|
||||||
export class MainThreadWindow implements MainThreadWindowShape {
|
export class MainThreadWindow implements MainThreadWindowShape {
|
||||||
@@ -23,7 +24,7 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
|||||||
constructor(
|
constructor(
|
||||||
extHostContext: IExtHostContext,
|
extHostContext: IExtHostContext,
|
||||||
@IWindowService private readonly windowService: IWindowService,
|
@IWindowService private readonly windowService: IWindowService,
|
||||||
@IWindowsService private readonly windowsService: IWindowsService,
|
@IOpenerService private readonly openerService: IOpenerService,
|
||||||
@ITunnelService private readonly tunnelService: ITunnelService,
|
@ITunnelService private readonly tunnelService: ITunnelService,
|
||||||
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
|
||||||
) {
|
) {
|
||||||
@@ -58,7 +59,7 @@ export class MainThreadWindow implements MainThreadWindowShape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.windowsService.openExternal(encodeURI(uri.toString(true)));
|
return this.openerService.openExternal(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
|
private getOrCreateTunnel(remotePort: number): Promise<RemoteTunnel> | undefined {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
|||||||
import { VIEWLET_ID as EXPLORER } from 'vs/workbench/contrib/files/common/files';
|
import { VIEWLET_ID as EXPLORER } from 'vs/workbench/contrib/files/common/files';
|
||||||
import { VIEWLET_ID as SCM } from 'vs/workbench/contrib/scm/common/scm';
|
import { VIEWLET_ID as SCM } from 'vs/workbench/contrib/scm/common/scm';
|
||||||
import { VIEWLET_ID as DEBUG } from 'vs/workbench/contrib/debug/common/debug';
|
import { VIEWLET_ID as DEBUG } from 'vs/workbench/contrib/debug/common/debug';
|
||||||
|
import { VIEWLET_ID as REMOTE } from 'vs/workbench/contrib/remote/common/remote.contribution';
|
||||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from 'vs/workbench/browser/viewlet';
|
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from 'vs/workbench/browser/viewlet';
|
||||||
@@ -79,6 +80,7 @@ interface IUserFriendlyViewDescriptor {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
when?: string;
|
when?: string;
|
||||||
|
group?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewDescriptor: IJSONSchema = {
|
const viewDescriptor: IJSONSchema = {
|
||||||
@@ -99,6 +101,27 @@ const viewDescriptor: IJSONSchema = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const nestableViewDescriptor: IJSONSchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
description: localize('vscode.extension.contributes.view.id', 'Identifier of the view. Use this to register a data provider through `vscode.window.registerTreeDataProviderForView` API. Also to trigger activating your extension by registering `onView:${id}` event to `activationEvents`.'),
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
description: localize('vscode.extension.contributes.view.name', 'The human-readable name of the view. Will be shown'),
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
when: {
|
||||||
|
description: localize('vscode.extension.contributes.view.when', 'Condition which must be true to show this view'),
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
group: {
|
||||||
|
description: localize('vscode.extension.contributes.view.group', 'Nested group in the viewlet'),
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
const viewsContribution: IJSONSchema = {
|
const viewsContribution: IJSONSchema = {
|
||||||
description: localize('vscode.extension.contributes.views', "Contributes views to the editor"),
|
description: localize('vscode.extension.contributes.views', "Contributes views to the editor"),
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@@ -126,6 +149,12 @@ const viewsContribution: IJSONSchema = {
|
|||||||
type: 'array',
|
type: 'array',
|
||||||
items: viewDescriptor,
|
items: viewDescriptor,
|
||||||
default: []
|
default: []
|
||||||
|
},
|
||||||
|
'remote': {
|
||||||
|
description: localize('views.remote', "Contributes views to Remote container in the Activity bar"),
|
||||||
|
type: 'array',
|
||||||
|
items: nestableViewDescriptor,
|
||||||
|
default: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
additionalProperties: {
|
additionalProperties: {
|
||||||
@@ -376,6 +405,12 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const order = ExtensionIdentifier.equals(extension.description.identifier, container.extensionId)
|
||||||
|
? index + 1
|
||||||
|
: container.orderDelegate
|
||||||
|
? container.orderDelegate.getOrder(item.group)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const viewDescriptor = <ICustomViewDescriptor>{
|
const viewDescriptor = <ICustomViewDescriptor>{
|
||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
@@ -384,9 +419,10 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
|||||||
canToggleVisibility: true,
|
canToggleVisibility: true,
|
||||||
collapsed: this.showCollapsed(container),
|
collapsed: this.showCollapsed(container),
|
||||||
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name, container),
|
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name, container),
|
||||||
order: ExtensionIdentifier.equals(extension.description.identifier, container.extensionId) ? index + 1 : undefined,
|
order: order,
|
||||||
extensionId: extension.description.identifier,
|
extensionId: extension.description.identifier,
|
||||||
originalContainerId: entry.key
|
originalContainerId: entry.key,
|
||||||
|
group: item.group
|
||||||
};
|
};
|
||||||
|
|
||||||
viewIds.push(viewDescriptor.id);
|
viewIds.push(viewDescriptor.id);
|
||||||
@@ -440,6 +476,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
|||||||
case 'explorer': return this.viewContainersRegistry.get(EXPLORER);
|
case 'explorer': return this.viewContainersRegistry.get(EXPLORER);
|
||||||
case 'debug': return this.viewContainersRegistry.get(DEBUG);
|
case 'debug': return this.viewContainersRegistry.get(DEBUG);
|
||||||
case 'scm': return this.viewContainersRegistry.get(SCM);
|
case 'scm': return this.viewContainersRegistry.get(SCM);
|
||||||
|
case 'remote': return this.viewContainersRegistry.get(REMOTE);
|
||||||
default: return this.viewContainersRegistry.get(`workbench.view.extension.${value}`);
|
default: return this.viewContainersRegistry.get(`workbench.view.extension.${value}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import * as path from 'vs/base/common/path';
|
import * as path from 'vs/base/common/path';
|
||||||
import { originalFSPath } from 'vs/base/common/resources';
|
import { originalFSPath, joinPath } from 'vs/base/common/resources';
|
||||||
import { Barrier } from 'vs/base/common/async';
|
import { Barrier } from 'vs/base/common/async';
|
||||||
import { dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
import { dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { TernarySearchTree } from 'vs/base/common/map';
|
import { TernarySearchTree } from 'vs/base/common/map';
|
||||||
@@ -332,14 +332,14 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
|||||||
|
|
||||||
const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
|
const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
|
||||||
return Promise.all<any>([
|
return Promise.all<any>([
|
||||||
this._loadCommonJSModule(extensionDescription.main, activationTimesBuilder),
|
this._loadCommonJSModule(joinPath(extensionDescription.extensionLocation, extensionDescription.main), activationTimesBuilder),
|
||||||
this._loadExtensionContext(extensionDescription)
|
this._loadExtensionContext(extensionDescription)
|
||||||
]).then(values => {
|
]).then(values => {
|
||||||
return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, <IExtensionModule>values[0], <IExtensionContext>values[1], activationTimesBuilder);
|
return AbstractExtHostExtensionService._callActivate(this._logService, extensionDescription.identifier, <IExtensionModule>values[0], <IExtensionContext>values[1], activationTimesBuilder);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract _loadCommonJSModule<T>(modulePath: string, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T>;
|
protected abstract _loadCommonJSModule<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T>;
|
||||||
|
|
||||||
private _loadExtensionContext(extensionDescription: IExtensionDescription): Promise<vscode.ExtensionContext> {
|
private _loadExtensionContext(extensionDescription: IExtensionDescription): Promise<vscode.ExtensionContext> {
|
||||||
|
|
||||||
@@ -536,7 +536,7 @@ export abstract class AbstractExtHostExtensionService implements ExtHostExtensio
|
|||||||
let testRunner: ITestRunner | INewTestRunner | undefined;
|
let testRunner: ITestRunner | INewTestRunner | undefined;
|
||||||
let requireError: Error | undefined;
|
let requireError: Error | undefined;
|
||||||
try {
|
try {
|
||||||
testRunner = await this._loadCommonJSModule(extensionTestsPath, new ExtensionActivationTimesBuilder(false));
|
testRunner = await this._loadCommonJSModule(URI.file(extensionTestsPath), new ExtensionActivationTimesBuilder(false));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
requireError = error;
|
requireError = error;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ import { connectProxyResolver } from 'vs/workbench/services/extensions/node/prox
|
|||||||
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
||||||
import { ExtHostDownloadService } from 'vs/workbench/api/node/extHostDownloadService';
|
import { ExtHostDownloadService } from 'vs/workbench/api/node/extHostDownloadService';
|
||||||
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
|
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
|
||||||
import { createAzdataApiFactory, createSqlopsApiFactory } from 'sql/workbench/api/common/sqlExtHost.api.impl'; // {{SQL CARBON EDIT}} use our extension initalizer
|
import { createAzdataApiFactory, createSqlopsApiFactory } from 'sql/workbench/api/common/sqlExtHost.api.impl'; // {{SQL CARBON EDIT}} use our extension initalizer
|
||||||
import { AzdataNodeModuleFactory, SqlopsNodeModuleFactory } from 'sql/workbench/api/node/extHostRequireInterceptor'; // {{SQL CARBON EDIT}} use our extension initalizer
|
import { AzdataNodeModuleFactory, SqlopsNodeModuleFactory } from 'sql/workbench/api/node/extHostRequireInterceptor'; // {{SQL CARBON EDIT}} use our extension initalizer
|
||||||
|
|
||||||
@@ -61,12 +64,15 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _loadCommonJSModule<T>(modulePath: string, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
protected _loadCommonJSModule<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
||||||
|
if (module.scheme !== Schemas.file) {
|
||||||
|
throw new Error(`Cannot load URI: '${module}', must be of file-scheme`);
|
||||||
|
}
|
||||||
let r: T | null = null;
|
let r: T | null = null;
|
||||||
activationTimesBuilder.codeLoadingStart();
|
activationTimesBuilder.codeLoadingStart();
|
||||||
this._logService.info(`ExtensionService#loadCommonJSModule ${modulePath}`);
|
this._logService.info(`ExtensionService#loadCommonJSModule ${module.toString(true)}`);
|
||||||
try {
|
try {
|
||||||
r = require.__$__nodeRequire<T>(modulePath);
|
r = require.__$__nodeRequire<T>(module.fsPath);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Promise.reject(e);
|
return Promise.reject(e);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -6,13 +6,16 @@
|
|||||||
import { createApiFactoryAndRegisterActors, IExtensionApiFactory } from 'vs/workbench/api/common/extHost.api.impl';
|
import { createApiFactoryAndRegisterActors, IExtensionApiFactory } from 'vs/workbench/api/common/extHost.api.impl';
|
||||||
import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator';
|
import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||||
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
||||||
import { endsWith } from 'vs/base/common/strings';
|
import { endsWith, startsWith } from 'vs/base/common/strings';
|
||||||
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { TernarySearchTree } from 'vs/base/common/map';
|
import { TernarySearchTree } from 'vs/base/common/map';
|
||||||
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
import { joinPath } from 'vs/base/common/resources';
|
||||||
|
|
||||||
class ApiInstances {
|
class ApiInstances {
|
||||||
|
|
||||||
@@ -52,11 +55,8 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
|
|||||||
this._apiInstances = new ApiInstances(apiFactory, extensionPath, this._registry, configProvider);
|
this._apiInstances = new ApiInstances(apiFactory, extensionPath, this._registry, configProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected _loadCommonJSModule<T>(modulePath: string, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
protected _loadCommonJSModule<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
||||||
|
|
||||||
// make sure modulePath ends with `.js`
|
|
||||||
const suffix = '.js';
|
|
||||||
modulePath = endsWith(modulePath, suffix) ? modulePath : modulePath + suffix;
|
|
||||||
|
|
||||||
interface FakeCommonJSSelf {
|
interface FakeCommonJSSelf {
|
||||||
module?: object;
|
module?: object;
|
||||||
@@ -69,30 +69,66 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
|
|||||||
|
|
||||||
// FAKE commonjs world that only collects exports
|
// FAKE commonjs world that only collects exports
|
||||||
const patchSelf: FakeCommonJSSelf = <any>self;
|
const patchSelf: FakeCommonJSSelf = <any>self;
|
||||||
const module = { exports: {} };
|
|
||||||
patchSelf.module = module;
|
|
||||||
patchSelf.exports = module.exports;
|
|
||||||
patchSelf.window = self; // <- that's improper but might help extensions that aren't authored correctly
|
patchSelf.window = self; // <- that's improper but might help extensions that aren't authored correctly
|
||||||
|
|
||||||
// FAKE require function that only works for the vscode-module
|
// FAKE require function that only works for the vscode-module
|
||||||
patchSelf.require = (module: string) => {
|
const moduleStack: URI[] = [];
|
||||||
if (module !== 'vscode') {
|
patchSelf.require = (mod: string) => {
|
||||||
throw new Error(`Cannot load module '${module}'`);
|
const parent = moduleStack[moduleStack.length - 1];
|
||||||
|
if (mod === 'vscode') {
|
||||||
|
return this._apiInstances!.get(parent.fsPath);
|
||||||
}
|
}
|
||||||
return this._apiInstances!.get(modulePath);
|
if (!startsWith(mod, '.')) {
|
||||||
|
throw new Error(`Cannot load module '${mod}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const exports = Object.create(null);
|
||||||
|
patchSelf.module = { exports };
|
||||||
|
patchSelf.exports = exports;
|
||||||
|
|
||||||
|
const next = joinPath(parent, '..', ensureSuffix(mod, '.js'));
|
||||||
|
moduleStack.push(next);
|
||||||
|
importScripts(asDomUri(next).toString(true));
|
||||||
|
moduleStack.pop();
|
||||||
|
|
||||||
|
return exports;
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
activationTimesBuilder.codeLoadingStart();
|
activationTimesBuilder.codeLoadingStart();
|
||||||
importScripts(modulePath);
|
|
||||||
|
const exports = Object.create(null);
|
||||||
|
patchSelf.module = { exports };
|
||||||
|
patchSelf.exports = exports;
|
||||||
|
|
||||||
|
module = module.with({ path: ensureSuffix(module.path, '.js') });
|
||||||
|
moduleStack.push(module);
|
||||||
|
|
||||||
|
importScripts(asDomUri(module).toString(true));
|
||||||
|
moduleStack.pop();
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
activationTimesBuilder.codeLoadingStop();
|
activationTimesBuilder.codeLoadingStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(module.exports as T);
|
return Promise.resolve<T>(exports);
|
||||||
}
|
}
|
||||||
|
|
||||||
async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
|
async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
|
||||||
throw new Error('Not supported');
|
throw new Error('Not supported');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo@joh this is a copy of `dom.ts#asDomUri`
|
||||||
|
function asDomUri(uri: URI): URI {
|
||||||
|
if (Schemas.vscodeRemote === uri.scheme) {
|
||||||
|
// rewrite vscode-remote-uris to uris of the window location
|
||||||
|
// so that they can be intercepted by the service worker
|
||||||
|
return URI.parse(window.location.href).with({ path: '/vscode-remote', query: JSON.stringify(uri) });
|
||||||
|
}
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureSuffix(path: string, suffix: string): string {
|
||||||
|
return endsWith(path, suffix) ? path : path + suffix;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1177,10 +1177,12 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private createGridDescriptor(): ISerializedGrid {
|
private createGridDescriptor(): ISerializedGrid {
|
||||||
const width = this.storageService.getNumber(Storage.GRID_WIDTH, StorageScope.GLOBAL, 600);
|
const workbenchDimensions = getClientArea(this.parent);
|
||||||
const height = this.storageService.getNumber(Storage.GRID_HEIGHT, StorageScope.GLOBAL, 400);
|
const width = this.storageService.getNumber(Storage.GRID_WIDTH, StorageScope.GLOBAL, workbenchDimensions.width);
|
||||||
const sideBarSize = this.storageService.getNumber(Storage.SIDEBAR_SIZE, StorageScope.GLOBAL, 300);
|
const height = this.storageService.getNumber(Storage.GRID_HEIGHT, StorageScope.GLOBAL, workbenchDimensions.height);
|
||||||
const panelSize = this.storageService.getNumber(Storage.PANEL_SIZE, StorageScope.GLOBAL, 300);
|
// At some point, we will not fall back to old keys from legacy layout, but for now, let's migrate the keys
|
||||||
|
const sideBarSize = this.storageService.getNumber(Storage.SIDEBAR_SIZE, StorageScope.GLOBAL, this.storageService.getNumber('workbench.sidebar.width', StorageScope.GLOBAL, Math.min(workbenchDimensions.width / 4, 300))!);
|
||||||
|
const panelSize = this.storageService.getNumber(Storage.PANEL_SIZE, StorageScope.GLOBAL, this.storageService.getNumber(this.state.panel.position === Position.BOTTOM ? 'workbench.panel.height' : 'workbench.panel.width', StorageScope.GLOBAL, workbenchDimensions.height / 3));
|
||||||
|
|
||||||
const titleBarHeight = this.titleBarPartView.minimumHeight;
|
const titleBarHeight = this.titleBarPartView.minimumHeight;
|
||||||
const statusBarHeight = this.statusBarPartView.minimumHeight;
|
const statusBarHeight = this.statusBarPartView.minimumHeight;
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export interface IEditorOpeningEvent extends IEditorIdentifier {
|
|||||||
* Allows to prevent the opening of an editor by providing a callback
|
* Allows to prevent the opening of an editor by providing a callback
|
||||||
* that will be executed instead. By returning another editor promise
|
* that will be executed instead. By returning another editor promise
|
||||||
* it is possible to override the opening with another editor. It is ok
|
* it is possible to override the opening with another editor. It is ok
|
||||||
* to return a promise that resolves to NULL to prevent the opening
|
* to return a promise that resolves to `undefined` to prevent the opening
|
||||||
* alltogether.
|
* alltogether.
|
||||||
*/
|
*/
|
||||||
prevent(callback: () => undefined | Promise<IEditor | undefined>): void;
|
prevent(callback: () => undefined | Promise<IEditor | undefined>): void;
|
||||||
|
|||||||
@@ -382,7 +382,19 @@ export class ContributableViewsModel extends Disposable {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (this.getViewOrder(a) - this.getViewOrder(b)) || (a.id < b.id ? -1 : 1);
|
return (this.getViewOrder(a) - this.getViewOrder(b)) || this.getGroupOrderResult(a, b) || (a.id < b.id ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getGroupOrderResult(a: IViewDescriptor, b: IViewDescriptor) {
|
||||||
|
if (!a.group || !b.group) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.group === b.group) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.group < b.group ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getViewOrder(viewDescriptor: IViewDescriptor): number {
|
private getViewOrder(viewDescriptor: IViewDescriptor): number {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
|||||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
||||||
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
|
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
|
||||||
// tslint:disable-next-line: import-patterns
|
// tslint:disable-next-line: import-patterns
|
||||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||||
import { addDisposableListener, EventType, windowOpenNoOpener } from 'vs/base/browser/dom';
|
import { addDisposableListener, EventType, windowOpenNoOpener } from 'vs/base/browser/dom';
|
||||||
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { pathsToEditors } from 'vs/workbench/common/editor';
|
import { pathsToEditors } from 'vs/workbench/common/editor';
|
||||||
@@ -31,14 +31,14 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
|||||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||||
import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage';
|
import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage';
|
||||||
// tslint:disable-next-line: import-patterns
|
|
||||||
import { IExperimentService, IExperiment, ExperimentActionType, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService';
|
|
||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||||
import { IProductService } from 'vs/platform/product/common/product';
|
import { IProductService } from 'vs/platform/product/common/product';
|
||||||
import Severity from 'vs/base/common/severity';
|
import Severity from 'vs/base/common/severity';
|
||||||
import { localize } from 'vs/nls';
|
import { localize } from 'vs/nls';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
|
// tslint:disable-next-line: import-patterns
|
||||||
|
import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats';
|
||||||
|
|
||||||
//#region Extension Tips
|
//#region Extension Tips
|
||||||
|
|
||||||
@@ -751,13 +751,13 @@ export class SimpleWindowsService implements IWindowsService {
|
|||||||
async openAboutDialog(): Promise<void> {
|
async openAboutDialog(): Promise<void> {
|
||||||
const detail = localize('aboutDetail',
|
const detail = localize('aboutDetail',
|
||||||
"Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
|
"Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
|
||||||
this.productService.version || 'Unknown',
|
this.productService.productConfiguration.version || 'Unknown',
|
||||||
this.productService.commit || 'Unknown',
|
this.productService.productConfiguration.commit || 'Unknown',
|
||||||
this.productService.date || 'Unknown',
|
this.productService.productConfiguration.date || 'Unknown',
|
||||||
navigator.userAgent
|
navigator.userAgent
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = await this.dialogService.show(Severity.Info, this.productService.nameLong, [localize('copy', "Copy"), localize('ok', "OK")], { detail });
|
const result = await this.dialogService.show(Severity.Info, this.productService.productConfiguration.nameLong, [localize('copy', "Copy"), localize('ok', "OK")], { detail });
|
||||||
|
|
||||||
if (result === 0) {
|
if (result === 0) {
|
||||||
this.clipboardService.writeText(detail);
|
this.clipboardService.writeText(detail);
|
||||||
@@ -855,33 +855,26 @@ registerSingleton(ITunnelService, SimpleTunnelService);
|
|||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region experiments
|
//#region workspace stats
|
||||||
|
|
||||||
|
class WorkspaceStatsService implements IWorkspaceStatsService {
|
||||||
|
|
||||||
class ExperimentService implements IExperimentService {
|
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|
||||||
async getExperimentById(id: string): Promise<IExperiment> {
|
getTags(): Promise<Tags> {
|
||||||
return {
|
return Promise.resolve({});
|
||||||
enabled: false,
|
|
||||||
id: '',
|
|
||||||
state: ExperimentState.NoRun
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getExperimentsByType(type: ExperimentActionType): Promise<IExperiment[]> {
|
getTelemetryWorkspaceId(workspace: IWorkspace, state: WorkbenchState): string | undefined {
|
||||||
return [];
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCuratedExtensionsList(curatedExtensionsKey: string): Promise<string[]> {
|
getHashedRemotesFromUri(workspaceUri: URI, stripEndingDotGit?: boolean): Promise<string[]> {
|
||||||
return [];
|
return Promise.resolve([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
markAsCompleted(experimentId: string): void { }
|
|
||||||
|
|
||||||
onExperimentEnabled: Event<IExperiment> = Event.None;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerSingleton(IExperimentService, ExperimentService);
|
registerSingleton(IWorkspaceStatsService, WorkspaceStatsService);
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export interface IViewContainersRegistry {
|
|||||||
*
|
*
|
||||||
* @returns the registered ViewContainer.
|
* @returns the registered ViewContainer.
|
||||||
*/
|
*/
|
||||||
registerViewContainer(id: string, hideIfEmpty?: boolean, extensionId?: ExtensionIdentifier): ViewContainer;
|
registerViewContainer(id: string, hideIfEmpty?: boolean, extensionId?: ExtensionIdentifier, viewOrderDelegate?: ViewOrderDelegate): ViewContainer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deregisters the given view container
|
* Deregisters the given view container
|
||||||
@@ -67,8 +67,12 @@ export interface IViewContainersRegistry {
|
|||||||
get(id: string): ViewContainer | undefined;
|
get(id: string): ViewContainer | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ViewOrderDelegate {
|
||||||
|
getOrder(group?: string): number | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export class ViewContainer {
|
export class ViewContainer {
|
||||||
protected constructor(readonly id: string, readonly hideIfEmpty: boolean, readonly extensionId?: ExtensionIdentifier) { }
|
protected constructor(readonly id: string, readonly hideIfEmpty: boolean, readonly extensionId?: ExtensionIdentifier, readonly orderDelegate?: ViewOrderDelegate) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewContainersRegistryImpl extends Disposable implements IViewContainersRegistry {
|
class ViewContainersRegistryImpl extends Disposable implements IViewContainersRegistry {
|
||||||
@@ -85,7 +89,7 @@ class ViewContainersRegistryImpl extends Disposable implements IViewContainersRe
|
|||||||
return values(this.viewContainers);
|
return values(this.viewContainers);
|
||||||
}
|
}
|
||||||
|
|
||||||
registerViewContainer(id: string, hideIfEmpty?: boolean, extensionId?: ExtensionIdentifier): ViewContainer {
|
registerViewContainer(id: string, hideIfEmpty?: boolean, extensionId?: ExtensionIdentifier, viewOrderDelegate?: ViewOrderDelegate): ViewContainer {
|
||||||
const existing = this.viewContainers.get(id);
|
const existing = this.viewContainers.get(id);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
return existing;
|
return existing;
|
||||||
@@ -93,7 +97,7 @@ class ViewContainersRegistryImpl extends Disposable implements IViewContainersRe
|
|||||||
|
|
||||||
const viewContainer = new class extends ViewContainer {
|
const viewContainer = new class extends ViewContainer {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(id, !!hideIfEmpty, extensionId);
|
super(id, !!hideIfEmpty, extensionId, viewOrderDelegate);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.viewContainers.set(id, viewContainer);
|
this.viewContainers.set(id, viewContainer);
|
||||||
@@ -126,6 +130,8 @@ export interface IViewDescriptor {
|
|||||||
|
|
||||||
readonly when?: ContextKeyExpr;
|
readonly when?: ContextKeyExpr;
|
||||||
|
|
||||||
|
readonly group?: string;
|
||||||
|
|
||||||
readonly order?: number;
|
readonly order?: number;
|
||||||
|
|
||||||
readonly weight?: number;
|
readonly weight?: number;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import 'vs/css!./accessibility';
|
|||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
|
import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';
|
||||||
import { renderFormattedText } from 'vs/base/browser/htmlContentRenderer';
|
import { renderFormattedText } from 'vs/base/browser/formattedTextRenderer';
|
||||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||||
import { Widget } from 'vs/base/browser/ui/widget';
|
import { Widget } from 'vs/base/browser/ui/widget';
|
||||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer';
|
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|||||||
@@ -543,9 +543,9 @@ class FunctionBreakpointInputRenderer implements IListRenderer<IFunctionBreakpoi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openBreakpointSource(breakpoint: IBreakpoint, sideBySide: boolean, preserveFocus: boolean, debugService: IDebugService, editorService: IEditorService): Promise<IEditor | null> {
|
export function openBreakpointSource(breakpoint: IBreakpoint, sideBySide: boolean, preserveFocus: boolean, debugService: IDebugService, editorService: IEditorService): Promise<IEditor | undefined> {
|
||||||
if (breakpoint.uri.scheme === DEBUG_SCHEME && debugService.state === State.Inactive) {
|
if (breakpoint.uri.scheme === DEBUG_SCHEME && debugService.state === State.Inactive) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
const selection = breakpoint.endLineNumber ? {
|
const selection = breakpoint.endLineNumber ? {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/c
|
|||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
|
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||||
|
|
||||||
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
||||||
jsonRegistry.registerSchema(launchSchemaId, launchSchema);
|
jsonRegistry.registerSchema(launchSchemaId, launchSchema);
|
||||||
@@ -577,7 +578,7 @@ class Launch extends AbstractLaunch implements ILaunch {
|
|||||||
pinned: created,
|
pinned: created,
|
||||||
revealIfVisible: true
|
revealIfVisible: true
|
||||||
},
|
},
|
||||||
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(editor => ({ editor, created })));
|
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(editor => ({ editor: withUndefinedAsNull(editor), created })));
|
||||||
}, (error: Error) => {
|
}, (error: Error) => {
|
||||||
throw new Error(nls.localize('DebugConfig.failed', "Unable to create 'launch.json' file inside the '.vscode' folder ({0}).", error.message));
|
throw new Error(nls.localize('DebugConfig.failed', "Unable to create 'launch.json' file inside the '.vscode' folder ({0}).", error.message));
|
||||||
});
|
});
|
||||||
@@ -613,7 +614,7 @@ class WorkspaceLaunch extends AbstractLaunch implements ILaunch {
|
|||||||
return this.editorService.openEditor({
|
return this.editorService.openEditor({
|
||||||
resource: this.contextService.getWorkspace().configuration!,
|
resource: this.contextService.getWorkspace().configuration!,
|
||||||
options: { preserveFocus }
|
options: { preserveFocus }
|
||||||
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(editor => ({ editor, created: false }));
|
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(editor => ({ editor: withUndefinedAsNull(editor), created: false }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,6 +648,6 @@ class UserLaunch extends AbstractLaunch implements ILaunch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string): Promise<{ editor: IEditor | null, created: boolean }> {
|
openConfigFile(sideBySide: boolean, preserveFocus: boolean, type?: string): Promise<{ editor: IEditor | null, created: boolean }> {
|
||||||
return this.preferencesService.openGlobalSettings(false, { preserveFocus }).then(editor => ({ editor, created: false }));
|
return this.preferencesService.openGlobalSettings(false, { preserveFocus }).then(editor => ({ editor: withUndefinedAsNull(editor), created: false }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ export class DebugSession implements IDebugSession {
|
|||||||
|
|
||||||
return this.raw!.initialize({
|
return this.raw!.initialize({
|
||||||
clientID: 'vscode',
|
clientID: 'vscode',
|
||||||
clientName: this.productService.nameLong,
|
clientName: this.productService.productConfiguration.nameLong,
|
||||||
adapterID: this.configuration.type,
|
adapterID: this.configuration.type,
|
||||||
pathFormat: 'path',
|
pathFormat: 'path',
|
||||||
linesStartAt1: true,
|
linesStartAt1: true,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/
|
|||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { isUri } from 'vs/workbench/contrib/debug/common/debugUtils';
|
import { isUri } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||||
import { ITextEditor } from 'vs/workbench/common/editor';
|
import { ITextEditor } from 'vs/workbench/common/editor';
|
||||||
|
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||||
|
|
||||||
export const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source");
|
export const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source");
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@ export class Source {
|
|||||||
revealInCenterIfOutsideViewport: true,
|
revealInCenterIfOutsideViewport: true,
|
||||||
pinned: pinned || (!preserveFocus && !this.inMemory)
|
pinned: pinned || (!preserveFocus && !this.inMemory)
|
||||||
}
|
}
|
||||||
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
|
}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(withUndefinedAsNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getEncodedDebugData(modelUri: uri): { name: string, path: string, sessionId?: string, sourceReference?: number } {
|
static getEncodedDebugData(modelUri: uri): { name: string, path: string, sessionId?: string, sourceReference?: number } {
|
||||||
|
|||||||
@@ -4,12 +4,11 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
import { IExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService';
|
import { IExperimentService, ExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||||
import { ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
|
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||||
import { ExperimentalPrompts } from 'vs/workbench/contrib/experiments/electron-browser/experimentalPrompt';
|
import { ExperimentalPrompts } from 'vs/workbench/contrib/experiments/browser/experimentalPrompt';
|
||||||
|
|
||||||
registerSingleton(IExperimentService, ExperimentService, true);
|
registerSingleton(IExperimentService, ExperimentService, true);
|
||||||
|
|
||||||
@@ -4,7 +4,23 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Emitter, Event } from 'vs/base/common/event';
|
||||||
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
|
import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
|
||||||
|
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||||
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
|
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||||
|
import { language } from 'vs/base/common/platform';
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { match } from 'vs/base/common/glob';
|
||||||
|
import { IRequestService, asJson } from 'vs/platform/request/common/request';
|
||||||
|
import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/common/textfiles';
|
||||||
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
|
import { distinct } from 'vs/base/common/arrays';
|
||||||
|
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||||
|
import { IProductService } from 'vs/platform/product/common/product';
|
||||||
|
import { IWorkspaceStatsService } from 'vs/workbench/contrib/stats/common/workspaceStats';
|
||||||
|
|
||||||
export const enum ExperimentState {
|
export const enum ExperimentState {
|
||||||
Evaluating,
|
Evaluating,
|
||||||
@@ -57,3 +73,387 @@ export interface IExperimentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const IExperimentService = createDecorator<IExperimentService>('experimentService');
|
export const IExperimentService = createDecorator<IExperimentService>('experimentService');
|
||||||
|
|
||||||
|
interface IExperimentStorageState {
|
||||||
|
enabled: boolean;
|
||||||
|
state: ExperimentState;
|
||||||
|
editCount?: number;
|
||||||
|
lastEditedDate?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRawExperiment {
|
||||||
|
id: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
condition?: {
|
||||||
|
insidersOnly?: boolean;
|
||||||
|
newUser?: boolean;
|
||||||
|
displayLanguage?: string;
|
||||||
|
installedExtensions?: {
|
||||||
|
excludes?: string[];
|
||||||
|
includes?: string[];
|
||||||
|
},
|
||||||
|
fileEdits?: {
|
||||||
|
filePathPattern?: string;
|
||||||
|
workspaceIncludes?: string[];
|
||||||
|
workspaceExcludes?: string[];
|
||||||
|
minEditCount: number;
|
||||||
|
},
|
||||||
|
experimentsPreviouslyRun?: {
|
||||||
|
excludes?: string[];
|
||||||
|
includes?: string[];
|
||||||
|
}
|
||||||
|
userProbability?: number;
|
||||||
|
};
|
||||||
|
action?: IExperimentAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ExperimentService extends Disposable implements IExperimentService {
|
||||||
|
_serviceBrand: any;
|
||||||
|
private _experiments: IExperiment[] = [];
|
||||||
|
private _loadExperimentsPromise: Promise<void>;
|
||||||
|
private _curatedMapping = Object.create(null);
|
||||||
|
|
||||||
|
private readonly _onExperimentEnabled = this._register(new Emitter<IExperiment>());
|
||||||
|
onExperimentEnabled: Event<IExperiment> = this._onExperimentEnabled.event;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@IStorageService private readonly storageService: IStorageService,
|
||||||
|
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||||
|
@ITextFileService private readonly textFileService: ITextFileService,
|
||||||
|
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||||
|
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||||
|
@ILifecycleService private readonly lifecycleService: ILifecycleService,
|
||||||
|
@IRequestService private readonly requestService: IRequestService,
|
||||||
|
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||||
|
@IProductService private readonly productService: IProductService,
|
||||||
|
@IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._loadExperimentsPromise = Promise.resolve(this.lifecycleService.when(LifecyclePhase.Eventually)).then(() => this.loadExperiments());
|
||||||
|
}
|
||||||
|
|
||||||
|
public getExperimentById(id: string): Promise<IExperiment> {
|
||||||
|
return this._loadExperimentsPromise.then(() => {
|
||||||
|
return this._experiments.filter(x => x.id === id)[0];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getExperimentsByType(type: ExperimentActionType): Promise<IExperiment[]> {
|
||||||
|
return this._loadExperimentsPromise.then(() => {
|
||||||
|
if (type === ExperimentActionType.Custom) {
|
||||||
|
return this._experiments.filter(x => x.enabled && (!x.action || x.action.type === type));
|
||||||
|
}
|
||||||
|
return this._experiments.filter(x => x.enabled && x.action && x.action.type === type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCuratedExtensionsList(curatedExtensionsKey: string): Promise<string[]> {
|
||||||
|
return this._loadExperimentsPromise.then(() => {
|
||||||
|
for (const experiment of this._experiments) {
|
||||||
|
if (experiment.enabled
|
||||||
|
&& experiment.state === ExperimentState.Run
|
||||||
|
&& this._curatedMapping[experiment.id]
|
||||||
|
&& this._curatedMapping[experiment.id].curatedExtensionsKey === curatedExtensionsKey) {
|
||||||
|
return this._curatedMapping[experiment.id].curatedExtensionsList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public markAsCompleted(experimentId: string): void {
|
||||||
|
const storageKey = 'experiments.' + experimentId;
|
||||||
|
const experimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), {});
|
||||||
|
experimentState.state = ExperimentState.Complete;
|
||||||
|
this.storageService.store(storageKey, JSON.stringify(experimentState), StorageScope.GLOBAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getExperiments(): Promise<IRawExperiment[]> {
|
||||||
|
if (!this.productService.productConfiguration.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) {
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
return this.requestService.request({ type: 'GET', url: this.productService.productConfiguration.experimentsUrl }, CancellationToken.None).then(context => {
|
||||||
|
if (context.res.statusCode !== 200) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
return asJson(context).then((result: any) => {
|
||||||
|
return result && Array.isArray(result['experiments']) ? result['experiments'] : [];
|
||||||
|
});
|
||||||
|
}, () => Promise.resolve(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadExperiments(): Promise<any> {
|
||||||
|
return this.getExperiments().then(rawExperiments => {
|
||||||
|
// Offline mode
|
||||||
|
if (!rawExperiments) {
|
||||||
|
const allExperimentIdsFromStorage = safeParse(this.storageService.get('allExperiments', StorageScope.GLOBAL), []);
|
||||||
|
if (Array.isArray(allExperimentIdsFromStorage)) {
|
||||||
|
allExperimentIdsFromStorage.forEach(experimentId => {
|
||||||
|
const storageKey = 'experiments.' + experimentId;
|
||||||
|
const experimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), null);
|
||||||
|
if (experimentState) {
|
||||||
|
this._experiments.push({
|
||||||
|
id: experimentId,
|
||||||
|
enabled: experimentState.enabled,
|
||||||
|
state: experimentState.state
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear disbaled/deleted experiments from storage
|
||||||
|
const allExperimentIdsFromStorage = safeParse(this.storageService.get('allExperiments', StorageScope.GLOBAL), []);
|
||||||
|
const enabledExperiments = rawExperiments.filter(experiment => !!experiment.enabled).map(experiment => experiment.id.toLowerCase());
|
||||||
|
if (Array.isArray(allExperimentIdsFromStorage)) {
|
||||||
|
allExperimentIdsFromStorage.forEach(experiment => {
|
||||||
|
if (enabledExperiments.indexOf(experiment) === -1) {
|
||||||
|
this.storageService.remove(`experiments.${experiment}`, StorageScope.GLOBAL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (enabledExperiments.length) {
|
||||||
|
this.storageService.store('allExperiments', JSON.stringify(enabledExperiments), StorageScope.GLOBAL);
|
||||||
|
} else {
|
||||||
|
this.storageService.remove('allExperiments', StorageScope.GLOBAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
const promises = rawExperiments.map(experiment => {
|
||||||
|
const processedExperiment: IExperiment = {
|
||||||
|
id: experiment.id,
|
||||||
|
enabled: !!experiment.enabled,
|
||||||
|
state: !!experiment.enabled ? ExperimentState.Evaluating : ExperimentState.NoRun
|
||||||
|
};
|
||||||
|
|
||||||
|
if (experiment.action) {
|
||||||
|
processedExperiment.action = {
|
||||||
|
type: ExperimentActionType[experiment.action.type] || ExperimentActionType.Custom,
|
||||||
|
properties: experiment.action.properties
|
||||||
|
};
|
||||||
|
if (processedExperiment.action.type === ExperimentActionType.Prompt) {
|
||||||
|
((<IExperimentActionPromptProperties>processedExperiment.action.properties).commands || []).forEach(x => {
|
||||||
|
if (x.curatedExtensionsKey && Array.isArray(x.curatedExtensionsList)) {
|
||||||
|
this._curatedMapping[experiment.id] = x;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!processedExperiment.action.properties) {
|
||||||
|
processedExperiment.action.properties = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._experiments.push(processedExperiment);
|
||||||
|
|
||||||
|
if (!processedExperiment.enabled) {
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const storageKey = 'experiments.' + experiment.id;
|
||||||
|
const experimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), {});
|
||||||
|
if (!experimentState.hasOwnProperty('enabled')) {
|
||||||
|
experimentState.enabled = processedExperiment.enabled;
|
||||||
|
}
|
||||||
|
if (!experimentState.hasOwnProperty('state')) {
|
||||||
|
experimentState.state = processedExperiment.enabled ? ExperimentState.Evaluating : ExperimentState.NoRun;
|
||||||
|
} else {
|
||||||
|
processedExperiment.state = experimentState.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.shouldRunExperiment(experiment, processedExperiment).then((state: ExperimentState) => {
|
||||||
|
experimentState.state = processedExperiment.state = state;
|
||||||
|
this.storageService.store(storageKey, JSON.stringify(experimentState), StorageScope.GLOBAL);
|
||||||
|
|
||||||
|
if (state === ExperimentState.Run) {
|
||||||
|
this.fireRunExperiment(processedExperiment);
|
||||||
|
}
|
||||||
|
return Promise.resolve(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
return Promise.all(promises).then(() => {
|
||||||
|
type ExperimentsClassification = {
|
||||||
|
experiments: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||||
|
};
|
||||||
|
this.telemetryService.publicLog2<{ experiments: IExperiment[] }, ExperimentsClassification>('experiments', { experiments: this._experiments });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private fireRunExperiment(experiment: IExperiment) {
|
||||||
|
this._onExperimentEnabled.fire(experiment);
|
||||||
|
const runExperimentIdsFromStorage: string[] = safeParse(this.storageService.get('currentOrPreviouslyRunExperiments', StorageScope.GLOBAL), []);
|
||||||
|
if (runExperimentIdsFromStorage.indexOf(experiment.id) === -1) {
|
||||||
|
runExperimentIdsFromStorage.push(experiment.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we dont store duplicates
|
||||||
|
const distinctExperiments = distinct(runExperimentIdsFromStorage);
|
||||||
|
if (runExperimentIdsFromStorage.length !== distinctExperiments.length) {
|
||||||
|
this.storageService.store('currentOrPreviouslyRunExperiments', JSON.stringify(distinctExperiments), StorageScope.GLOBAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkExperimentDependencies(experiment: IRawExperiment): boolean {
|
||||||
|
const experimentsPreviouslyRun = experiment.condition ? experiment.condition.experimentsPreviouslyRun : undefined;
|
||||||
|
if (experimentsPreviouslyRun) {
|
||||||
|
const runExperimentIdsFromStorage: string[] = safeParse(this.storageService.get('currentOrPreviouslyRunExperiments', StorageScope.GLOBAL), []);
|
||||||
|
let includeCheck = true;
|
||||||
|
let excludeCheck = true;
|
||||||
|
const includes = experimentsPreviouslyRun.includes;
|
||||||
|
if (Array.isArray(includes)) {
|
||||||
|
includeCheck = runExperimentIdsFromStorage.some(x => includes.indexOf(x) > -1);
|
||||||
|
}
|
||||||
|
const excludes = experimentsPreviouslyRun.excludes;
|
||||||
|
if (includeCheck && Array.isArray(excludes)) {
|
||||||
|
excludeCheck = !runExperimentIdsFromStorage.some(x => excludes.indexOf(x) > -1);
|
||||||
|
}
|
||||||
|
if (!includeCheck || !excludeCheck) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private shouldRunExperiment(experiment: IRawExperiment, processedExperiment: IExperiment): Promise<ExperimentState> {
|
||||||
|
if (processedExperiment.state !== ExperimentState.Evaluating) {
|
||||||
|
return Promise.resolve(processedExperiment.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!experiment.enabled) {
|
||||||
|
return Promise.resolve(ExperimentState.NoRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
const condition = experiment.condition;
|
||||||
|
if (!condition) {
|
||||||
|
return Promise.resolve(ExperimentState.Run);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.checkExperimentDependencies(experiment)) {
|
||||||
|
return Promise.resolve(ExperimentState.NoRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.environmentService.appQuality === 'stable' && condition.insidersOnly === true) {
|
||||||
|
return Promise.resolve(ExperimentState.NoRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isNewUser = !this.storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL);
|
||||||
|
if ((condition.newUser === true && !isNewUser)
|
||||||
|
|| (condition.newUser === false && isNewUser)) {
|
||||||
|
return Promise.resolve(ExperimentState.NoRun);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof condition.displayLanguage === 'string') {
|
||||||
|
let localeToCheck = condition.displayLanguage.toLowerCase();
|
||||||
|
let displayLanguage = language!.toLowerCase();
|
||||||
|
|
||||||
|
if (localeToCheck !== displayLanguage) {
|
||||||
|
const a = displayLanguage.indexOf('-');
|
||||||
|
const b = localeToCheck.indexOf('-');
|
||||||
|
if (a > -1) {
|
||||||
|
displayLanguage = displayLanguage.substr(0, a);
|
||||||
|
}
|
||||||
|
if (b > -1) {
|
||||||
|
localeToCheck = localeToCheck.substr(0, b);
|
||||||
|
}
|
||||||
|
if (displayLanguage !== localeToCheck) {
|
||||||
|
return Promise.resolve(ExperimentState.NoRun);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!condition.userProbability) {
|
||||||
|
condition.userProbability = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let extensionsCheckPromise = Promise.resolve(true);
|
||||||
|
const installedExtensions = condition.installedExtensions;
|
||||||
|
if (installedExtensions) {
|
||||||
|
extensionsCheckPromise = this.extensionManagementService.getInstalled(ExtensionType.User).then(locals => {
|
||||||
|
let includesCheck = true;
|
||||||
|
let excludesCheck = true;
|
||||||
|
const localExtensions = locals.map(local => `${local.manifest.publisher.toLowerCase()}.${local.manifest.name.toLowerCase()}`);
|
||||||
|
if (Array.isArray(installedExtensions.includes) && installedExtensions.includes.length) {
|
||||||
|
const extensionIncludes = installedExtensions.includes.map(e => e.toLowerCase());
|
||||||
|
includesCheck = localExtensions.some(e => extensionIncludes.indexOf(e) > -1);
|
||||||
|
}
|
||||||
|
if (Array.isArray(installedExtensions.excludes) && installedExtensions.excludes.length) {
|
||||||
|
const extensionExcludes = installedExtensions.excludes.map(e => e.toLowerCase());
|
||||||
|
excludesCheck = !localExtensions.some(e => extensionExcludes.indexOf(e) > -1);
|
||||||
|
}
|
||||||
|
return includesCheck && excludesCheck;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const storageKey = 'experiments.' + experiment.id;
|
||||||
|
const experimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), {});
|
||||||
|
|
||||||
|
return extensionsCheckPromise.then(success => {
|
||||||
|
const fileEdits = condition.fileEdits;
|
||||||
|
if (!success || !fileEdits || typeof fileEdits.minEditCount !== 'number') {
|
||||||
|
const runExperiment = success && typeof condition.userProbability === 'number' && Math.random() < condition.userProbability;
|
||||||
|
return runExperiment ? ExperimentState.Run : ExperimentState.NoRun;
|
||||||
|
}
|
||||||
|
|
||||||
|
experimentState.editCount = experimentState.editCount || 0;
|
||||||
|
if (experimentState.editCount >= fileEdits.minEditCount) {
|
||||||
|
return ExperimentState.Run;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onSaveHandler = this.textFileService.models.onModelsSaved(e => {
|
||||||
|
const date = new Date().toDateString();
|
||||||
|
const latestExperimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), {});
|
||||||
|
if (latestExperimentState.state !== ExperimentState.Evaluating) {
|
||||||
|
onSaveHandler.dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.forEach(async event => {
|
||||||
|
if (event.kind !== StateChange.SAVED
|
||||||
|
|| latestExperimentState.state !== ExperimentState.Evaluating
|
||||||
|
|| date === latestExperimentState.lastEditedDate
|
||||||
|
|| (typeof latestExperimentState.editCount === 'number' && latestExperimentState.editCount >= fileEdits.minEditCount)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let filePathCheck = true;
|
||||||
|
let workspaceCheck = true;
|
||||||
|
|
||||||
|
if (typeof fileEdits.filePathPattern === 'string') {
|
||||||
|
filePathCheck = match(fileEdits.filePathPattern, event.resource.fsPath);
|
||||||
|
}
|
||||||
|
if (Array.isArray(fileEdits.workspaceIncludes) && fileEdits.workspaceIncludes.length) {
|
||||||
|
const tags = await this.workspaceStatsService.getTags();
|
||||||
|
workspaceCheck = !!tags && fileEdits.workspaceIncludes.some(x => !!tags[x]);
|
||||||
|
}
|
||||||
|
if (workspaceCheck && Array.isArray(fileEdits.workspaceExcludes) && fileEdits.workspaceExcludes.length) {
|
||||||
|
const tags = await this.workspaceStatsService.getTags();
|
||||||
|
workspaceCheck = !!tags && !fileEdits.workspaceExcludes.some(x => !!tags[x]);
|
||||||
|
}
|
||||||
|
if (filePathCheck && workspaceCheck) {
|
||||||
|
latestExperimentState.editCount = (latestExperimentState.editCount || 0) + 1;
|
||||||
|
latestExperimentState.lastEditedDate = date;
|
||||||
|
this.storageService.store(storageKey, JSON.stringify(latestExperimentState), StorageScope.GLOBAL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (typeof latestExperimentState.editCount === 'number' && latestExperimentState.editCount >= fileEdits.minEditCount) {
|
||||||
|
processedExperiment.state = latestExperimentState.state = (typeof condition.userProbability === 'number' && Math.random() < condition.userProbability && this.checkExperimentDependencies(experiment)) ? ExperimentState.Run : ExperimentState.NoRun;
|
||||||
|
this.storageService.store(storageKey, JSON.stringify(latestExperimentState), StorageScope.GLOBAL);
|
||||||
|
if (latestExperimentState.state === ExperimentState.Run && experiment.action && ExperimentActionType[experiment.action.type] === ExperimentActionType.Prompt) {
|
||||||
|
this.fireRunExperiment(processedExperiment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this._register(onSaveHandler);
|
||||||
|
return ExperimentState.Evaluating;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function safeParse(text: string | undefined, defaultObject: any) {
|
||||||
|
try {
|
||||||
|
return text ? JSON.parse(text) || defaultObject : defaultObject;
|
||||||
|
} catch (e) {
|
||||||
|
return defaultObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,407 +0,0 @@
|
|||||||
/*---------------------------------------------------------------------------------------------
|
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
||||||
*--------------------------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
|
||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
|
||||||
import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
|
|
||||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
|
||||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
|
||||||
import { language } from 'vs/base/common/platform';
|
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { match } from 'vs/base/common/glob';
|
|
||||||
import { IRequestService, asJson } from 'vs/platform/request/common/request';
|
|
||||||
import { Emitter, Event } from 'vs/base/common/event';
|
|
||||||
import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/common/textfiles';
|
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
|
||||||
import { distinct } from 'vs/base/common/arrays';
|
|
||||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
|
||||||
import { ExperimentState, IExperimentAction, IExperimentService, IExperiment, ExperimentActionType, IExperimentActionPromptProperties } from 'vs/workbench/contrib/experiments/common/experimentService';
|
|
||||||
import { IProductService } from 'vs/platform/product/common/product';
|
|
||||||
import { IWorkspaceStatsService } from 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService';
|
|
||||||
|
|
||||||
interface IExperimentStorageState {
|
|
||||||
enabled: boolean;
|
|
||||||
state: ExperimentState;
|
|
||||||
editCount?: number;
|
|
||||||
lastEditedDate?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IRawExperiment {
|
|
||||||
id: string;
|
|
||||||
enabled?: boolean;
|
|
||||||
condition?: {
|
|
||||||
insidersOnly?: boolean;
|
|
||||||
newUser?: boolean;
|
|
||||||
displayLanguage?: string;
|
|
||||||
installedExtensions?: {
|
|
||||||
excludes?: string[];
|
|
||||||
includes?: string[];
|
|
||||||
},
|
|
||||||
fileEdits?: {
|
|
||||||
filePathPattern?: string;
|
|
||||||
workspaceIncludes?: string[];
|
|
||||||
workspaceExcludes?: string[];
|
|
||||||
minEditCount: number;
|
|
||||||
},
|
|
||||||
experimentsPreviouslyRun?: {
|
|
||||||
excludes?: string[];
|
|
||||||
includes?: string[];
|
|
||||||
}
|
|
||||||
userProbability?: number;
|
|
||||||
};
|
|
||||||
action?: IExperimentAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ExperimentService extends Disposable implements IExperimentService {
|
|
||||||
_serviceBrand: any;
|
|
||||||
private _experiments: IExperiment[] = [];
|
|
||||||
private _loadExperimentsPromise: Promise<void>;
|
|
||||||
private _curatedMapping = Object.create(null);
|
|
||||||
|
|
||||||
private readonly _onExperimentEnabled = this._register(new Emitter<IExperiment>());
|
|
||||||
onExperimentEnabled: Event<IExperiment> = this._onExperimentEnabled.event;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@IStorageService private readonly storageService: IStorageService,
|
|
||||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
|
||||||
@ITextFileService private readonly textFileService: ITextFileService,
|
|
||||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
|
||||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
|
||||||
@ILifecycleService private readonly lifecycleService: ILifecycleService,
|
|
||||||
@IRequestService private readonly requestService: IRequestService,
|
|
||||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
|
||||||
@IProductService private readonly productService: IProductService,
|
|
||||||
@IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this._loadExperimentsPromise = Promise.resolve(this.lifecycleService.when(LifecyclePhase.Eventually)).then(() => this.loadExperiments());
|
|
||||||
}
|
|
||||||
|
|
||||||
public getExperimentById(id: string): Promise<IExperiment> {
|
|
||||||
return this._loadExperimentsPromise.then(() => {
|
|
||||||
return this._experiments.filter(x => x.id === id)[0];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public getExperimentsByType(type: ExperimentActionType): Promise<IExperiment[]> {
|
|
||||||
return this._loadExperimentsPromise.then(() => {
|
|
||||||
if (type === ExperimentActionType.Custom) {
|
|
||||||
return this._experiments.filter(x => x.enabled && (!x.action || x.action.type === type));
|
|
||||||
}
|
|
||||||
return this._experiments.filter(x => x.enabled && x.action && x.action.type === type);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public getCuratedExtensionsList(curatedExtensionsKey: string): Promise<string[]> {
|
|
||||||
return this._loadExperimentsPromise.then(() => {
|
|
||||||
for (const experiment of this._experiments) {
|
|
||||||
if (experiment.enabled
|
|
||||||
&& experiment.state === ExperimentState.Run
|
|
||||||
&& this._curatedMapping[experiment.id]
|
|
||||||
&& this._curatedMapping[experiment.id].curatedExtensionsKey === curatedExtensionsKey) {
|
|
||||||
return this._curatedMapping[experiment.id].curatedExtensionsList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public markAsCompleted(experimentId: string): void {
|
|
||||||
const storageKey = 'experiments.' + experimentId;
|
|
||||||
const experimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), {});
|
|
||||||
experimentState.state = ExperimentState.Complete;
|
|
||||||
this.storageService.store(storageKey, JSON.stringify(experimentState), StorageScope.GLOBAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getExperiments(): Promise<IRawExperiment[]> {
|
|
||||||
if (!this.productService.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
return this.requestService.request({ type: 'GET', url: this.productService.experimentsUrl }, CancellationToken.None).then(context => {
|
|
||||||
if (context.res.statusCode !== 200) {
|
|
||||||
return Promise.resolve(null);
|
|
||||||
}
|
|
||||||
return asJson(context).then((result: any) => {
|
|
||||||
return result && Array.isArray(result['experiments']) ? result['experiments'] : [];
|
|
||||||
});
|
|
||||||
}, () => Promise.resolve(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
private loadExperiments(): Promise<any> {
|
|
||||||
return this.getExperiments().then(rawExperiments => {
|
|
||||||
// Offline mode
|
|
||||||
if (!rawExperiments) {
|
|
||||||
const allExperimentIdsFromStorage = safeParse(this.storageService.get('allExperiments', StorageScope.GLOBAL), []);
|
|
||||||
if (Array.isArray(allExperimentIdsFromStorage)) {
|
|
||||||
allExperimentIdsFromStorage.forEach(experimentId => {
|
|
||||||
const storageKey = 'experiments.' + experimentId;
|
|
||||||
const experimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), null);
|
|
||||||
if (experimentState) {
|
|
||||||
this._experiments.push({
|
|
||||||
id: experimentId,
|
|
||||||
enabled: experimentState.enabled,
|
|
||||||
state: experimentState.state
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return Promise.resolve(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear disbaled/deleted experiments from storage
|
|
||||||
const allExperimentIdsFromStorage = safeParse(this.storageService.get('allExperiments', StorageScope.GLOBAL), []);
|
|
||||||
const enabledExperiments = rawExperiments.filter(experiment => !!experiment.enabled).map(experiment => experiment.id.toLowerCase());
|
|
||||||
if (Array.isArray(allExperimentIdsFromStorage)) {
|
|
||||||
allExperimentIdsFromStorage.forEach(experiment => {
|
|
||||||
if (enabledExperiments.indexOf(experiment) === -1) {
|
|
||||||
this.storageService.remove(`experiments.${experiment}`, StorageScope.GLOBAL);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (enabledExperiments.length) {
|
|
||||||
this.storageService.store('allExperiments', JSON.stringify(enabledExperiments), StorageScope.GLOBAL);
|
|
||||||
} else {
|
|
||||||
this.storageService.remove('allExperiments', StorageScope.GLOBAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
const promises = rawExperiments.map(experiment => {
|
|
||||||
const processedExperiment: IExperiment = {
|
|
||||||
id: experiment.id,
|
|
||||||
enabled: !!experiment.enabled,
|
|
||||||
state: !!experiment.enabled ? ExperimentState.Evaluating : ExperimentState.NoRun
|
|
||||||
};
|
|
||||||
|
|
||||||
if (experiment.action) {
|
|
||||||
processedExperiment.action = {
|
|
||||||
type: ExperimentActionType[experiment.action.type] || ExperimentActionType.Custom,
|
|
||||||
properties: experiment.action.properties
|
|
||||||
};
|
|
||||||
if (processedExperiment.action.type === ExperimentActionType.Prompt) {
|
|
||||||
((<IExperimentActionPromptProperties>processedExperiment.action.properties).commands || []).forEach(x => {
|
|
||||||
if (x.curatedExtensionsKey && Array.isArray(x.curatedExtensionsList)) {
|
|
||||||
this._curatedMapping[experiment.id] = x;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!processedExperiment.action.properties) {
|
|
||||||
processedExperiment.action.properties = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._experiments.push(processedExperiment);
|
|
||||||
|
|
||||||
if (!processedExperiment.enabled) {
|
|
||||||
return Promise.resolve(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
const storageKey = 'experiments.' + experiment.id;
|
|
||||||
const experimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), {});
|
|
||||||
if (!experimentState.hasOwnProperty('enabled')) {
|
|
||||||
experimentState.enabled = processedExperiment.enabled;
|
|
||||||
}
|
|
||||||
if (!experimentState.hasOwnProperty('state')) {
|
|
||||||
experimentState.state = processedExperiment.enabled ? ExperimentState.Evaluating : ExperimentState.NoRun;
|
|
||||||
} else {
|
|
||||||
processedExperiment.state = experimentState.state;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.shouldRunExperiment(experiment, processedExperiment).then((state: ExperimentState) => {
|
|
||||||
experimentState.state = processedExperiment.state = state;
|
|
||||||
this.storageService.store(storageKey, JSON.stringify(experimentState), StorageScope.GLOBAL);
|
|
||||||
|
|
||||||
if (state === ExperimentState.Run) {
|
|
||||||
this.fireRunExperiment(processedExperiment);
|
|
||||||
}
|
|
||||||
return Promise.resolve(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
return Promise.all(promises).then(() => {
|
|
||||||
type ExperimentsClassification = {
|
|
||||||
experiments: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
|
||||||
};
|
|
||||||
this.telemetryService.publicLog2<{ experiments: IExperiment[] }, ExperimentsClassification>('experiments', { experiments: this._experiments });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private fireRunExperiment(experiment: IExperiment) {
|
|
||||||
this._onExperimentEnabled.fire(experiment);
|
|
||||||
const runExperimentIdsFromStorage: string[] = safeParse(this.storageService.get('currentOrPreviouslyRunExperiments', StorageScope.GLOBAL), []);
|
|
||||||
if (runExperimentIdsFromStorage.indexOf(experiment.id) === -1) {
|
|
||||||
runExperimentIdsFromStorage.push(experiment.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure we dont store duplicates
|
|
||||||
const distinctExperiments = distinct(runExperimentIdsFromStorage);
|
|
||||||
if (runExperimentIdsFromStorage.length !== distinctExperiments.length) {
|
|
||||||
this.storageService.store('currentOrPreviouslyRunExperiments', JSON.stringify(distinctExperiments), StorageScope.GLOBAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private checkExperimentDependencies(experiment: IRawExperiment): boolean {
|
|
||||||
const experimentsPreviouslyRun = experiment.condition ? experiment.condition.experimentsPreviouslyRun : undefined;
|
|
||||||
if (experimentsPreviouslyRun) {
|
|
||||||
const runExperimentIdsFromStorage: string[] = safeParse(this.storageService.get('currentOrPreviouslyRunExperiments', StorageScope.GLOBAL), []);
|
|
||||||
let includeCheck = true;
|
|
||||||
let excludeCheck = true;
|
|
||||||
const includes = experimentsPreviouslyRun.includes;
|
|
||||||
if (Array.isArray(includes)) {
|
|
||||||
includeCheck = runExperimentIdsFromStorage.some(x => includes.indexOf(x) > -1);
|
|
||||||
}
|
|
||||||
const excludes = experimentsPreviouslyRun.excludes;
|
|
||||||
if (includeCheck && Array.isArray(excludes)) {
|
|
||||||
excludeCheck = !runExperimentIdsFromStorage.some(x => excludes.indexOf(x) > -1);
|
|
||||||
}
|
|
||||||
if (!includeCheck || !excludeCheck) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private shouldRunExperiment(experiment: IRawExperiment, processedExperiment: IExperiment): Promise<ExperimentState> {
|
|
||||||
if (processedExperiment.state !== ExperimentState.Evaluating) {
|
|
||||||
return Promise.resolve(processedExperiment.state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!experiment.enabled) {
|
|
||||||
return Promise.resolve(ExperimentState.NoRun);
|
|
||||||
}
|
|
||||||
|
|
||||||
const condition = experiment.condition;
|
|
||||||
if (!condition) {
|
|
||||||
return Promise.resolve(ExperimentState.Run);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.checkExperimentDependencies(experiment)) {
|
|
||||||
return Promise.resolve(ExperimentState.NoRun);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.environmentService.appQuality === 'stable' && condition.insidersOnly === true) {
|
|
||||||
return Promise.resolve(ExperimentState.NoRun);
|
|
||||||
}
|
|
||||||
|
|
||||||
const isNewUser = !this.storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL);
|
|
||||||
if ((condition.newUser === true && !isNewUser)
|
|
||||||
|| (condition.newUser === false && isNewUser)) {
|
|
||||||
return Promise.resolve(ExperimentState.NoRun);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof condition.displayLanguage === 'string') {
|
|
||||||
let localeToCheck = condition.displayLanguage.toLowerCase();
|
|
||||||
let displayLanguage = language!.toLowerCase();
|
|
||||||
|
|
||||||
if (localeToCheck !== displayLanguage) {
|
|
||||||
const a = displayLanguage.indexOf('-');
|
|
||||||
const b = localeToCheck.indexOf('-');
|
|
||||||
if (a > -1) {
|
|
||||||
displayLanguage = displayLanguage.substr(0, a);
|
|
||||||
}
|
|
||||||
if (b > -1) {
|
|
||||||
localeToCheck = localeToCheck.substr(0, b);
|
|
||||||
}
|
|
||||||
if (displayLanguage !== localeToCheck) {
|
|
||||||
return Promise.resolve(ExperimentState.NoRun);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!condition.userProbability) {
|
|
||||||
condition.userProbability = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let extensionsCheckPromise = Promise.resolve(true);
|
|
||||||
const installedExtensions = condition.installedExtensions;
|
|
||||||
if (installedExtensions) {
|
|
||||||
extensionsCheckPromise = this.extensionManagementService.getInstalled(ExtensionType.User).then(locals => {
|
|
||||||
let includesCheck = true;
|
|
||||||
let excludesCheck = true;
|
|
||||||
const localExtensions = locals.map(local => `${local.manifest.publisher.toLowerCase()}.${local.manifest.name.toLowerCase()}`);
|
|
||||||
if (Array.isArray(installedExtensions.includes) && installedExtensions.includes.length) {
|
|
||||||
const extensionIncludes = installedExtensions.includes.map(e => e.toLowerCase());
|
|
||||||
includesCheck = localExtensions.some(e => extensionIncludes.indexOf(e) > -1);
|
|
||||||
}
|
|
||||||
if (Array.isArray(installedExtensions.excludes) && installedExtensions.excludes.length) {
|
|
||||||
const extensionExcludes = installedExtensions.excludes.map(e => e.toLowerCase());
|
|
||||||
excludesCheck = !localExtensions.some(e => extensionExcludes.indexOf(e) > -1);
|
|
||||||
}
|
|
||||||
return includesCheck && excludesCheck;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const storageKey = 'experiments.' + experiment.id;
|
|
||||||
const experimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), {});
|
|
||||||
|
|
||||||
return extensionsCheckPromise.then(success => {
|
|
||||||
const fileEdits = condition.fileEdits;
|
|
||||||
if (!success || !fileEdits || typeof fileEdits.minEditCount !== 'number') {
|
|
||||||
const runExperiment = success && typeof condition.userProbability === 'number' && Math.random() < condition.userProbability;
|
|
||||||
return runExperiment ? ExperimentState.Run : ExperimentState.NoRun;
|
|
||||||
}
|
|
||||||
|
|
||||||
experimentState.editCount = experimentState.editCount || 0;
|
|
||||||
if (experimentState.editCount >= fileEdits.minEditCount) {
|
|
||||||
return ExperimentState.Run;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onSaveHandler = this.textFileService.models.onModelsSaved(e => {
|
|
||||||
const date = new Date().toDateString();
|
|
||||||
const latestExperimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), {});
|
|
||||||
if (latestExperimentState.state !== ExperimentState.Evaluating) {
|
|
||||||
onSaveHandler.dispose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.forEach(async event => {
|
|
||||||
if (event.kind !== StateChange.SAVED
|
|
||||||
|| latestExperimentState.state !== ExperimentState.Evaluating
|
|
||||||
|| date === latestExperimentState.lastEditedDate
|
|
||||||
|| (typeof latestExperimentState.editCount === 'number' && latestExperimentState.editCount >= fileEdits.minEditCount)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let filePathCheck = true;
|
|
||||||
let workspaceCheck = true;
|
|
||||||
|
|
||||||
if (typeof fileEdits.filePathPattern === 'string') {
|
|
||||||
filePathCheck = match(fileEdits.filePathPattern, event.resource.fsPath);
|
|
||||||
}
|
|
||||||
if (Array.isArray(fileEdits.workspaceIncludes) && fileEdits.workspaceIncludes.length) {
|
|
||||||
const tags = await this.workspaceStatsService.getTags();
|
|
||||||
workspaceCheck = !!tags && fileEdits.workspaceIncludes.some(x => !!tags[x]);
|
|
||||||
}
|
|
||||||
if (workspaceCheck && Array.isArray(fileEdits.workspaceExcludes) && fileEdits.workspaceExcludes.length) {
|
|
||||||
const tags = await this.workspaceStatsService.getTags();
|
|
||||||
workspaceCheck = !!tags && !fileEdits.workspaceExcludes.some(x => !!tags[x]);
|
|
||||||
}
|
|
||||||
if (filePathCheck && workspaceCheck) {
|
|
||||||
latestExperimentState.editCount = (latestExperimentState.editCount || 0) + 1;
|
|
||||||
latestExperimentState.lastEditedDate = date;
|
|
||||||
this.storageService.store(storageKey, JSON.stringify(latestExperimentState), StorageScope.GLOBAL);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (typeof latestExperimentState.editCount === 'number' && latestExperimentState.editCount >= fileEdits.minEditCount) {
|
|
||||||
processedExperiment.state = latestExperimentState.state = (typeof condition.userProbability === 'number' && Math.random() < condition.userProbability && this.checkExperimentDependencies(experiment)) ? ExperimentState.Run : ExperimentState.NoRun;
|
|
||||||
this.storageService.store(storageKey, JSON.stringify(latestExperimentState), StorageScope.GLOBAL);
|
|
||||||
if (latestExperimentState.state === ExperimentState.Run && experiment.action && ExperimentActionType[experiment.action.type] === ExperimentActionType.Prompt) {
|
|
||||||
this.fireRunExperiment(processedExperiment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this._register(onSaveHandler);
|
|
||||||
return ExperimentState.Evaluating;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function safeParse(text: string | undefined, defaultObject: any) {
|
|
||||||
try {
|
|
||||||
return text ? JSON.parse(text) || defaultObject : defaultObject;
|
|
||||||
} catch (e) {
|
|
||||||
return defaultObject;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,8 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { ExperimentActionType, ExperimentState, IExperiment } from 'vs/workbench/contrib/experiments/common/experimentService';
|
import { ExperimentActionType, ExperimentState, IExperiment, ExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||||
import { ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
|
|
||||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';
|
import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { TestNotificationService } from 'vs/platform/notification/test/common/te
|
|||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||||
import { ExperimentalPrompts } from 'vs/workbench/contrib/experiments/electron-browser/experimentalPrompt';
|
import { ExperimentalPrompts } from 'vs/workbench/contrib/experiments/browser/experimentalPrompt';
|
||||||
import { ExperimentActionType, ExperimentState, IExperiment, IExperimentActionPromptProperties, IExperimentService, LocalizedPromptText } from 'vs/workbench/contrib/experiments/common/experimentService';
|
import { ExperimentActionType, ExperimentState, IExperiment, IExperimentActionPromptProperties, IExperimentService, LocalizedPromptText } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||||
import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test';
|
import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test';
|
||||||
import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';
|
import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';
|
||||||
|
|||||||
@@ -79,10 +79,10 @@ export function toExtensionDescription(local: ILocalExtension): IExtensionDescri
|
|||||||
|
|
||||||
const promptDownloadManually = (extension: IGalleryExtension | undefined, message: string, error: Error,
|
const promptDownloadManually = (extension: IGalleryExtension | undefined, message: string, error: Error,
|
||||||
instantiationService: IInstantiationService, notificationService: INotificationService, openerService: IOpenerService, productService: IProductService) => {
|
instantiationService: IInstantiationService, notificationService: INotificationService, openerService: IOpenerService, productService: IProductService) => {
|
||||||
if (!extension || error.name === INSTALL_ERROR_INCOMPATIBLE || error.name === INSTALL_ERROR_MALICIOUS || !productService.extensionsGallery) {
|
if (!extension || error.name === INSTALL_ERROR_INCOMPATIBLE || error.name === INSTALL_ERROR_MALICIOUS || !productService.productConfiguration.extensionsGallery) {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
} else {
|
} else {
|
||||||
const downloadUrl = `${productService.extensionsGallery.serviceUrl}/publishers/${extension.publisher}/vsextensions/${extension.name}/${extension.version}/vspackage`;
|
const downloadUrl = `${productService.productConfiguration.extensionsGallery.serviceUrl}/publishers/${extension.publisher}/vsextensions/${extension.name}/${extension.version}/vspackage`;
|
||||||
notificationService.prompt(Severity.Error, message, [{
|
notificationService.prompt(Severity.Error, message, [{
|
||||||
label: localize('download', "Download Manually"),
|
label: localize('download', "Download Manually"),
|
||||||
run: () => openerService.open(URI.parse(downloadUrl)).then(() => {
|
run: () => openerService.open(URI.parse(downloadUrl)).then(() => {
|
||||||
|
|||||||
@@ -435,7 +435,7 @@ export class ExtensionsListView extends ViewletPanel {
|
|||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
if (this.productService) {
|
if (this.productService) {
|
||||||
let promiseRecommendedExtensionsByScenario: Promise<IPagedModel<IExtension>> | undefined;
|
let promiseRecommendedExtensionsByScenario: Promise<IPagedModel<IExtension>> | undefined;
|
||||||
Object.keys(this.productService.recommendedExtensionsByScenario).forEach(scenarioType => {
|
Object.keys(this.productService.productConfiguration.recommendedExtensionsByScenario).forEach(scenarioType => {
|
||||||
let re = new RegExp('@' + scenarioType, 'i');
|
let re = new RegExp('@' + scenarioType, 'i');
|
||||||
if (re.test(query.value)) {
|
if (re.test(query.value)) {
|
||||||
promiseRecommendedExtensionsByScenario = this.getRecommendedExtensionsByScenario(token, scenarioType);
|
promiseRecommendedExtensionsByScenario = this.getRecommendedExtensionsByScenario(token, scenarioType);
|
||||||
@@ -944,7 +944,7 @@ export class ServerExtensionsView extends ExtensionsListView {
|
|||||||
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
|
@IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||||
@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService,
|
@IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService,
|
||||||
@IProductService productService: IProductService,
|
@IProductService productService: IProductService,
|
||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
@IContextKeyService contextKeyService: IContextKeyService
|
||||||
) {
|
) {
|
||||||
options.server = server;
|
options.server = server;
|
||||||
super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService, productService, contextKeyService);
|
super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService, productService, contextKeyService);
|
||||||
@@ -960,7 +960,7 @@ export class ServerExtensionsView extends ExtensionsListView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getActions(): IAction[] {
|
getActions(): IAction[] {
|
||||||
if (this.extensionManagementServerService.localExtensionManagementServer === this.server) {
|
if (this.extensionManagementServerService.remoteExtensionManagementServer && this.extensionManagementServerService.localExtensionManagementServer === this.server) {
|
||||||
const installLocalExtensionsInRemoteAction = this._register(this.instantiationService.createInstance(InstallLocalExtensionsInRemoteAction, false));
|
const installLocalExtensionsInRemoteAction = this._register(this.instantiationService.createInstance(InstallLocalExtensionsInRemoteAction, false));
|
||||||
installLocalExtensionsInRemoteAction.class = 'octicon octicon-cloud-download';
|
installLocalExtensionsInRemoteAction.class = 'octicon octicon-cloud-download';
|
||||||
return [installLocalExtensionsInRemoteAction];
|
return [installLocalExtensionsInRemoteAction];
|
||||||
|
|||||||
@@ -118,20 +118,19 @@ class Extension implements IExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get url(): string | undefined {
|
get url(): string | undefined {
|
||||||
if (!this.productService.extensionsGallery || !this.gallery) {
|
if (!this.productService.productConfiguration.extensionsGallery || !this.gallery) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.productService.extensionsGallery.itemUrl && `${this.productService.extensionsGallery.itemUrl}?itemName=${this.publisher}.${this.name}`; // {{SQL CARBON EDIT}} add check for itemurl
|
return `${this.productService.productConfiguration.extensionsGallery.itemUrl}?itemName=${this.publisher}.${this.name}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
get downloadPage(): string {
|
get downloadPage(): string {
|
||||||
if (!this.productService.extensionsGallery) {
|
if (!this.productService.productConfiguration.extensionsGallery) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}}
|
|
||||||
return this.gallery && this.gallery.assets && this.gallery.assets.downloadPage && this.gallery.assets.downloadPage.uri;
|
return this.gallery && this.gallery.assets && this.gallery.assets.downloadPage && this.gallery.assets.downloadPage.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,7 +631,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
|||||||
text = text.replace(extensionRegex, (m, ext) => {
|
text = text.replace(extensionRegex, (m, ext) => {
|
||||||
|
|
||||||
// Get curated keywords
|
// Get curated keywords
|
||||||
const lookup = this.productService.extensionKeywords || {};
|
const lookup = this.productService.productConfiguration.extensionKeywords || {};
|
||||||
const keywords = lookup[ext] || [];
|
const keywords = lookup[ext] || [];
|
||||||
|
|
||||||
// Get mode name
|
// Get mode name
|
||||||
@@ -832,9 +831,9 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
|||||||
// This is the execution path for install/update extension from marketplace.
|
// This is the execution path for install/update extension from marketplace.
|
||||||
// Check both the vscode version and azure data studio version
|
// Check both the vscode version and azure data studio version
|
||||||
// The check is added here because we want to fail fast instead of downloading the VSIX and then fail.
|
// The check is added here because we want to fail fast instead of downloading the VSIX and then fail.
|
||||||
if (gallery.properties.engine && (!isEngineValid(gallery.properties.engine, this.productService.vscodeVersion)
|
if (gallery.properties.engine && (!isEngineValid(gallery.properties.engine, this.productService.productConfiguration.vscodeVersion)
|
||||||
|| (gallery.properties.azDataEngine && !isEngineValid(gallery.properties.azDataEngine, this.productService.version)))) {
|
|| (gallery.properties.azDataEngine && !isEngineValid(gallery.properties.azDataEngine, this.productService.productConfiguration.version)))) {
|
||||||
return Promise.reject(new Error(nls.localize('incompatible2', "Unable to install version '{2}' of extension '{0}' as it is not compatible with Azure Data Studio '{1}'.", extension.gallery!.identifier.id, this.productService.version, gallery.version)));
|
return Promise.reject(new Error(nls.localize('incompatible2', "Unable to install version '{2}' of extension '{0}' as it is not compatible with Azure Data Studio '{1}'.", extension.gallery!.identifier.id, this.productService.productConfiguration.version, gallery.version)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.installWithProgress(async () => {
|
return this.installWithProgress(async () => {
|
||||||
@@ -1077,7 +1076,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
|||||||
|
|
||||||
get allowedBadgeProviders(): string[] {
|
get allowedBadgeProviders(): string[] {
|
||||||
if (!this._extensionAllowedBadgeProviders) {
|
if (!this._extensionAllowedBadgeProviders) {
|
||||||
this._extensionAllowedBadgeProviders = (this.productService.extensionAllowedBadgeProviders || []).map(s => s.toLowerCase());
|
this._extensionAllowedBadgeProviders = (this.productService.productConfiguration.extensionAllowedBadgeProviders || []).map(s => s.toLowerCase());
|
||||||
}
|
}
|
||||||
return this._extensionAllowedBadgeProviders;
|
return this._extensionAllowedBadgeProviders;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import { IExtensionTipsService, ExtensionRecommendationReason, IExtensionsConfig
|
|||||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||||
import { ITextModel } from 'vs/editor/common/model';
|
import { ITextModel } from 'vs/editor/common/model';
|
||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
import product from 'vs/platform/product/node/product';
|
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
import { ShowRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction, InstallRecommendedExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
import { ShowRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction, InstallRecommendedExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||||
@@ -28,13 +27,11 @@ import { IFileService } from 'vs/platform/files/common/files';
|
|||||||
import { IExtensionsConfiguration, ConfigurationKey, ShowRecommendationsOnlyOnDemandKey, IExtensionsViewlet, IExtensionsWorkbenchService, EXTENSIONS_CONFIG, ExtensionsPolicyKey, ExtensionsPolicy } from 'vs/workbench/contrib/extensions/common/extensions';
|
import { IExtensionsConfiguration, ConfigurationKey, ShowRecommendationsOnlyOnDemandKey, IExtensionsViewlet, IExtensionsWorkbenchService, EXTENSIONS_CONFIG, ExtensionsPolicyKey, ExtensionsPolicy } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import * as pfs from 'vs/base/node/pfs';
|
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import { flatten, distinct, shuffle, coalesce } from 'vs/base/common/arrays';
|
import { flatten, distinct, shuffle, coalesce } from 'vs/base/common/arrays';
|
||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
import { guessMimeTypes, MIME_UNKNOWN } from 'vs/base/common/mime';
|
import { guessMimeTypes, MIME_UNKNOWN } from 'vs/base/common/mime';
|
||||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
import { getHashedRemotesFromUri } from 'vs/workbench/contrib/stats/electron-browser/workspaceStats';
|
|
||||||
import { IRequestService, asJson } from 'vs/platform/request/common/request';
|
import { IRequestService, asJson } from 'vs/platform/request/common/request';
|
||||||
import { isNumber } from 'vs/base/common/types';
|
import { isNumber } from 'vs/base/common/types';
|
||||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||||
@@ -47,11 +44,11 @@ import { IExperimentService, ExperimentActionType, ExperimentState } from 'vs/wo
|
|||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||||
import { extname } from 'vs/base/common/resources';
|
import { extname } from 'vs/base/common/resources';
|
||||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
import { IExeBasedExtensionTip, IProductService } from 'vs/platform/product/common/product';
|
||||||
import { IExeBasedExtensionTip } from 'vs/platform/product/common/product';
|
|
||||||
import { timeout } from 'vs/base/common/async';
|
import { timeout } from 'vs/base/common/async';
|
||||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry'; // {{SQL CARBON EDIT}}
|
||||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys'; // {{SQL CARBON EDIT}}
|
||||||
|
import { IWorkspaceStatsService } from 'vs/workbench/contrib/stats/common/workspaceStats';
|
||||||
|
|
||||||
const milliSecondsInADay = 1000 * 60 * 60 * 24;
|
const milliSecondsInADay = 1000 * 60 * 60 * 24;
|
||||||
const choiceNever = localize('neverShowAgain', "Don't Show Again");
|
const choiceNever = localize('neverShowAgain', "Don't Show Again");
|
||||||
@@ -117,8 +114,9 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||||
@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
|
@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
|
||||||
@IExperimentService private readonly experimentService: IExperimentService,
|
@IExperimentService private readonly experimentService: IExperimentService,
|
||||||
@ITextFileService private readonly textFileService: ITextFileService,
|
@IAdsTelemetryService private readonly adsTelemetryService: IAdsTelemetryService, // {{SQL CARBON EDIT}}
|
||||||
@IAdsTelemetryService private readonly adsTelemetryService: IAdsTelemetryService
|
@IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService,
|
||||||
|
@IProductService private readonly productService: IProductService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -128,8 +126,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (product.extensionsGallery && product.extensionsGallery.recommendationsUrl) {
|
if (this.productService.productConfiguration.extensionsGallery && this.productService.productConfiguration.extensionsGallery.recommendationsUrl) {
|
||||||
this._extensionsRecommendationsUrl = product.extensionsGallery.recommendationsUrl;
|
this._extensionsRecommendationsUrl = this.productService.productConfiguration.extensionsGallery.recommendationsUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sessionSeed = +new Date();
|
this.sessionSeed = +new Date();
|
||||||
@@ -258,7 +256,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
getKeymapRecommendations(): IExtensionRecommendation[] {
|
getKeymapRecommendations(): IExtensionRecommendation[] {
|
||||||
return (product.keymapExtensionTips || [])
|
return (this.productService.productConfiguration.keymapExtensionTips || [])
|
||||||
.filter(extensionId => this.isExtensionAllowedToBeRecommended(extensionId))
|
.filter(extensionId => this.isExtensionAllowedToBeRecommended(extensionId))
|
||||||
.map(extensionId => (<IExtensionRecommendation>{ extensionId, sources: ['application'] }));
|
.map(extensionId => (<IExtensionRecommendation>{ extensionId, sources: ['application'] }));
|
||||||
}
|
}
|
||||||
@@ -615,10 +613,10 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
return Object.keys(this._fileBasedRecommendations)
|
return Object.keys(this._fileBasedRecommendations)
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
if (this._fileBasedRecommendations[a].recommendedTime === this._fileBasedRecommendations[b].recommendedTime) {
|
if (this._fileBasedRecommendations[a].recommendedTime === this._fileBasedRecommendations[b].recommendedTime) {
|
||||||
if (!product.extensionImportantTips || caseInsensitiveGet(product.extensionImportantTips, a)) {
|
if (!this.productService.productConfiguration.extensionImportantTips || caseInsensitiveGet(this.productService.productConfiguration.extensionImportantTips, a)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (caseInsensitiveGet(product.extensionImportantTips, b)) {
|
if (caseInsensitiveGet(this.productService.productConfiguration.extensionImportantTips, b)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -629,13 +627,13 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse all file based recommendations from product.extensionTips
|
* Parse all file based recommendations from this.productService.productConfiguration.extensionTips
|
||||||
* Retire existing recommendations if they are older than a week or are not part of product.extensionTips anymore
|
* Retire existing recommendations if they are older than a week or are not part of this.productService.productConfiguration.extensionTips anymore
|
||||||
*/
|
*/
|
||||||
private fetchFileBasedRecommendations() {
|
private fetchFileBasedRecommendations() {
|
||||||
const extensionTips = product.extensionTips;
|
const extensionTips = this.productService.productConfiguration.extensionTips;
|
||||||
// {{SQL CARBON EDIT}}
|
// {{SQL CARBON EDIT}}
|
||||||
this._recommendations = product.recommendedExtensions;
|
this._recommendations = this.productService.productConfiguration.recommendedExtensions;
|
||||||
if (!extensionTips) {
|
if (!extensionTips) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -652,7 +650,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
forEach(product.extensionImportantTips, entry => {
|
forEach(this.productService.productConfiguration.extensionImportantTips, entry => {
|
||||||
let { key: id, value } = entry;
|
let { key: id, value } = entry;
|
||||||
const { pattern } = value;
|
const { pattern } = value;
|
||||||
let ids = this._availableRecommendations[pattern];
|
let ids = this._availableRecommendations[pattern];
|
||||||
@@ -714,7 +712,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
let { key: pattern, value: ids } = entry;
|
let { key: pattern, value: ids } = entry;
|
||||||
if (match(pattern, model.uri.toString())) {
|
if (match(pattern, model.uri.toString())) {
|
||||||
for (let id of ids) {
|
for (let id of ids) {
|
||||||
if (caseInsensitiveGet(product.extensionImportantTips, id)) {
|
if (caseInsensitiveGet(this.productService.productConfiguration.extensionImportantTips, id)) {
|
||||||
recommendationsToSuggest.push(id);
|
recommendationsToSuggest.push(id);
|
||||||
}
|
}
|
||||||
const filedBasedRecommendation = this._fileBasedRecommendations[id.toLowerCase()] || { recommendedTime: now, sources: [] };
|
const filedBasedRecommendation = this._fileBasedRecommendations[id.toLowerCase()] || { recommendedTime: now, sources: [] };
|
||||||
@@ -768,7 +766,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
const id = recommendationsToSuggest[0];
|
const id = recommendationsToSuggest[0];
|
||||||
const entry = caseInsensitiveGet(product.extensionImportantTips, id);
|
const entry = caseInsensitiveGet(this.productService.productConfiguration.extensionImportantTips, id);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -994,14 +992,14 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If user has any of the tools listed in product.exeBasedExtensionTips, fetch corresponding recommendations
|
* If user has any of the tools listed in this.productService.productConfiguration.exeBasedExtensionTips, fetch corresponding recommendations
|
||||||
*/
|
*/
|
||||||
private fetchExecutableRecommendations(important: boolean): Promise<void> {
|
private fetchExecutableRecommendations(important: boolean): Promise<void> {
|
||||||
const homeDir = os.homedir();
|
const homeDir = os.homedir();
|
||||||
let foundExecutables: Set<string> = new Set<string>();
|
let foundExecutables: Set<string> = new Set<string>();
|
||||||
|
|
||||||
let findExecutable = (exeName: string, tip: IExeBasedExtensionTip, path: string) => {
|
let findExecutable = (exeName: string, tip: IExeBasedExtensionTip, path: string) => {
|
||||||
return pfs.fileExists(path).then(exists => {
|
return this.fileService.exists(URI.file(path)).then(exists => {
|
||||||
if (exists && !foundExecutables.has(exeName)) {
|
if (exists && !foundExecutables.has(exeName)) {
|
||||||
foundExecutables.add(exeName);
|
foundExecutables.add(exeName);
|
||||||
(tip['recommendations'] || []).forEach(extensionId => {
|
(tip['recommendations'] || []).forEach(extensionId => {
|
||||||
@@ -1018,7 +1016,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
|
|
||||||
let promises: Promise<void>[] = [];
|
let promises: Promise<void>[] = [];
|
||||||
// Loop through recommended extensions
|
// Loop through recommended extensions
|
||||||
forEach(product.exeBasedExtensionTips, entry => {
|
forEach(this.productService.productConfiguration.exeBasedExtensionTips, entry => {
|
||||||
if (typeof entry.value !== 'object' || !Array.isArray(entry.value['recommendations'])) {
|
if (typeof entry.value !== 'object' || !Array.isArray(entry.value['recommendations'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1090,7 +1088,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
|
|
||||||
const storageKey = 'extensionsAssistant/dynamicWorkspaceRecommendations';
|
const storageKey = 'extensionsAssistant/dynamicWorkspaceRecommendations';
|
||||||
const workspaceUri = this.contextService.getWorkspace().folders[0].uri;
|
const workspaceUri = this.contextService.getWorkspace().folders[0].uri;
|
||||||
return Promise.all([getHashedRemotesFromUri(workspaceUri, this.fileService, this.textFileService, false), getHashedRemotesFromUri(workspaceUri, this.fileService, this.textFileService, true)]).then(([hashedRemotes1, hashedRemotes2]) => {
|
return Promise.all([this.workspaceStatsService.getHashedRemotesFromUri(workspaceUri, false), this.workspaceStatsService.getHashedRemotesFromUri(workspaceUri, true)]).then(([hashedRemotes1, hashedRemotes2]) => {
|
||||||
const hashedRemotes = (hashedRemotes1 || []).concat(hashedRemotes2 || []);
|
const hashedRemotes = (hashedRemotes1 || []).concat(hashedRemotes2 || []);
|
||||||
if (!hashedRemotes.length) {
|
if (!hashedRemotes.length) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -1248,7 +1246,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
|
|||||||
return Promise.reject(new Error(localize('scenarioTypeUndefined', 'The scenario type for extension recommendations must be provided.')));
|
return Promise.reject(new Error(localize('scenarioTypeUndefined', 'The scenario type for extension recommendations must be provided.')));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve((product.recommendedExtensionsByScenario[scenarioType] || [])
|
return Promise.resolve((this.productService.productConfiguration.recommendedExtensionsByScenario[scenarioType] || [])
|
||||||
.filter(extensionId => this.isExtensionAllowedToBeRecommended(extensionId))
|
.filter(extensionId => this.isExtensionAllowedToBeRecommended(extensionId))
|
||||||
.map(extensionId => (<IExtensionRecommendation>{ extensionId, sources: ['application'] })));
|
.map(extensionId => (<IExtensionRecommendation>{ extensionId, sources: ['application'] })));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import { NullLogService } from 'vs/platform/log/common/log';
|
|||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
|
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
|
import { IProductService } from 'vs/platform/product/common/product';
|
||||||
|
|
||||||
const mockExtensionGallery: IGalleryExtension[] = [
|
const mockExtensionGallery: IGalleryExtension[] = [
|
||||||
aGalleryExtension('MockExtension1', {
|
aGalleryExtension('MockExtension1', {
|
||||||
|
|||||||
@@ -35,8 +35,7 @@ import { URLService } from 'vs/platform/url/common/urlService';
|
|||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||||
import { SinonStub } from 'sinon';
|
import { SinonStub } from 'sinon';
|
||||||
import { IExperimentService, ExperimentState, ExperimentActionType } from 'vs/workbench/contrib/experiments/common/experimentService';
|
import { IExperimentService, ExperimentState, ExperimentActionType, ExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||||
import { ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
|
|
||||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||||
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl';
|
||||||
import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||||
|
|||||||
@@ -73,8 +73,8 @@ export class FeedbackDropdown extends Dropdown {
|
|||||||
this.feedbackDelegate = options.feedbackService;
|
this.feedbackDelegate = options.feedbackService;
|
||||||
this.maxFeedbackCharacters = this.feedbackDelegate.getCharacterLimit(this.sentiment);
|
this.maxFeedbackCharacters = this.feedbackDelegate.getCharacterLimit(this.sentiment);
|
||||||
|
|
||||||
if (productService.sendASmile) {
|
if (productService.productConfiguration.sendASmile) {
|
||||||
this.requestFeatureLink = productService.sendASmile.requestFeatureUrl;
|
this.requestFeatureLink = productService.productConfiguration.sendASmile.requestFeatureUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.integrityService.isPure().then(result => {
|
this.integrityService.isPure().then(result => {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export class FeedbackStatusbarConribution extends Disposable implements IWorkben
|
|||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (productService.sendASmile) {
|
if (productService.productConfiguration.sendASmile) {
|
||||||
this.entry = this._register(statusbarService.addEntry(this.getStatusEntry(), 'status.feedback', localize('status.feedback', "Tweet Feedback"), StatusbarAlignment.RIGHT, -100 /* towards the end of the right hand side */));
|
this.entry = this._register(statusbarService.addEntry(this.getStatusEntry(), 'status.feedback', localize('status.feedback', "Tweet Feedback"), StatusbarAlignment.RIGHT, -100 /* towards the end of the right hand side */));
|
||||||
|
|
||||||
CommandsRegistry.registerCommand('_feedback.open', () => this.toggleFeedback());
|
CommandsRegistry.registerCommand('_feedback.open', () => this.toggleFeedback());
|
||||||
|
|||||||
@@ -7,16 +7,15 @@ import * as nls from 'vs/nls';
|
|||||||
import { BaseBinaryResourceEditor } from 'vs/workbench/browser/parts/editor/binaryEditor';
|
import { BaseBinaryResourceEditor } from 'vs/workbench/browser/parts/editor/binaryEditor';
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
|
||||||
import { EditorInput, EditorOptions } from 'vs/workbench/common/editor';
|
import { EditorInput, EditorOptions } from 'vs/workbench/common/editor';
|
||||||
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
|
||||||
import { URI } from 'vs/base/common/uri';
|
|
||||||
import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files';
|
import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files';
|
||||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of editor for binary files like images.
|
* An implementation of editor for binary files like images.
|
||||||
@@ -28,7 +27,7 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor {
|
|||||||
constructor(
|
constructor(
|
||||||
@ITelemetryService telemetryService: ITelemetryService,
|
@ITelemetryService telemetryService: ITelemetryService,
|
||||||
@IThemeService themeService: IThemeService,
|
@IThemeService themeService: IThemeService,
|
||||||
@IWindowsService private readonly windowsService: IWindowsService,
|
@IOpenerService private readonly openerService: IOpenerService,
|
||||||
@IEditorService private readonly editorService: IEditorService,
|
@IEditorService private readonly editorService: IEditorService,
|
||||||
@IStorageService storageService: IStorageService,
|
@IStorageService storageService: IStorageService,
|
||||||
@IFileService fileService: IFileService,
|
@IFileService fileService: IFileService,
|
||||||
@@ -39,7 +38,7 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor {
|
|||||||
BinaryFileEditor.ID,
|
BinaryFileEditor.ID,
|
||||||
{
|
{
|
||||||
openInternal: (input, options) => this.openInternal(input, options),
|
openInternal: (input, options) => this.openInternal(input, options),
|
||||||
openExternal: resource => this.openExternal(resource)
|
openExternal: resource => this.openerService.openExternal(resource)
|
||||||
},
|
},
|
||||||
telemetryService,
|
telemetryService,
|
||||||
themeService,
|
themeService,
|
||||||
@@ -58,13 +57,6 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async openExternal(resource: URI): Promise<void> {
|
|
||||||
const didOpen = await this.windowsService.openExternal(resource.toString());
|
|
||||||
if (!didOpen) {
|
|
||||||
return this.windowsService.showItemInFolder(resource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getTitle(): string | null {
|
getTitle(): string | null {
|
||||||
return this.input ? this.input.getName() : nls.localize('binaryFileEditor', "Binary File Viewer");
|
return this.input ? this.input.getName() : nls.localize('binaryFileEditor', "Binary File Viewer");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import { ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet';
|
|||||||
import { KeyChord, KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
import { KeyChord, KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||||
|
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||||
|
|
||||||
export class ExplorerViewletViewsContribution extends Disposable implements IWorkbenchContribution {
|
export class ExplorerViewletViewsContribution extends Disposable implements IWorkbenchContribution {
|
||||||
|
|
||||||
@@ -202,7 +203,7 @@ export class ExplorerViewlet extends ViewContainerViewlet {
|
|||||||
openEditorsView.setStructuralRefreshDelay(delay);
|
openEditorsView.setStructuralRefreshDelay(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
let openedEditor: IEditor | null = null;
|
let openedEditor: IEditor | undefined;
|
||||||
try {
|
try {
|
||||||
openedEditor = await this.editorService.openEditor(editor, options, group);
|
openedEditor = await this.editorService.openEditor(editor, options, group);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -214,7 +215,7 @@ export class ExplorerViewlet extends ViewContainerViewlet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return openedEditor;
|
return withUndefinedAsNull(openedEditor);
|
||||||
});
|
});
|
||||||
|
|
||||||
const explorerInstantiator = this.instantiationService.createChild(new ServiceCollection([IEditorService, delegatingEditorService]));
|
const explorerInstantiator = this.instantiationService.createChild(new ServiceCollection([IEditorService, delegatingEditorService]));
|
||||||
|
|||||||
@@ -503,7 +503,7 @@ export class GlobalCompareResourcesAction extends Action {
|
|||||||
override: this.editorService.openEditor({
|
override: this.editorService.openEditor({
|
||||||
leftResource: activeResource,
|
leftResource: activeResource,
|
||||||
rightResource: resource
|
rightResource: resource
|
||||||
}).then(() => null)
|
}).then(() => undefined)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,7 +158,11 @@ export class ExplorerService implements IExplorerService {
|
|||||||
// Stat needs to be resolved first and then revealed
|
// Stat needs to be resolved first and then revealed
|
||||||
const options: IResolveFileOptions = { resolveTo: [resource], resolveMetadata: this.sortOrder === 'modified' };
|
const options: IResolveFileOptions = { resolveTo: [resource], resolveMetadata: this.sortOrder === 'modified' };
|
||||||
const workspaceFolder = this.contextService.getWorkspaceFolder(resource);
|
const workspaceFolder = this.contextService.getWorkspaceFolder(resource);
|
||||||
const rootUri = workspaceFolder ? workspaceFolder.uri : this.roots[0].resource;
|
if (workspaceFolder === null) {
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
}
|
||||||
|
const rootUri = workspaceFolder.uri;
|
||||||
|
|
||||||
const root = this.roots.filter(r => r.resource.toString() === rootUri.toString()).pop()!;
|
const root = this.roots.filter(r => r.resource.toString() === rootUri.toString()).pop()!;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -534,8 +534,10 @@ export class MarkersPanel extends Panel implements IMarkerFilterController {
|
|||||||
const span1 = dom.append(container, dom.$('span'));
|
const span1 = dom.append(container, dom.$('span'));
|
||||||
span1.textContent = Messages.MARKERS_PANEL_NO_PROBLEMS_FILTERS;
|
span1.textContent = Messages.MARKERS_PANEL_NO_PROBLEMS_FILTERS;
|
||||||
const link = dom.append(container, dom.$('a.messageAction'));
|
const link = dom.append(container, dom.$('a.messageAction'));
|
||||||
link.textContent = localize('clearFilter', "Clear Filter.");
|
link.textContent = localize('clearFilter', "Clear Filter");
|
||||||
link.setAttribute('tabIndex', '0');
|
link.setAttribute('tabIndex', '0');
|
||||||
|
const span2 = dom.append(container, dom.$('span'));
|
||||||
|
span2.textContent = '.';
|
||||||
dom.addStandardDisposableListener(link, dom.EventType.CLICK, () => this.filterAction.filterText = '');
|
dom.addStandardDisposableListener(link, dom.EventType.CLICK, () => this.filterAction.filterText = '');
|
||||||
dom.addStandardDisposableListener(link, dom.EventType.KEY_DOWN, (e: IKeyboardEvent) => {
|
dom.addStandardDisposableListener(link, dom.EventType.KEY_DOWN, (e: IKeyboardEvent) => {
|
||||||
if (e.equals(KeyCode.Enter) || e.equals(KeyCode.Space)) {
|
if (e.equals(KeyCode.Enter) || e.equals(KeyCode.Space)) {
|
||||||
|
|||||||