Archived
Merge from vscode e558dc6ea73a75bd69d7a0b485f0e7e4194c66bf (#6864)
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
trigger:
|
||||||
|
branches:
|
||||||
|
include: ['master']
|
||||||
|
pr:
|
||||||
|
branches:
|
||||||
|
include: ['master']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- task: NodeTool@0
|
||||||
|
inputs:
|
||||||
|
versionSpec: "10.15.1"
|
||||||
|
|
||||||
|
- task: AzureKeyVault@1
|
||||||
|
displayName: 'Azure Key Vault: Get Secrets'
|
||||||
|
inputs:
|
||||||
|
azureSubscription: 'vscode-builds-subscription'
|
||||||
|
KeyVaultName: vscode
|
||||||
|
|
||||||
|
- script: |
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cat << EOF > ~/.netrc
|
||||||
|
machine github.com
|
||||||
|
login vscode
|
||||||
|
password $(github-distro-mixin-password)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
git config user.email "vscode@microsoft.com"
|
||||||
|
git config user.name "VSCode"
|
||||||
|
|
||||||
|
git checkout origin/ben/electron-test
|
||||||
|
git merge origin/master
|
||||||
|
|
||||||
|
# Push master branch into exploration branch
|
||||||
|
git push origin HEAD:ben/electron-test
|
||||||
|
|
||||||
|
displayName: Sync & Merge Exploration
|
||||||
@@ -19,18 +19,23 @@ class AbstractGlobalsRuleWalker extends Lint.RuleWalker {
|
|||||||
const checker = this.program.getTypeChecker();
|
const checker = this.program.getTypeChecker();
|
||||||
const symbol = checker.getSymbolAtLocation(node);
|
const symbol = checker.getSymbolAtLocation(node);
|
||||||
if (symbol) {
|
if (symbol) {
|
||||||
const valueDeclaration = symbol.valueDeclaration;
|
const declarations = symbol.declarations;
|
||||||
if (valueDeclaration) {
|
if (Array.isArray(declarations) && symbol.declarations.some(declaration => {
|
||||||
const parent = valueDeclaration.parent;
|
if (declaration) {
|
||||||
if (parent) {
|
const parent = declaration.parent;
|
||||||
const sourceFile = parent.getSourceFile();
|
if (parent) {
|
||||||
if (sourceFile) {
|
const sourceFile = parent.getSourceFile();
|
||||||
const fileName = sourceFile.fileName;
|
if (sourceFile) {
|
||||||
if (fileName && fileName.indexOf(this.getDefinitionPattern()) >= 0) {
|
const fileName = sourceFile.fileName;
|
||||||
this.addFailureAtNode(node, `Cannot use global '${node.text}' in '${this._config.target}'`);
|
if (fileName && fileName.indexOf(this.getDefinitionPattern()) >= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
})) {
|
||||||
|
this.addFailureAtNode(node, `Cannot use global '${node.text}' in '${this._config.target}'`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,18 +30,24 @@ export abstract class AbstractGlobalsRuleWalker extends Lint.RuleWalker {
|
|||||||
const checker = this.program.getTypeChecker();
|
const checker = this.program.getTypeChecker();
|
||||||
const symbol = checker.getSymbolAtLocation(node);
|
const symbol = checker.getSymbolAtLocation(node);
|
||||||
if (symbol) {
|
if (symbol) {
|
||||||
const valueDeclaration = symbol.valueDeclaration;
|
const declarations = symbol.declarations;
|
||||||
if (valueDeclaration) {
|
if (Array.isArray(declarations) && symbol.declarations.some(declaration => {
|
||||||
const parent = valueDeclaration.parent;
|
if (declaration) {
|
||||||
if (parent) {
|
const parent = declaration.parent;
|
||||||
const sourceFile = parent.getSourceFile();
|
if (parent) {
|
||||||
if (sourceFile) {
|
const sourceFile = parent.getSourceFile();
|
||||||
const fileName = sourceFile.fileName;
|
if (sourceFile) {
|
||||||
if (fileName && fileName.indexOf(this.getDefinitionPattern()) >= 0) {
|
const fileName = sourceFile.fileName;
|
||||||
this.addFailureAtNode(node, `Cannot use global '${node.text}' in '${this._config.target}'`);
|
if (fileName && fileName.indexOf(this.getDefinitionPattern()) >= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
})) {
|
||||||
|
this.addFailureAtNode(node, `Cannot use global '${node.text}' in '${this._config.target}'`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"watch": "gulp watch-extension:configuration-editing"
|
"watch": "gulp watch-extension:configuration-editing"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsonc-parser": "2.0.2",
|
"jsonc-parser": "^2.1.1",
|
||||||
"vscode-nls": "^4.0.0"
|
"vscode-nls": "^4.0.0"
|
||||||
},
|
},
|
||||||
"contributes": {
|
"contributes": {
|
||||||
|
|||||||
@@ -7,10 +7,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9"
|
||||||
integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw==
|
integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw==
|
||||||
|
|
||||||
jsonc-parser@2.0.2:
|
jsonc-parser@^2.1.1:
|
||||||
version "2.0.2"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.2.tgz#42fcf56d70852a043fadafde51ddb4a85649978d"
|
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.1.1.tgz#83dc3d7a6e7186346b889b1280eefa04446c6d3e"
|
||||||
integrity sha512-TSU435K5tEKh3g7bam1AFf+uZrISheoDsLlpmAo6wWZYqjsnd09lHYK1Qo+moK4Ikifev1Gdpa69g4NELKnCrQ==
|
integrity sha512-VC0CjnWJylKB1iov4u76/W/5Ef0ydDkjtYWxoZ9t3HdWlSnZQwZL5MgFikaB/EtQ4RmMEw3tmQzuYnZA2/Ja1g==
|
||||||
|
|
||||||
vscode-nls@^4.0.0:
|
vscode-nls@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"watch": "gulp watch-extension:extension-editing"
|
"watch": "gulp watch-extension:extension-editing"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsonc-parser": "^2.0.2",
|
"jsonc-parser": "^2.1.1",
|
||||||
"markdown-it": "^8.3.1",
|
"markdown-it": "^8.3.1",
|
||||||
"parse5": "^3.0.2",
|
"parse5": "^3.0.2",
|
||||||
"vscode-nls": "^4.0.0"
|
"vscode-nls": "^4.0.0"
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ entities@~1.1.1:
|
|||||||
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
|
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
|
||||||
integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA=
|
integrity sha1-blwtClYhtdra7O+AuQ7ftc13cvA=
|
||||||
|
|
||||||
jsonc-parser@^2.0.2:
|
jsonc-parser@^2.1.1:
|
||||||
version "2.0.2"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.2.tgz#42fcf56d70852a043fadafde51ddb4a85649978d"
|
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.1.1.tgz#83dc3d7a6e7186346b889b1280eefa04446c6d3e"
|
||||||
integrity sha512-TSU435K5tEKh3g7bam1AFf+uZrISheoDsLlpmAo6wWZYqjsnd09lHYK1Qo+moK4Ikifev1Gdpa69g4NELKnCrQ==
|
integrity sha512-VC0CjnWJylKB1iov4u76/W/5Ef0ydDkjtYWxoZ9t3HdWlSnZQwZL5MgFikaB/EtQ4RmMEw3tmQzuYnZA2/Ja1g==
|
||||||
|
|
||||||
linkify-it@^2.0.0:
|
linkify-it@^2.0.0:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
|
|||||||
@@ -145,11 +145,14 @@ export function activate(context: ExtensionContext) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const schemaDocuments: { [uri: string]: boolean } = {};
|
||||||
|
|
||||||
// handle content request
|
// handle content request
|
||||||
client.onRequest(VSCodeContentRequest.type, (uriPath: string) => {
|
client.onRequest(VSCodeContentRequest.type, (uriPath: string) => {
|
||||||
let uri = Uri.parse(uriPath);
|
let uri = Uri.parse(uriPath);
|
||||||
if (uri.scheme !== 'http' && uri.scheme !== 'https') {
|
if (uri.scheme !== 'http' && uri.scheme !== 'https') {
|
||||||
return workspace.openTextDocument(uri).then(doc => {
|
return workspace.openTextDocument(uri).then(doc => {
|
||||||
|
schemaDocuments[uri.toString()] = true;
|
||||||
return doc.getText();
|
return doc.getText();
|
||||||
}, error => {
|
}, error => {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
@@ -164,10 +167,12 @@ export function activate(context: ExtensionContext) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let handleContentChange = (uri: Uri) => {
|
let handleContentChange = (uriString: string) => {
|
||||||
if (uri.scheme === 'vscode' && uri.authority === 'schemas') {
|
if (schemaDocuments[uriString]) {
|
||||||
client.sendNotification(SchemaContentChangeNotification.type, uri.toString());
|
client.sendNotification(SchemaContentChangeNotification.type, uriString);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
let handleActiveEditorChange = (activeEditor?: TextEditor) => {
|
let handleActiveEditorChange = (activeEditor?: TextEditor) => {
|
||||||
@@ -184,10 +189,13 @@ export function activate(context: ExtensionContext) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
toDispose.push(workspace.onDidChangeTextDocument(e => handleContentChange(e.document.uri)));
|
toDispose.push(workspace.onDidChangeTextDocument(e => handleContentChange(e.document.uri.toString())));
|
||||||
toDispose.push(workspace.onDidCloseTextDocument(d => {
|
toDispose.push(workspace.onDidCloseTextDocument(d => {
|
||||||
handleContentChange(d.uri);
|
const uriString = d.uri.toString();
|
||||||
fileSchemaErrors.delete(d.uri.toString());
|
if (handleContentChange(uriString)) {
|
||||||
|
delete schemaDocuments[uriString];
|
||||||
|
}
|
||||||
|
fileSchemaErrors.delete(uriString);
|
||||||
}));
|
}));
|
||||||
toDispose.push(window.onDidChangeActiveTextEditor(handleActiveEditorChange));
|
toDispose.push(window.onDidChangeActiveTextEditor(handleActiveEditorChange));
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
},
|
},
|
||||||
"main": "./out/jsonServerMain",
|
"main": "./out/jsonServerMain",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsonc-parser": "^2.1.0",
|
"jsonc-parser": "^2.1.1",
|
||||||
"request-light": "^0.2.4",
|
"request-light": "^0.2.4",
|
||||||
"vscode-json-languageservice": "^3.3.1",
|
"vscode-json-languageservice": "^3.3.1",
|
||||||
"vscode-languageserver": "^5.3.0-next.8",
|
"vscode-languageserver": "^5.3.0-next.8",
|
||||||
|
|||||||
@@ -59,6 +59,11 @@ jsonc-parser@^2.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.1.0.tgz#eb0d0c7a3c33048524ce3574c57c7278fb2f1bf3"
|
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.1.0.tgz#eb0d0c7a3c33048524ce3574c57c7278fb2f1bf3"
|
||||||
integrity sha512-n9GrT8rrr2fhvBbANa1g+xFmgGK5X91KFeDwlKQ3+SJfmH5+tKv/M/kahx/TXOMflfWHKGKqKyfHQaLKTNzJ6w==
|
integrity sha512-n9GrT8rrr2fhvBbANa1g+xFmgGK5X91KFeDwlKQ3+SJfmH5+tKv/M/kahx/TXOMflfWHKGKqKyfHQaLKTNzJ6w==
|
||||||
|
|
||||||
|
jsonc-parser@^2.1.1:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.1.1.tgz#83dc3d7a6e7186346b889b1280eefa04446c6d3e"
|
||||||
|
integrity sha512-VC0CjnWJylKB1iov4u76/W/5Ef0ydDkjtYWxoZ9t3HdWlSnZQwZL5MgFikaB/EtQ4RmMEw3tmQzuYnZA2/Ja1g==
|
||||||
|
|
||||||
ms@2.0.0:
|
ms@2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||||
|
|||||||
@@ -320,7 +320,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"highlight.js": "9.15.8",
|
"highlight.js": "9.15.8",
|
||||||
"markdown-it": "^8.4.2",
|
"markdown-it": "^9.1.0",
|
||||||
"markdown-it-front-matter": "^0.1.2",
|
"markdown-it-front-matter": "^0.1.2",
|
||||||
"vscode-extension-telemetry": "0.1.1",
|
"vscode-extension-telemetry": "0.1.1",
|
||||||
"vscode-nls": "^4.0.0"
|
"vscode-nls": "^4.0.0"
|
||||||
|
|||||||
@@ -3900,10 +3900,10 @@ markdown-it-front-matter@^0.1.2:
|
|||||||
resolved "https://registry.yarnpkg.com/markdown-it-front-matter/-/markdown-it-front-matter-0.1.2.tgz#e50bf56e77e6a4f5ac4ffa894d4d45ccd9896b20"
|
resolved "https://registry.yarnpkg.com/markdown-it-front-matter/-/markdown-it-front-matter-0.1.2.tgz#e50bf56e77e6a4f5ac4ffa894d4d45ccd9896b20"
|
||||||
integrity sha1-5Qv1bnfmpPWsT/qJTU1FzNmJayA=
|
integrity sha1-5Qv1bnfmpPWsT/qJTU1FzNmJayA=
|
||||||
|
|
||||||
markdown-it@^8.4.2:
|
markdown-it@^9.1.0:
|
||||||
version "8.4.2"
|
version "9.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54"
|
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-9.1.0.tgz#df9601c168568704d554b1fff9af0c5b561168d9"
|
||||||
integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==
|
integrity sha512-xHKG4C8iPriyfu/jc2hsCC045fKrMQ0VexX2F1FGYiRxDxqMB2aAhF8WauJ3fltn2kb90moGBkiiEdooGIg55w==
|
||||||
dependencies:
|
dependencies:
|
||||||
argparse "^1.0.7"
|
argparse "^1.0.7"
|
||||||
entities "~1.1.1"
|
entities "~1.1.1"
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ set VSCODE_CLI=1
|
|||||||
set ELECTRON_DEFAULT_ERROR_MODE=1
|
set ELECTRON_DEFAULT_ERROR_MODE=1
|
||||||
set ELECTRON_ENABLE_LOGGING=1
|
set ELECTRON_ENABLE_LOGGING=1
|
||||||
set ELECTRON_ENABLE_STACK_DUMPING=1
|
set ELECTRON_ENABLE_STACK_DUMPING=1
|
||||||
|
set VSCODE_LOGS=
|
||||||
|
|
||||||
:: Launch Code
|
:: Launch Code
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,12 @@ import { IConfigurationResolverService } from 'vs/workbench/services/configurati
|
|||||||
import { IFileService } from 'vs/platform/files/common/files';
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
import * as pfs from 'vs/base/node/pfs';
|
import * as pfs from 'vs/base/node/pfs';
|
||||||
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||||
|
import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api';
|
||||||
|
|
||||||
class TestEnvironmentService implements IWorkbenchEnvironmentService {
|
class TestEnvironmentService implements IWorkbenchEnvironmentService {
|
||||||
|
logFile: URI;
|
||||||
|
options?: IWorkbenchConstructionOptions;
|
||||||
|
galleryMachineIdResource?: URI;
|
||||||
webviewCspSource: string;
|
webviewCspSource: string;
|
||||||
webviewCspRule: string;
|
webviewCspRule: string;
|
||||||
localeResource: URI;
|
localeResource: URI;
|
||||||
|
|||||||
@@ -1186,22 +1186,14 @@ export function animate(fn: () => void): IDisposable {
|
|||||||
return toDisposable(() => stepDisposable.dispose());
|
return toDisposable(() => stepDisposable.dispose());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RemoteAuthorities.setPreferredWebSchema(/^https:/.test(window.location.href) ? 'https' : 'http');
|
||||||
|
|
||||||
const _location = URI.parse(window.location.href);
|
|
||||||
|
|
||||||
export function asDomUri(uri: URI): URI {
|
export function asDomUri(uri: URI): URI {
|
||||||
if (!uri) {
|
if (!uri) {
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
if (Schemas.vscodeRemote === uri.scheme) {
|
if (Schemas.vscodeRemote === uri.scheme) {
|
||||||
if (platform.isWeb) {
|
return RemoteAuthorities.rewrite(uri.authority, uri.path);
|
||||||
// rewrite vscode-remote-uris to uris of the window location
|
|
||||||
// so that they can be intercepted by the service worker
|
|
||||||
return _location.with({ path: '/vscode-remote', query: JSON.stringify(uri) });
|
|
||||||
} else {
|
|
||||||
return RemoteAuthorities.rewrite(uri.authority, uri.path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,9 +197,11 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
|
|||||||
allowedAttributes: {
|
allowedAttributes: {
|
||||||
'a': ['href', 'name', 'target', 'data-href'],
|
'a': ['href', 'name', 'target', 'data-href'],
|
||||||
'iframe': ['allowfullscreen', 'frameborder', 'src'],
|
'iframe': ['allowfullscreen', 'frameborder', 'src'],
|
||||||
'img': ['src', 'title', 'alt', 'width', 'height']
|
'img': ['src', 'title', 'alt', 'width', 'height'],
|
||||||
|
'div': ['class', 'data-code']
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
signalInnerHTML!();
|
signalInnerHTML!();
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ export interface IFindInputOptions extends IFindInputStyles {
|
|||||||
readonly validation?: IInputValidator;
|
readonly validation?: IInputValidator;
|
||||||
readonly label: string;
|
readonly label: string;
|
||||||
readonly flexibleHeight?: boolean;
|
readonly flexibleHeight?: boolean;
|
||||||
|
readonly flexibleWidth?: boolean;
|
||||||
|
readonly flexibleMaxHeight?: number;
|
||||||
|
|
||||||
readonly appendCaseSensitiveLabel?: string;
|
readonly appendCaseSensitiveLabel?: string;
|
||||||
readonly appendWholeWordsLabel?: string;
|
readonly appendWholeWordsLabel?: string;
|
||||||
@@ -119,6 +121,8 @@ export class FindInput extends Widget {
|
|||||||
const appendRegexLabel = options.appendRegexLabel || '';
|
const appendRegexLabel = options.appendRegexLabel || '';
|
||||||
const history = options.history || [];
|
const history = options.history || [];
|
||||||
const flexibleHeight = !!options.flexibleHeight;
|
const flexibleHeight = !!options.flexibleHeight;
|
||||||
|
const flexibleWidth = !!options.flexibleWidth;
|
||||||
|
const flexibleMaxHeight = options.flexibleMaxHeight;
|
||||||
|
|
||||||
this.domNode = document.createElement('div');
|
this.domNode = document.createElement('div');
|
||||||
dom.addClass(this.domNode, 'monaco-findInput');
|
dom.addClass(this.domNode, 'monaco-findInput');
|
||||||
@@ -142,7 +146,9 @@ export class FindInput extends Widget {
|
|||||||
inputValidationErrorForeground: this.inputValidationErrorForeground,
|
inputValidationErrorForeground: this.inputValidationErrorForeground,
|
||||||
inputValidationErrorBorder: this.inputValidationErrorBorder,
|
inputValidationErrorBorder: this.inputValidationErrorBorder,
|
||||||
history,
|
history,
|
||||||
flexibleHeight
|
flexibleHeight,
|
||||||
|
flexibleWidth,
|
||||||
|
flexibleMaxHeight
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.regex = this._register(new RegexCheckbox({
|
this.regex = this._register(new RegexCheckbox({
|
||||||
@@ -194,11 +200,7 @@ export class FindInput extends Widget {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
if (this._showOptionButtons) {
|
if (this._showOptionButtons) {
|
||||||
const paddingRight = (this.caseSensitive.width() + this.wholeWords.width() + this.regex.width()) + 'px';
|
this.inputBox.paddingRight = this.caseSensitive.width() + this.wholeWords.width() + this.regex.width();
|
||||||
this.inputBox.inputElement.style.paddingRight = paddingRight;
|
|
||||||
if (this.inputBox.mirrorElement) {
|
|
||||||
this.inputBox.mirrorElement.style.paddingRight = paddingRight;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arrow-Key support to navigate between options
|
// Arrow-Key support to navigate between options
|
||||||
|
|||||||
@@ -0,0 +1,373 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import 'vs/css!./findInput';
|
||||||
|
|
||||||
|
import * as nls from 'vs/nls';
|
||||||
|
import * as dom from 'vs/base/browser/dom';
|
||||||
|
import { IMessage as InputBoxMessage, IInputValidator, IInputBoxStyles, HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||||
|
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
|
||||||
|
import { Widget } from 'vs/base/browser/ui/widget';
|
||||||
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
|
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
|
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||||
|
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||||
|
import { Color } from 'vs/base/common/color';
|
||||||
|
import { ICheckboxStyles, Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
|
||||||
|
import { IFindInputCheckboxOpts } from 'vs/base/browser/ui/findinput/findInputCheckboxes';
|
||||||
|
|
||||||
|
export interface IReplaceInputOptions extends IReplaceInputStyles {
|
||||||
|
readonly placeholder?: string;
|
||||||
|
readonly width?: number;
|
||||||
|
readonly validation?: IInputValidator;
|
||||||
|
readonly label: string;
|
||||||
|
readonly flexibleHeight?: boolean;
|
||||||
|
readonly flexibleWidth?: boolean;
|
||||||
|
readonly flexibleMaxHeight?: number;
|
||||||
|
|
||||||
|
readonly history?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IReplaceInputStyles extends IInputBoxStyles {
|
||||||
|
inputActiveOptionBorder?: Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NLS_DEFAULT_LABEL = nls.localize('defaultLabel', "input");
|
||||||
|
const NLS_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseCheckbox', "Preserve Case");
|
||||||
|
|
||||||
|
export class PreserveCaseCheckbox extends Checkbox {
|
||||||
|
constructor(opts: IFindInputCheckboxOpts) {
|
||||||
|
super({
|
||||||
|
// TODO: does this need its own icon?
|
||||||
|
actionClassName: 'monaco-case-sensitive',
|
||||||
|
title: NLS_PRESERVE_CASE_LABEL + opts.appendTitle,
|
||||||
|
isChecked: opts.isChecked,
|
||||||
|
inputActiveOptionBorder: opts.inputActiveOptionBorder
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ReplaceInput extends Widget {
|
||||||
|
|
||||||
|
static readonly OPTION_CHANGE: string = 'optionChange';
|
||||||
|
|
||||||
|
private contextViewProvider: IContextViewProvider | undefined;
|
||||||
|
private placeholder: string;
|
||||||
|
private validation?: IInputValidator;
|
||||||
|
private label: string;
|
||||||
|
private fixFocusOnOptionClickEnabled = true;
|
||||||
|
|
||||||
|
private inputActiveOptionBorder?: Color;
|
||||||
|
private inputBackground?: Color;
|
||||||
|
private inputForeground?: Color;
|
||||||
|
private inputBorder?: Color;
|
||||||
|
|
||||||
|
private inputValidationInfoBorder?: Color;
|
||||||
|
private inputValidationInfoBackground?: Color;
|
||||||
|
private inputValidationInfoForeground?: Color;
|
||||||
|
private inputValidationWarningBorder?: Color;
|
||||||
|
private inputValidationWarningBackground?: Color;
|
||||||
|
private inputValidationWarningForeground?: Color;
|
||||||
|
private inputValidationErrorBorder?: Color;
|
||||||
|
private inputValidationErrorBackground?: Color;
|
||||||
|
private inputValidationErrorForeground?: Color;
|
||||||
|
|
||||||
|
private preserveCase: PreserveCaseCheckbox;
|
||||||
|
private cachedOptionsWidth: number = 0;
|
||||||
|
public domNode: HTMLElement;
|
||||||
|
public inputBox: HistoryInputBox;
|
||||||
|
|
||||||
|
private readonly _onDidOptionChange = this._register(new Emitter<boolean>());
|
||||||
|
public readonly onDidOptionChange: Event<boolean /* via keyboard */> = this._onDidOptionChange.event;
|
||||||
|
|
||||||
|
private readonly _onKeyDown = this._register(new Emitter<IKeyboardEvent>());
|
||||||
|
public readonly onKeyDown: Event<IKeyboardEvent> = this._onKeyDown.event;
|
||||||
|
|
||||||
|
private readonly _onMouseDown = this._register(new Emitter<IMouseEvent>());
|
||||||
|
public readonly onMouseDown: Event<IMouseEvent> = this._onMouseDown.event;
|
||||||
|
|
||||||
|
private readonly _onInput = this._register(new Emitter<void>());
|
||||||
|
public readonly onInput: Event<void> = this._onInput.event;
|
||||||
|
|
||||||
|
private readonly _onKeyUp = this._register(new Emitter<IKeyboardEvent>());
|
||||||
|
public readonly onKeyUp: Event<IKeyboardEvent> = this._onKeyUp.event;
|
||||||
|
|
||||||
|
private _onPreserveCaseKeyDown = this._register(new Emitter<IKeyboardEvent>());
|
||||||
|
public readonly onPreserveCaseKeyDown: Event<IKeyboardEvent> = this._onPreserveCaseKeyDown.event;
|
||||||
|
|
||||||
|
constructor(parent: HTMLElement | null, contextViewProvider: IContextViewProvider | undefined, private readonly _showOptionButtons: boolean, options: IReplaceInputOptions) {
|
||||||
|
super();
|
||||||
|
this.contextViewProvider = contextViewProvider;
|
||||||
|
this.placeholder = options.placeholder || '';
|
||||||
|
this.validation = options.validation;
|
||||||
|
this.label = options.label || NLS_DEFAULT_LABEL;
|
||||||
|
|
||||||
|
this.inputActiveOptionBorder = options.inputActiveOptionBorder;
|
||||||
|
this.inputBackground = options.inputBackground;
|
||||||
|
this.inputForeground = options.inputForeground;
|
||||||
|
this.inputBorder = options.inputBorder;
|
||||||
|
|
||||||
|
this.inputValidationInfoBorder = options.inputValidationInfoBorder;
|
||||||
|
this.inputValidationInfoBackground = options.inputValidationInfoBackground;
|
||||||
|
this.inputValidationInfoForeground = options.inputValidationInfoForeground;
|
||||||
|
this.inputValidationWarningBorder = options.inputValidationWarningBorder;
|
||||||
|
this.inputValidationWarningBackground = options.inputValidationWarningBackground;
|
||||||
|
this.inputValidationWarningForeground = options.inputValidationWarningForeground;
|
||||||
|
this.inputValidationErrorBorder = options.inputValidationErrorBorder;
|
||||||
|
this.inputValidationErrorBackground = options.inputValidationErrorBackground;
|
||||||
|
this.inputValidationErrorForeground = options.inputValidationErrorForeground;
|
||||||
|
|
||||||
|
const flexibleHeight = !!options.flexibleHeight;
|
||||||
|
const flexibleWidth = !!options.flexibleWidth;
|
||||||
|
const flexibleMaxHeight = options.flexibleMaxHeight;
|
||||||
|
|
||||||
|
this.buildDomNode(options.history || [], flexibleHeight, flexibleWidth, flexibleMaxHeight);
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
parent.appendChild(this.domNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown.fire(e));
|
||||||
|
this.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp.fire(e));
|
||||||
|
this.oninput(this.inputBox.inputElement, (e) => this._onInput.fire());
|
||||||
|
this.onmousedown(this.inputBox.inputElement, (e) => this._onMouseDown.fire(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public enable(): void {
|
||||||
|
dom.removeClass(this.domNode, 'disabled');
|
||||||
|
this.inputBox.enable();
|
||||||
|
this.preserveCase.enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public disable(): void {
|
||||||
|
dom.addClass(this.domNode, 'disabled');
|
||||||
|
this.inputBox.disable();
|
||||||
|
this.preserveCase.disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public setFocusInputOnOptionClick(value: boolean): void {
|
||||||
|
this.fixFocusOnOptionClickEnabled = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setEnabled(enabled: boolean): void {
|
||||||
|
if (enabled) {
|
||||||
|
this.enable();
|
||||||
|
} else {
|
||||||
|
this.disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
this.clearValidation();
|
||||||
|
this.setValue('');
|
||||||
|
this.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getValue(): string {
|
||||||
|
return this.inputBox.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setValue(value: string): void {
|
||||||
|
if (this.inputBox.value !== value) {
|
||||||
|
this.inputBox.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public onSearchSubmit(): void {
|
||||||
|
this.inputBox.addToHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public style(styles: IReplaceInputStyles): void {
|
||||||
|
this.inputActiveOptionBorder = styles.inputActiveOptionBorder;
|
||||||
|
this.inputBackground = styles.inputBackground;
|
||||||
|
this.inputForeground = styles.inputForeground;
|
||||||
|
this.inputBorder = styles.inputBorder;
|
||||||
|
|
||||||
|
this.inputValidationInfoBackground = styles.inputValidationInfoBackground;
|
||||||
|
this.inputValidationInfoForeground = styles.inputValidationInfoForeground;
|
||||||
|
this.inputValidationInfoBorder = styles.inputValidationInfoBorder;
|
||||||
|
this.inputValidationWarningBackground = styles.inputValidationWarningBackground;
|
||||||
|
this.inputValidationWarningForeground = styles.inputValidationWarningForeground;
|
||||||
|
this.inputValidationWarningBorder = styles.inputValidationWarningBorder;
|
||||||
|
this.inputValidationErrorBackground = styles.inputValidationErrorBackground;
|
||||||
|
this.inputValidationErrorForeground = styles.inputValidationErrorForeground;
|
||||||
|
this.inputValidationErrorBorder = styles.inputValidationErrorBorder;
|
||||||
|
|
||||||
|
this.applyStyles();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected applyStyles(): void {
|
||||||
|
if (this.domNode) {
|
||||||
|
const checkBoxStyles: ICheckboxStyles = {
|
||||||
|
inputActiveOptionBorder: this.inputActiveOptionBorder,
|
||||||
|
};
|
||||||
|
this.preserveCase.style(checkBoxStyles);
|
||||||
|
|
||||||
|
const inputBoxStyles: IInputBoxStyles = {
|
||||||
|
inputBackground: this.inputBackground,
|
||||||
|
inputForeground: this.inputForeground,
|
||||||
|
inputBorder: this.inputBorder,
|
||||||
|
inputValidationInfoBackground: this.inputValidationInfoBackground,
|
||||||
|
inputValidationInfoForeground: this.inputValidationInfoForeground,
|
||||||
|
inputValidationInfoBorder: this.inputValidationInfoBorder,
|
||||||
|
inputValidationWarningBackground: this.inputValidationWarningBackground,
|
||||||
|
inputValidationWarningForeground: this.inputValidationWarningForeground,
|
||||||
|
inputValidationWarningBorder: this.inputValidationWarningBorder,
|
||||||
|
inputValidationErrorBackground: this.inputValidationErrorBackground,
|
||||||
|
inputValidationErrorForeground: this.inputValidationErrorForeground,
|
||||||
|
inputValidationErrorBorder: this.inputValidationErrorBorder
|
||||||
|
};
|
||||||
|
this.inputBox.style(inputBoxStyles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public select(): void {
|
||||||
|
this.inputBox.select();
|
||||||
|
}
|
||||||
|
|
||||||
|
public focus(): void {
|
||||||
|
this.inputBox.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPreserveCase(): boolean {
|
||||||
|
return this.preserveCase.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setPreserveCase(value: boolean): void {
|
||||||
|
this.preserveCase.checked = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public focusOnPreserve(): void {
|
||||||
|
this.preserveCase.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _lastHighlightFindOptions: number = 0;
|
||||||
|
public highlightFindOptions(): void {
|
||||||
|
dom.removeClass(this.domNode, 'highlight-' + (this._lastHighlightFindOptions));
|
||||||
|
this._lastHighlightFindOptions = 1 - this._lastHighlightFindOptions;
|
||||||
|
dom.addClass(this.domNode, 'highlight-' + (this._lastHighlightFindOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildDomNode(history: string[], flexibleHeight: boolean, flexibleWidth: boolean, flexibleMaxHeight: number | undefined): void {
|
||||||
|
this.domNode = document.createElement('div');
|
||||||
|
dom.addClass(this.domNode, 'monaco-findInput');
|
||||||
|
|
||||||
|
this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {
|
||||||
|
ariaLabel: this.label || '',
|
||||||
|
placeholder: this.placeholder || '',
|
||||||
|
validationOptions: {
|
||||||
|
validation: this.validation
|
||||||
|
},
|
||||||
|
inputBackground: this.inputBackground,
|
||||||
|
inputForeground: this.inputForeground,
|
||||||
|
inputBorder: this.inputBorder,
|
||||||
|
inputValidationInfoBackground: this.inputValidationInfoBackground,
|
||||||
|
inputValidationInfoForeground: this.inputValidationInfoForeground,
|
||||||
|
inputValidationInfoBorder: this.inputValidationInfoBorder,
|
||||||
|
inputValidationWarningBackground: this.inputValidationWarningBackground,
|
||||||
|
inputValidationWarningForeground: this.inputValidationWarningForeground,
|
||||||
|
inputValidationWarningBorder: this.inputValidationWarningBorder,
|
||||||
|
inputValidationErrorBackground: this.inputValidationErrorBackground,
|
||||||
|
inputValidationErrorForeground: this.inputValidationErrorForeground,
|
||||||
|
inputValidationErrorBorder: this.inputValidationErrorBorder,
|
||||||
|
history,
|
||||||
|
flexibleHeight,
|
||||||
|
flexibleWidth,
|
||||||
|
flexibleMaxHeight
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.preserveCase = this._register(new PreserveCaseCheckbox({
|
||||||
|
appendTitle: '',
|
||||||
|
isChecked: false,
|
||||||
|
inputActiveOptionBorder: this.inputActiveOptionBorder
|
||||||
|
}));
|
||||||
|
this._register(this.preserveCase.onChange(viaKeyboard => {
|
||||||
|
this._onDidOptionChange.fire(viaKeyboard);
|
||||||
|
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
|
||||||
|
this.inputBox.focus();
|
||||||
|
}
|
||||||
|
this.validate();
|
||||||
|
}));
|
||||||
|
this._register(this.preserveCase.onKeyDown(e => {
|
||||||
|
this._onPreserveCaseKeyDown.fire(e);
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (this._showOptionButtons) {
|
||||||
|
this.cachedOptionsWidth = this.preserveCase.width();
|
||||||
|
} else {
|
||||||
|
this.cachedOptionsWidth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrow-Key support to navigate between options
|
||||||
|
let indexes = [this.preserveCase.domNode];
|
||||||
|
this.onkeydown(this.domNode, (event: IKeyboardEvent) => {
|
||||||
|
if (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) {
|
||||||
|
let index = indexes.indexOf(<HTMLElement>document.activeElement);
|
||||||
|
if (index >= 0) {
|
||||||
|
let newIndex: number = -1;
|
||||||
|
if (event.equals(KeyCode.RightArrow)) {
|
||||||
|
newIndex = (index + 1) % indexes.length;
|
||||||
|
} else if (event.equals(KeyCode.LeftArrow)) {
|
||||||
|
if (index === 0) {
|
||||||
|
newIndex = indexes.length - 1;
|
||||||
|
} else {
|
||||||
|
newIndex = index - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.equals(KeyCode.Escape)) {
|
||||||
|
indexes[index].blur();
|
||||||
|
} else if (newIndex >= 0) {
|
||||||
|
indexes[newIndex].focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
dom.EventHelper.stop(event, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
let controls = document.createElement('div');
|
||||||
|
controls.className = 'controls';
|
||||||
|
controls.style.display = this._showOptionButtons ? 'block' : 'none';
|
||||||
|
controls.appendChild(this.preserveCase.domNode);
|
||||||
|
|
||||||
|
this.domNode.appendChild(controls);
|
||||||
|
}
|
||||||
|
|
||||||
|
public validate(): void {
|
||||||
|
if (this.inputBox) {
|
||||||
|
this.inputBox.validate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public showMessage(message: InputBoxMessage): void {
|
||||||
|
if (this.inputBox) {
|
||||||
|
this.inputBox.showMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public clearMessage(): void {
|
||||||
|
if (this.inputBox) {
|
||||||
|
this.inputBox.hideMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearValidation(): void {
|
||||||
|
if (this.inputBox) {
|
||||||
|
this.inputBox.hideMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public set width(newWidth: number) {
|
||||||
|
this.inputBox.paddingRight = this.cachedOptionsWidth;
|
||||||
|
this.inputBox.width = newWidth;
|
||||||
|
this.domNode.style.width = newWidth + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,8 @@
|
|||||||
display: block;
|
display: block;
|
||||||
-ms-overflow-style: none; /* IE 10+ */
|
-ms-overflow-style: none; /* IE 10+ */
|
||||||
overflow: -moz-scrollbars-none; /* Firefox */
|
overflow: -moz-scrollbars-none; /* Firefox */
|
||||||
|
scrollbar-width: none; /* Firefox ^64 */
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-inputbox > .wrapper > textarea.input::-webkit-scrollbar {
|
.monaco-inputbox > .wrapper > textarea.input::-webkit-scrollbar {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export interface IInputOptions extends IInputBoxStyles {
|
|||||||
readonly type?: string;
|
readonly type?: string;
|
||||||
readonly validationOptions?: IInputValidationOptions;
|
readonly validationOptions?: IInputValidationOptions;
|
||||||
readonly flexibleHeight?: boolean;
|
readonly flexibleHeight?: boolean;
|
||||||
|
readonly flexibleWidth?: boolean;
|
||||||
readonly flexibleMaxHeight?: number;
|
readonly flexibleMaxHeight?: number;
|
||||||
readonly actions?: ReadonlyArray<IAction>;
|
readonly actions?: ReadonlyArray<IAction>;
|
||||||
|
|
||||||
@@ -185,6 +186,13 @@ export class InputBox extends Widget {
|
|||||||
this.mirror.innerHTML = ' ';
|
this.mirror.innerHTML = ' ';
|
||||||
|
|
||||||
this.scrollableElement = new ScrollableElement(this.element, { vertical: ScrollbarVisibility.Auto });
|
this.scrollableElement = new ScrollableElement(this.element, { vertical: ScrollbarVisibility.Auto });
|
||||||
|
|
||||||
|
if (this.options.flexibleWidth) {
|
||||||
|
this.input.setAttribute('wrap', 'off');
|
||||||
|
this.mirror.style.whiteSpace = 'pre';
|
||||||
|
this.mirror.style.wordWrap = 'initial';
|
||||||
|
}
|
||||||
|
|
||||||
dom.append(container, this.scrollableElement.getDomNode());
|
dom.append(container, this.scrollableElement.getDomNode());
|
||||||
this._register(this.scrollableElement);
|
this._register(this.scrollableElement);
|
||||||
|
|
||||||
@@ -345,12 +353,36 @@ export class InputBox extends Widget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public set width(width: number) {
|
public set width(width: number) {
|
||||||
this.input.style.width = width + 'px';
|
if (this.options.flexibleHeight && this.options.flexibleWidth) {
|
||||||
|
// textarea with horizontal scrolling
|
||||||
|
let horizontalPadding = 0;
|
||||||
|
if (this.mirror) {
|
||||||
|
const paddingLeft = parseFloat(this.mirror.style.paddingLeft || '') || 0;
|
||||||
|
const paddingRight = parseFloat(this.mirror.style.paddingRight || '') || 0;
|
||||||
|
horizontalPadding = paddingLeft + paddingRight;
|
||||||
|
}
|
||||||
|
this.input.style.width = (width - horizontalPadding) + 'px';
|
||||||
|
} else {
|
||||||
|
this.input.style.width = width + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
if (this.mirror) {
|
if (this.mirror) {
|
||||||
this.mirror.style.width = width + 'px';
|
this.mirror.style.width = width + 'px';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public set paddingRight(paddingRight: number) {
|
||||||
|
if (this.options.flexibleHeight && this.options.flexibleWidth) {
|
||||||
|
this.input.style.width = `calc(100% - ${paddingRight}px)`;
|
||||||
|
} else {
|
||||||
|
this.input.style.paddingRight = paddingRight + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mirror) {
|
||||||
|
this.mirror.style.paddingRight = paddingRight + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private updateScrollDimensions(): void {
|
private updateScrollDimensions(): void {
|
||||||
if (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number') {
|
if (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number') {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -683,6 +683,22 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
|||||||
this.scrollableElement.setScrollPosition({ scrollTop });
|
this.scrollableElement.setScrollPosition({ scrollTop });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getScrollLeft(): number {
|
||||||
|
const scrollPosition = this.scrollableElement.getScrollPosition();
|
||||||
|
return scrollPosition.scrollLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
setScrollLeftt(scrollLeft: number): void {
|
||||||
|
if (this.scrollableElementUpdateDisposable) {
|
||||||
|
this.scrollableElementUpdateDisposable.dispose();
|
||||||
|
this.scrollableElementUpdateDisposable = null;
|
||||||
|
this.scrollableElement.setScrollDimensions({ scrollWidth: this.scrollWidth });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scrollableElement.setScrollPosition({ scrollLeft });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
get scrollTop(): number {
|
get scrollTop(): number {
|
||||||
return this.getScrollTop();
|
return this.getScrollTop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1307,6 +1307,14 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
|||||||
this.view.setScrollTop(scrollTop);
|
this.view.setScrollTop(scrollTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get scrollLeft(): number {
|
||||||
|
return this.view.getScrollLeft();
|
||||||
|
}
|
||||||
|
|
||||||
|
set scrollLeft(scrollLeft: number) {
|
||||||
|
this.view.setScrollLeftt(scrollLeft);
|
||||||
|
}
|
||||||
|
|
||||||
get scrollHeight(): number {
|
get scrollHeight(): number {
|
||||||
return this.view.scrollHeight;
|
return this.view.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1319,6 +1319,14 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
|
|||||||
this.view.scrollTop = scrollTop;
|
this.view.scrollTop = scrollTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get scrollLeft(): number {
|
||||||
|
return this.view.scrollTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
set scrollLeft(scrollLeft: number) {
|
||||||
|
this.view.scrollLeft = scrollLeft;
|
||||||
|
}
|
||||||
|
|
||||||
get scrollHeight(): number {
|
get scrollHeight(): number {
|
||||||
return this.view.scrollHeight;
|
return this.view.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -400,6 +400,14 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
|
|||||||
this.tree.scrollTop = scrollTop;
|
this.tree.scrollTop = scrollTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get scrollLeft(): number {
|
||||||
|
return this.tree.scrollLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
set scrollLeft(scrollLeft: number) {
|
||||||
|
this.tree.scrollLeft = scrollLeft;
|
||||||
|
}
|
||||||
|
|
||||||
get scrollHeight(): number {
|
get scrollHeight(): number {
|
||||||
return this.tree.scrollHeight;
|
return this.tree.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ export class IndexTreeModel<T extends Exclude<any, undefined>, TFilterData = voi
|
|||||||
|
|
||||||
const result = this._setListNodeCollapsed(node, listIndex, revealed, collapsed!, recursive || false);
|
const result = this._setListNodeCollapsed(node, listIndex, revealed, collapsed!, recursive || false);
|
||||||
|
|
||||||
if (this.autoExpandSingleChildren && !collapsed! && !recursive) {
|
if (node !== this.root && this.autoExpandSingleChildren && !collapsed! && !recursive) {
|
||||||
let onlyVisibleChildIndex = -1;
|
let onlyVisibleChildIndex = -1;
|
||||||
|
|
||||||
for (let i = 0; i < node.children.length; i++) {
|
for (let i = 0; i < node.children.length; i++) {
|
||||||
|
|||||||
@@ -549,7 +549,7 @@ export function fuzzyScore(pattern: string, patternLow: string, patternPos: numb
|
|||||||
const patternStartPos = patternPos;
|
const patternStartPos = patternPos;
|
||||||
const wordStartPos = wordPos;
|
const wordStartPos = wordPos;
|
||||||
|
|
||||||
// There will be a mach, fill in tables
|
// There will be a match, fill in tables
|
||||||
for (patternPos = patternStartPos + 1; patternPos <= patternLen; patternPos++) {
|
for (patternPos = patternStartPos + 1; patternPos <= patternLen; patternPos++) {
|
||||||
|
|
||||||
for (wordPos = 1; wordPos <= wordLen; wordPos++) {
|
for (wordPos = 1; wordPos <= wordLen; wordPos++) {
|
||||||
@@ -573,6 +573,11 @@ export function fuzzyScore(pattern: string, patternLow: string, patternPos: numb
|
|||||||
} else {
|
} else {
|
||||||
score = 5;
|
score = 5;
|
||||||
}
|
}
|
||||||
|
} else if (isSeparatorAtPos(wordLow, wordPos - 1) && (wordPos === 1 || !isSeparatorAtPos(wordLow, wordPos - 2))) {
|
||||||
|
// hitting a separator: `. <-> foo.bar`
|
||||||
|
// ^
|
||||||
|
score = 5;
|
||||||
|
|
||||||
} else if (isSeparatorAtPos(wordLow, wordPos - 2) || isWhitespaceAtPos(wordLow, wordPos - 2)) {
|
} else if (isSeparatorAtPos(wordLow, wordPos - 2) || isWhitespaceAtPos(wordLow, wordPos - 2)) {
|
||||||
// post separator: `foo <-> bar_foo`
|
// post separator: `foo <-> bar_foo`
|
||||||
// ^^^
|
// ^^^
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import * as platform from 'vs/base/common/platform';
|
||||||
|
|
||||||
export namespace Schemas {
|
export namespace Schemas {
|
||||||
|
|
||||||
@@ -58,11 +59,17 @@ class RemoteAuthoritiesImpl {
|
|||||||
private readonly _hosts: { [authority: string]: string; };
|
private readonly _hosts: { [authority: string]: string; };
|
||||||
private readonly _ports: { [authority: string]: number; };
|
private readonly _ports: { [authority: string]: number; };
|
||||||
private readonly _connectionTokens: { [authority: string]: string; };
|
private readonly _connectionTokens: { [authority: string]: string; };
|
||||||
|
private _preferredWebSchema: 'http' | 'https';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this._hosts = Object.create(null);
|
this._hosts = Object.create(null);
|
||||||
this._ports = Object.create(null);
|
this._ports = Object.create(null);
|
||||||
this._connectionTokens = Object.create(null);
|
this._connectionTokens = Object.create(null);
|
||||||
|
this._preferredWebSchema = 'http';
|
||||||
|
}
|
||||||
|
|
||||||
|
public setPreferredWebSchema(schema: 'http' | 'https') {
|
||||||
|
this._preferredWebSchema = schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
public set(authority: string, host: string, port: number): void {
|
public set(authority: string, host: string, port: number): void {
|
||||||
@@ -79,9 +86,9 @@ class RemoteAuthoritiesImpl {
|
|||||||
const port = this._ports[authority];
|
const port = this._ports[authority];
|
||||||
const connectionToken = this._connectionTokens[authority];
|
const connectionToken = this._connectionTokens[authority];
|
||||||
return URI.from({
|
return URI.from({
|
||||||
scheme: Schemas.vscodeRemoteResource,
|
scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource,
|
||||||
authority: `${host}:${port}`,
|
authority: `${host}:${port}`,
|
||||||
path: `/vscode-remote2`,
|
path: `/vscode-remote-resource`,
|
||||||
query: `path=${encodeURIComponent(path)}&tkn=${encodeURIComponent(connectionToken)}`
|
query: `path=${encodeURIComponent(path)}&tkn=${encodeURIComponent(connectionToken)}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -366,6 +366,10 @@ suite('Filters', () => {
|
|||||||
assertMatches('f', ':foo', ':^foo', fuzzyScore);
|
assertMatches('f', ':foo', ':^foo', fuzzyScore);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Separator only match should not be weak #79558', function () {
|
||||||
|
assertMatches('.', 'foo.bar', 'foo^.bar', fuzzyScore);
|
||||||
|
});
|
||||||
|
|
||||||
test('Cannot set property \'1\' of undefined, #26511', function () {
|
test('Cannot set property \'1\' of undefined, #26511', function () {
|
||||||
let word = new Array<void>(123).join('a');
|
let word = new Array<void>(123).join('a');
|
||||||
let pattern = new Array<void>(120).join('a');
|
let pattern = new Array<void>(120).join('a');
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
</body>
|
</body>
|
||||||
|
|
||||||
<!-- Require our AMD loader -->
|
<!-- Require our AMD loader -->
|
||||||
<script src="./out/vs/loader.js"></script>
|
<script src="./static/out/vs/loader.js"></script>
|
||||||
|
|
||||||
<!-- Startup via workbench.js -->
|
<!-- Startup via workbench.js -->
|
||||||
<script src="./out/vs/code/browser/workbench/workbench.js"></script>
|
<script src="./static/out/vs/code/browser/workbench/workbench.js"></script>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -8,15 +8,15 @@
|
|||||||
(function () {
|
(function () {
|
||||||
|
|
||||||
require.config({
|
require.config({
|
||||||
baseUrl: `${window.location.origin}/out`,
|
baseUrl: `${window.location.origin}/static/out`,
|
||||||
paths: {
|
paths: {
|
||||||
'vscode-textmate': `${window.location.origin}/node_modules/vscode-textmate/release/main`,
|
'vscode-textmate': `${window.location.origin}/static/node_modules/vscode-textmate/release/main`,
|
||||||
'onigasm-umd': `${window.location.origin}/node_modules/onigasm-umd/release/main`,
|
'onigasm-umd': `${window.location.origin}/static/node_modules/onigasm-umd/release/main`,
|
||||||
'xterm': `${window.location.origin}/node_modules/xterm/lib/xterm.js`,
|
'xterm': `${window.location.origin}/static/node_modules/xterm/lib/xterm.js`,
|
||||||
'xterm-addon-search': `${window.location.origin}/node_modules/xterm-addon-search/lib/xterm-addon-search.js`,
|
'xterm-addon-search': `${window.location.origin}/static/node_modules/xterm-addon-search/lib/xterm-addon-search.js`,
|
||||||
'xterm-addon-web-links': `${window.location.origin}/node_modules/xterm-addon-web-links/lib/xterm-addon-web-links.js`,
|
'xterm-addon-web-links': `${window.location.origin}/static/node_modules/xterm-addon-web-links/lib/xterm-addon-web-links.js`,
|
||||||
'semver-umd': `${window.location.origin}/node_modules/semver-umd/lib/semver-umd.js`,
|
'semver-umd': `${window.location.origin}/static/node_modules/semver-umd/lib/semver-umd.js`,
|
||||||
'@microsoft/applicationinsights-web': `${window.location.origin}/node_modules/@microsoft/applicationinsights-web/dist/applicationinsights-web.js`,
|
'@microsoft/applicationinsights-web': `${window.location.origin}/static/node_modules/@microsoft/applicationinsights-web/dist/applicationinsights-web.js`,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,41 +4,39 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as dom from 'vs/base/browser/dom';
|
import * as dom from 'vs/base/browser/dom';
|
||||||
|
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { LinkedList } from 'vs/base/common/linkedList';
|
||||||
import { parse } from 'vs/base/common/marshalling';
|
import { parse } from 'vs/base/common/marshalling';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import * as resources from 'vs/base/common/resources';
|
import * as resources from 'vs/base/common/resources';
|
||||||
|
import { equalsIgnoreCase } from 'vs/base/common/strings';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||||
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
|
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
|
||||||
import { IOpenerService, IOpener } from 'vs/platform/opener/common/opener';
|
|
||||||
import { equalsIgnoreCase } from 'vs/base/common/strings';
|
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { LinkedList } from 'vs/base/common/linkedList';
|
|
||||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
|
||||||
import { localize } from 'vs/nls';
|
|
||||||
import { IProductService } from 'vs/platform/product/common/product';
|
|
||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
|
||||||
import Severity from 'vs/base/common/severity';
|
|
||||||
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { IOpener, IOpenerService, IValidator } from 'vs/platform/opener/common/opener';
|
||||||
|
|
||||||
export class OpenerService implements IOpenerService {
|
export class OpenerService extends Disposable implements IOpenerService {
|
||||||
|
|
||||||
_serviceBrand!: ServiceIdentifier<any>;
|
_serviceBrand!: ServiceIdentifier<any>;
|
||||||
|
|
||||||
private readonly _opener = new LinkedList<IOpener>();
|
private readonly _openers = new LinkedList<IOpener>();
|
||||||
|
private readonly _validators = new LinkedList<IValidator>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ICodeEditorService private readonly _editorService: ICodeEditorService,
|
@ICodeEditorService private readonly _editorService: ICodeEditorService,
|
||||||
@ICommandService private readonly _commandService: ICommandService,
|
@ICommandService private readonly _commandService: ICommandService,
|
||||||
@IStorageService private readonly _storageService: IStorageService,
|
|
||||||
@IDialogService private readonly _dialogService: IDialogService,
|
|
||||||
@IProductService private readonly _productService: IProductService
|
|
||||||
) {
|
) {
|
||||||
//
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
registerOpener(opener: IOpener): IDisposable {
|
registerOpener(opener: IOpener): IDisposable {
|
||||||
const remove = this._opener.push(opener);
|
const remove = this._openers.push(opener);
|
||||||
|
return { dispose: remove };
|
||||||
|
}
|
||||||
|
|
||||||
|
registerValidator(validator: IValidator): IDisposable {
|
||||||
|
const remove = this._validators.push(validator);
|
||||||
return { dispose: remove };
|
return { dispose: remove };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,8 +45,16 @@ export class OpenerService implements IOpenerService {
|
|||||||
if (!resource.scheme) {
|
if (!resource.scheme) {
|
||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check with contributed validators
|
||||||
|
for (const validator of this._validators.toArray()) {
|
||||||
|
if (!(await validator.shouldOpen(resource))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check with contributed openers
|
// check with contributed openers
|
||||||
for (const opener of this._opener.toArray()) {
|
for (const opener of this._openers.toArray()) {
|
||||||
const handled = await opener.open(resource, options);
|
const handled = await opener.open(resource, options);
|
||||||
if (handled) {
|
if (handled) {
|
||||||
return true;
|
return true;
|
||||||
@@ -60,7 +66,7 @@ export class OpenerService implements IOpenerService {
|
|||||||
|
|
||||||
private _doOpen(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise<boolean> {
|
private _doOpen(resource: URI, options?: { openToSide?: boolean, openExternal?: boolean }): Promise<boolean> {
|
||||||
|
|
||||||
const { scheme, authority, path, query, fragment } = resource;
|
const { scheme, path, query, fragment } = resource;
|
||||||
|
|
||||||
if (equalsIgnoreCase(scheme, Schemas.mailto) || (options && options.openExternal)) {
|
if (equalsIgnoreCase(scheme, Schemas.mailto) || (options && options.openExternal)) {
|
||||||
// open default mail application
|
// open default mail application
|
||||||
@@ -68,48 +74,8 @@ export class OpenerService implements IOpenerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) {
|
if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) {
|
||||||
let trustedDomains: string[] = ['https://code.visualstudio.com'];
|
// open link in default browser
|
||||||
try {
|
return this._doOpenExternal(resource);
|
||||||
const trustedDomainsSrc = this._storageService.get('http.trustedDomains', StorageScope.GLOBAL);
|
|
||||||
if (trustedDomainsSrc) {
|
|
||||||
trustedDomains = JSON.parse(trustedDomainsSrc);
|
|
||||||
}
|
|
||||||
} catch (err) { }
|
|
||||||
|
|
||||||
const domainToOpen = `${scheme}://${authority}`;
|
|
||||||
|
|
||||||
if (isDomainTrusted(domainToOpen, trustedDomains)) {
|
|
||||||
return this._doOpenExternal(resource);
|
|
||||||
} else {
|
|
||||||
return this._dialogService.show(
|
|
||||||
Severity.Info,
|
|
||||||
localize(
|
|
||||||
'openExternalLinkAt',
|
|
||||||
'Do you want {0} to open the external website?\n{1}',
|
|
||||||
this._productService.nameShort,
|
|
||||||
resource.toString(true)
|
|
||||||
),
|
|
||||||
[
|
|
||||||
localize('openLink', 'Open Link'),
|
|
||||||
localize('cancel', 'Cancel'),
|
|
||||||
localize('configureTrustedDomains', 'Configure Trusted Domains')
|
|
||||||
],
|
|
||||||
{
|
|
||||||
cancelId: 1
|
|
||||||
}).then((choice) => {
|
|
||||||
if (choice === 0) {
|
|
||||||
return this._doOpenExternal(resource);
|
|
||||||
} else if (choice === 2) {
|
|
||||||
return this._commandService.executeCommand('workbench.action.configureTrustedDomains', domainToOpen).then((pickedDomains: string[]) => {
|
|
||||||
if (pickedDomains.indexOf(domainToOpen) !== -1) {
|
|
||||||
return this._doOpenExternal(resource);
|
|
||||||
}
|
|
||||||
return Promise.resolve(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return Promise.resolve(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} 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
|
||||||
if (!CommandsRegistry.getCommand(path)) {
|
if (!CommandsRegistry.getCommand(path)) {
|
||||||
@@ -158,22 +124,8 @@ export class OpenerService implements IOpenerService {
|
|||||||
|
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
dispose() {
|
||||||
* Check whether a domain like https://www.microsoft.com matches
|
this._validators.clear();
|
||||||
* the list of trusted domains.
|
|
||||||
*/
|
|
||||||
function isDomainTrusted(domain: string, trustedDomains: string[]) {
|
|
||||||
for (let i = 0; i < trustedDomains.length; i++) {
|
|
||||||
if (trustedDomains[i] === '*') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trustedDomains[i] === domain) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -367,6 +367,10 @@ export let completionKindFromString: {
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
export const enum CompletionItemKindModifier {
|
||||||
|
Deprecated = 1
|
||||||
|
}
|
||||||
|
|
||||||
export const enum CompletionItemInsertTextRule {
|
export const enum CompletionItemInsertTextRule {
|
||||||
/**
|
/**
|
||||||
* Adjust whitespace/indentation of multiline insert texts to
|
* Adjust whitespace/indentation of multiline insert texts to
|
||||||
@@ -396,6 +400,11 @@ export interface CompletionItem {
|
|||||||
* an icon is chosen by the editor.
|
* an icon is chosen by the editor.
|
||||||
*/
|
*/
|
||||||
kind: CompletionItemKind;
|
kind: CompletionItemKind;
|
||||||
|
/**
|
||||||
|
* A modifier to the `kind` which affect how the item
|
||||||
|
* is rendered, e.g. Deprecated is rendered with a strikeout
|
||||||
|
*/
|
||||||
|
kindModifier?: CompletionItemKindModifier;
|
||||||
/**
|
/**
|
||||||
* A human-readable string with additional information
|
* A human-readable string with additional information
|
||||||
* about this item, like type or symbol information.
|
* about this item, like type or symbol information.
|
||||||
@@ -464,7 +473,7 @@ export interface CompletionItem {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
[key: string]: any;
|
_id?: [number, number];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CompletionList {
|
export interface CompletionList {
|
||||||
|
|||||||
@@ -581,6 +581,10 @@ export enum CompletionItemKind {
|
|||||||
Snippet = 25
|
Snippet = 25
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CompletionItemKindModifier {
|
||||||
|
Deprecated = 1
|
||||||
|
}
|
||||||
|
|
||||||
export enum CompletionItemInsertTextRule {
|
export enum CompletionItemInsertTextRule {
|
||||||
/**
|
/**
|
||||||
* Adjust whitespace/indentation of multiline insert texts to
|
* Adjust whitespace/indentation of multiline insert texts to
|
||||||
|
|||||||
@@ -12,19 +12,20 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||||||
import { EditorAction, EditorCommand, ServicesAccessor, registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
import { EditorAction, EditorCommand, ServicesAccessor, registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||||
import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_FIND_WIDGET_VISIBLE, FIND_IDS, FindModelBoundToEditorModel, ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleSearchScopeKeybinding, ToggleWholeWordKeybinding } from 'vs/editor/contrib/find/findModel';
|
import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_FIND_WIDGET_VISIBLE, FIND_IDS, FindModelBoundToEditorModel, ToggleCaseSensitiveKeybinding, ToggleRegexKeybinding, ToggleSearchScopeKeybinding, ToggleWholeWordKeybinding, CONTEXT_REPLACE_INPUT_FOCUSED } from 'vs/editor/contrib/find/findModel';
|
||||||
import { FindOptionsWidget } from 'vs/editor/contrib/find/findOptionsWidget';
|
import { FindOptionsWidget } from 'vs/editor/contrib/find/findOptionsWidget';
|
||||||
import { FindReplaceState, FindReplaceStateChangedEvent, INewFindReplaceState } from 'vs/editor/contrib/find/findState';
|
import { FindReplaceState, FindReplaceStateChangedEvent, INewFindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||||
import { FindWidget, IFindController } from 'vs/editor/contrib/find/findWidget';
|
import { FindWidget, IFindController } from 'vs/editor/contrib/find/findWidget';
|
||||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||||
import { optional } from 'vs/platform/instantiation/common/instantiation';
|
import { optional } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
|
|
||||||
const SEARCH_STRING_MAX_LENGTH = 524288;
|
const SEARCH_STRING_MAX_LENGTH = 524288;
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd
|
|||||||
protected _state: FindReplaceState;
|
protected _state: FindReplaceState;
|
||||||
protected _updateHistoryDelayer: Delayer<void>;
|
protected _updateHistoryDelayer: Delayer<void>;
|
||||||
private _model: FindModelBoundToEditorModel | null;
|
private _model: FindModelBoundToEditorModel | null;
|
||||||
private readonly _storageService: IStorageService;
|
protected readonly _storageService: IStorageService;
|
||||||
private readonly _clipboardService: IClipboardService;
|
private readonly _clipboardService: IClipboardService;
|
||||||
protected readonly _contextKeyService: IContextKeyService;
|
protected readonly _contextKeyService: IContextKeyService;
|
||||||
|
|
||||||
@@ -383,10 +384,11 @@ export class FindController extends CommonFindController implements IFindControl
|
|||||||
@IContextKeyService _contextKeyService: IContextKeyService,
|
@IContextKeyService _contextKeyService: IContextKeyService,
|
||||||
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
@IKeybindingService private readonly _keybindingService: IKeybindingService,
|
||||||
@IThemeService private readonly _themeService: IThemeService,
|
@IThemeService private readonly _themeService: IThemeService,
|
||||||
@IStorageService storageService: IStorageService,
|
@INotificationService private readonly _notificationService: INotificationService,
|
||||||
@optional(IClipboardService) clipboardService: IClipboardService
|
@IStorageService _storageService: IStorageService,
|
||||||
|
@optional(IClipboardService) clipboardService: IClipboardService,
|
||||||
) {
|
) {
|
||||||
super(editor, _contextKeyService, storageService, clipboardService);
|
super(editor, _contextKeyService, _storageService, clipboardService);
|
||||||
this._widget = null;
|
this._widget = null;
|
||||||
this._findOptionsWidget = null;
|
this._findOptionsWidget = null;
|
||||||
}
|
}
|
||||||
@@ -422,7 +424,7 @@ export class FindController extends CommonFindController implements IFindControl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _createFindWidget() {
|
private _createFindWidget() {
|
||||||
this._widget = this._register(new FindWidget(this._editor, this, this._state, this._contextViewService, this._keybindingService, this._contextKeyService, this._themeService));
|
this._widget = this._register(new FindWidget(this._editor, this, this._state, this._contextViewService, this._keybindingService, this._contextKeyService, this._themeService, this._storageService, this._notificationService));
|
||||||
this._findOptionsWidget = this._register(new FindOptionsWidget(this._editor, this._state, this._keybindingService, this._themeService));
|
this._findOptionsWidget = this._register(new FindOptionsWidget(this._editor, this._state, this._keybindingService, this._themeService));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -540,6 +542,27 @@ export class NextMatchFindAction extends MatchFindAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class NextMatchFindAction2 extends MatchFindAction {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
id: FIND_IDS.NextMatchFindAction,
|
||||||
|
label: nls.localize('findNextMatchAction', "Find Next"),
|
||||||
|
alias: 'Find Next',
|
||||||
|
precondition: undefined,
|
||||||
|
kbOpts: {
|
||||||
|
kbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_FIND_INPUT_FOCUSED),
|
||||||
|
primary: KeyCode.Enter,
|
||||||
|
weight: KeybindingWeight.EditorContrib
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _run(controller: CommonFindController): boolean {
|
||||||
|
return controller.moveToNextMatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class PreviousMatchFindAction extends MatchFindAction {
|
export class PreviousMatchFindAction extends MatchFindAction {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -562,6 +585,27 @@ export class PreviousMatchFindAction extends MatchFindAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PreviousMatchFindAction2 extends MatchFindAction {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super({
|
||||||
|
id: FIND_IDS.PreviousMatchFindAction,
|
||||||
|
label: nls.localize('findPreviousMatchAction', "Find Previous"),
|
||||||
|
alias: 'Find Previous',
|
||||||
|
precondition: undefined,
|
||||||
|
kbOpts: {
|
||||||
|
kbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_FIND_INPUT_FOCUSED),
|
||||||
|
primary: KeyMod.Shift | KeyCode.Enter,
|
||||||
|
weight: KeybindingWeight.EditorContrib
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _run(controller: CommonFindController): boolean {
|
||||||
|
return controller.moveToPrevMatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class SelectionMatchFindAction extends EditorAction {
|
export abstract class SelectionMatchFindAction extends EditorAction {
|
||||||
public run(accessor: ServicesAccessor | null, editor: ICodeEditor): void {
|
public run(accessor: ServicesAccessor | null, editor: ICodeEditor): void {
|
||||||
let controller = CommonFindController.get(editor);
|
let controller = CommonFindController.get(editor);
|
||||||
@@ -695,7 +739,9 @@ registerEditorContribution(FindController);
|
|||||||
registerEditorAction(StartFindAction);
|
registerEditorAction(StartFindAction);
|
||||||
registerEditorAction(StartFindWithSelectionAction);
|
registerEditorAction(StartFindWithSelectionAction);
|
||||||
registerEditorAction(NextMatchFindAction);
|
registerEditorAction(NextMatchFindAction);
|
||||||
|
registerEditorAction(NextMatchFindAction2);
|
||||||
registerEditorAction(PreviousMatchFindAction);
|
registerEditorAction(PreviousMatchFindAction);
|
||||||
|
registerEditorAction(PreviousMatchFindAction2);
|
||||||
registerEditorAction(NextSelectionMatchFindAction);
|
registerEditorAction(NextSelectionMatchFindAction);
|
||||||
registerEditorAction(PreviousSelectionMatchFindAction);
|
registerEditorAction(PreviousSelectionMatchFindAction);
|
||||||
registerEditorAction(StartFindReplaceAction);
|
registerEditorAction(StartFindReplaceAction);
|
||||||
@@ -781,6 +827,17 @@ registerEditorCommand(new FindCommand({
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
registerEditorCommand(new FindCommand({
|
||||||
|
id: FIND_IDS.ReplaceOneAction,
|
||||||
|
precondition: CONTEXT_FIND_WIDGET_VISIBLE,
|
||||||
|
handler: x => x.replace(),
|
||||||
|
kbOpts: {
|
||||||
|
weight: KeybindingWeight.EditorContrib + 5,
|
||||||
|
kbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_REPLACE_INPUT_FOCUSED),
|
||||||
|
primary: KeyCode.Enter
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
registerEditorCommand(new FindCommand({
|
registerEditorCommand(new FindCommand({
|
||||||
id: FIND_IDS.ReplaceAllAction,
|
id: FIND_IDS.ReplaceAllAction,
|
||||||
precondition: CONTEXT_FIND_WIDGET_VISIBLE,
|
precondition: CONTEXT_FIND_WIDGET_VISIBLE,
|
||||||
@@ -792,6 +849,20 @@ registerEditorCommand(new FindCommand({
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
registerEditorCommand(new FindCommand({
|
||||||
|
id: FIND_IDS.ReplaceAllAction,
|
||||||
|
precondition: CONTEXT_FIND_WIDGET_VISIBLE,
|
||||||
|
handler: x => x.replaceAll(),
|
||||||
|
kbOpts: {
|
||||||
|
weight: KeybindingWeight.EditorContrib + 5,
|
||||||
|
kbExpr: ContextKeyExpr.and(EditorContextKeys.focus, CONTEXT_REPLACE_INPUT_FOCUSED),
|
||||||
|
primary: undefined,
|
||||||
|
mac: {
|
||||||
|
primary: KeyMod.CtrlCmd | KeyCode.Enter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
registerEditorCommand(new FindCommand({
|
registerEditorCommand(new FindCommand({
|
||||||
id: FIND_IDS.SelectAllMatchesAction,
|
id: FIND_IDS.SelectAllMatchesAction,
|
||||||
precondition: CONTEXT_FIND_WIDGET_VISIBLE,
|
precondition: CONTEXT_FIND_WIDGET_VISIBLE,
|
||||||
|
|||||||
@@ -32,8 +32,8 @@
|
|||||||
.monaco-editor .find-widget {
|
.monaco-editor .find-widget {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
top: -44px; /* find input height + shadow (10px) */
|
top: -44px;
|
||||||
height: 34px; /* find input height */
|
height: 33px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
line-height: 19px;
|
line-height: 19px;
|
||||||
transition: top 200ms linear;
|
transition: top 200ms linear;
|
||||||
@@ -47,12 +47,10 @@
|
|||||||
/* Find widget when replace is toggled on */
|
/* Find widget when replace is toggled on */
|
||||||
.monaco-editor .find-widget.replaceToggled {
|
.monaco-editor .find-widget.replaceToggled {
|
||||||
top: -74px; /* find input height + replace input height + shadow (10px) */
|
top: -74px; /* find input height + replace input height + shadow (10px) */
|
||||||
height: 64px; /* find input height + replace input height */
|
|
||||||
}
|
}
|
||||||
.monaco-editor .find-widget.replaceToggled > .replace-part {
|
.monaco-editor .find-widget.replaceToggled > .replace-part {
|
||||||
display: flex;
|
display: flex;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .find-widget.visible,
|
.monaco-editor .find-widget.visible,
|
||||||
@@ -60,13 +58,31 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Multiple line find widget */
|
||||||
|
|
||||||
|
.monaco-editor .find-widget.multipleline {
|
||||||
|
top: unset;
|
||||||
|
bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monaco-editor .find-widget.multipleline.visible,
|
||||||
|
.monaco-editor .find-widget.multipleline.replaceToggled.visible {
|
||||||
|
top: 0px;
|
||||||
|
bottom: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monaco-editor .find-widget .monaco-inputbox.synthetic-focus {
|
||||||
|
outline: 1px solid -webkit-focus-ring-color;
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
.monaco-editor .find-widget .monaco-inputbox .input {
|
.monaco-editor .find-widget .monaco-inputbox .input {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
/* Style to compensate for //winjs */
|
/* Style to compensate for //winjs */
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .find-widget .replace-input .input {
|
.monaco-editor .find-widget .monaco-findInput .input {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,29 +92,38 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .find-widget > .find-part .monaco-inputbox,
|
.monaco-editor .find-widget > .find-part .monaco-inputbox,
|
||||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox {
|
.monaco-editor .find-widget > .replace-part .monaco-inputbox {
|
||||||
height: 25px;
|
min-height: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input {
|
|
||||||
width: 100% !important;
|
|
||||||
padding-right: 66px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input {
|
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .mirror {
|
||||||
padding-right: 22px;
|
padding-right: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input,
|
.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input,
|
||||||
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input {
|
.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .mirror,
|
||||||
|
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input,
|
||||||
|
.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .mirror {
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
padding-bottom: 2px;
|
padding-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.monaco-editor .find-widget > .find-part .find-actions {
|
||||||
|
height: 25px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monaco-editor .find-widget > .replace-part .replace-actions {
|
||||||
|
height: 25px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.monaco-editor .find-widget .monaco-findInput {
|
.monaco-editor .find-widget .monaco-findInput {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -106,6 +131,16 @@
|
|||||||
flex:1;
|
flex:1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.monaco-editor .find-widget .monaco-findInput .monaco-scrollable-element {
|
||||||
|
/* Make sure textarea inherits the width correctly */
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monaco-editor .find-widget .monaco-findInput .monaco-scrollable-element .scrollbar.vertical {
|
||||||
|
/* Hide vertical scrollbar */
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.monaco-editor .find-widget .matchesCount {
|
.monaco-editor .find-widget .matchesCount {
|
||||||
display: flex;
|
display: flex;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
@@ -237,15 +272,17 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .find-widget > .replace-part > .replace-input {
|
.monaco-editor .find-widget > .replace-part > .monaco-findInput {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
display: -webkit-flex;
|
display: -webkit-flex;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
width: auto !important;
|
flex: auto;
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.monaco-editor .find-widget > .replace-part > .replace-input > .controls {
|
.monaco-editor .find-widget > .replace-part > .monaco-findInput > .controls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 3px;
|
top: 3px;
|
||||||
right: 2px;
|
right: 2px;
|
||||||
|
|||||||
@@ -9,11 +9,12 @@ import * as dom from 'vs/base/browser/dom';
|
|||||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||||
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
|
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
|
||||||
|
import { alert as alertFn } from 'vs/base/browser/ui/aria/aria';
|
||||||
import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput';
|
import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput';
|
||||||
import { HistoryInputBox, IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';
|
import { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||||
|
import { ReplaceInput } from 'vs/base/browser/ui/findinput/replaceInput';
|
||||||
import { IHorizontalSashLayoutProvider, ISashEvent, Orientation, Sash } from 'vs/base/browser/ui/sash/sash';
|
import { IHorizontalSashLayoutProvider, ISashEvent, Orientation, Sash } from 'vs/base/browser/ui/sash/sash';
|
||||||
import { Widget } from 'vs/base/browser/ui/widget';
|
import { Widget } from 'vs/base/browser/ui/widget';
|
||||||
import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox';
|
|
||||||
import { Delayer } from 'vs/base/common/async';
|
import { Delayer } from 'vs/base/common/async';
|
||||||
import { Color } from 'vs/base/common/color';
|
import { Color } from 'vs/base/common/color';
|
||||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||||
@@ -28,11 +29,12 @@ import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_REPLACE_INPUT_FOCUSED, FIND_IDS, MA
|
|||||||
import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState';
|
import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState';
|
||||||
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||||
import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry';
|
import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||||
import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget';
|
import { ContextScopedFindInput, ContextScopedReplaceInput } from 'vs/platform/browser/contextScopedHistoryWidget';
|
||||||
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
|
||||||
import { alert as alertFn } from 'vs/base/browser/ui/aria/aria';
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
|
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||||
|
|
||||||
export interface IFindController {
|
export interface IFindController {
|
||||||
replace(): void;
|
replace(): void;
|
||||||
@@ -48,7 +50,6 @@ const NLS_TOGGLE_SELECTION_FIND_TITLE = nls.localize('label.toggleSelectionFind'
|
|||||||
const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close");
|
const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close");
|
||||||
const NLS_REPLACE_INPUT_LABEL = nls.localize('label.replace', "Replace");
|
const NLS_REPLACE_INPUT_LABEL = nls.localize('label.replace', "Replace");
|
||||||
const NLS_REPLACE_INPUT_PLACEHOLDER = nls.localize('placeholder.replace', "Replace");
|
const NLS_REPLACE_INPUT_PLACEHOLDER = nls.localize('placeholder.replace', "Replace");
|
||||||
const NLS_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseCheckbox', "Preserve Case");
|
|
||||||
const NLS_REPLACE_BTN_LABEL = nls.localize('label.replaceButton', "Replace");
|
const NLS_REPLACE_BTN_LABEL = nls.localize('label.replaceButton', "Replace");
|
||||||
const NLS_REPLACE_ALL_BTN_LABEL = nls.localize('label.replaceAllButton', "Replace All");
|
const NLS_REPLACE_ALL_BTN_LABEL = nls.localize('label.replaceAllButton', "Replace All");
|
||||||
const NLS_TOGGLE_REPLACE_MODE_BTN_LABEL = nls.localize('label.toggleReplaceButton', "Toggle Replace mode");
|
const NLS_TOGGLE_REPLACE_MODE_BTN_LABEL = nls.localize('label.toggleReplaceButton', "Toggle Replace mode");
|
||||||
@@ -59,14 +60,12 @@ const NLS_NO_RESULTS = nls.localize('label.noResults', "No Results");
|
|||||||
const FIND_WIDGET_INITIAL_WIDTH = 411;
|
const FIND_WIDGET_INITIAL_WIDTH = 411;
|
||||||
const PART_WIDTH = 275;
|
const PART_WIDTH = 275;
|
||||||
const FIND_INPUT_AREA_WIDTH = PART_WIDTH - 54;
|
const FIND_INPUT_AREA_WIDTH = PART_WIDTH - 54;
|
||||||
const REPLACE_INPUT_AREA_WIDTH = FIND_INPUT_AREA_WIDTH;
|
|
||||||
|
|
||||||
let MAX_MATCHES_COUNT_WIDTH = 69;
|
let MAX_MATCHES_COUNT_WIDTH = 69;
|
||||||
let FIND_ALL_CONTROLS_WIDTH = 17/** Find Input margin-left */ + (MAX_MATCHES_COUNT_WIDTH + 3 + 1) /** Match Results */ + 23 /** Button */ * 4 + 2/** sash */;
|
let FIND_ALL_CONTROLS_WIDTH = 17/** Find Input margin-left */ + (MAX_MATCHES_COUNT_WIDTH + 3 + 1) /** Match Results */ + 23 /** Button */ * 4 + 2/** sash */;
|
||||||
|
|
||||||
const FIND_INPUT_AREA_HEIGHT = 34; // The height of Find Widget when Replace Input is not visible.
|
const FIND_INPUT_AREA_HEIGHT = 33; // The height of Find Widget when Replace Input is not visible.
|
||||||
const FIND_REPLACE_AREA_HEIGHT = 64; // The height of Find Widget when Replace Input is visible.
|
const ctrlEnterReplaceAllWarningPromptedKey = 'ctrlEnterReplaceAll.windows.donotask';
|
||||||
|
|
||||||
|
|
||||||
export class FindWidgetViewZone implements IViewZone {
|
export class FindWidgetViewZone implements IViewZone {
|
||||||
public readonly afterLineNumber: number;
|
public readonly afterLineNumber: number;
|
||||||
@@ -84,6 +83,22 @@ export class FindWidgetViewZone implements IViewZone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stopPropagationForMultiLineUpwards(event: IKeyboardEvent, value: string, textarea: HTMLTextAreaElement | null) {
|
||||||
|
const isMultiline = !!value.match(/\n/);
|
||||||
|
if (textarea && isMultiline && textarea.selectionStart > 0) {
|
||||||
|
event.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopPropagationForMultiLineDownwards(event: IKeyboardEvent, value: string, textarea: HTMLTextAreaElement | null) {
|
||||||
|
const isMultiline = !!value.match(/\n/);
|
||||||
|
if (textarea && isMultiline && textarea.selectionEnd < textarea.value.length) {
|
||||||
|
event.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSashLayoutProvider {
|
export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSashLayoutProvider {
|
||||||
private static readonly ID = 'editor.contrib.findWidget';
|
private static readonly ID = 'editor.contrib.findWidget';
|
||||||
private readonly _codeEditor: ICodeEditor;
|
private readonly _codeEditor: ICodeEditor;
|
||||||
@@ -92,10 +107,13 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
private readonly _contextViewProvider: IContextViewProvider;
|
private readonly _contextViewProvider: IContextViewProvider;
|
||||||
private readonly _keybindingService: IKeybindingService;
|
private readonly _keybindingService: IKeybindingService;
|
||||||
private readonly _contextKeyService: IContextKeyService;
|
private readonly _contextKeyService: IContextKeyService;
|
||||||
|
private readonly _storageService: IStorageService;
|
||||||
|
private readonly _notificationService: INotificationService;
|
||||||
|
|
||||||
private _domNode!: HTMLElement;
|
private _domNode!: HTMLElement;
|
||||||
|
private _cachedHeight: number | null;
|
||||||
private _findInput!: FindInput;
|
private _findInput!: FindInput;
|
||||||
private _replaceInputBox!: HistoryInputBox;
|
private _replaceInput!: ReplaceInput;
|
||||||
|
|
||||||
private _toggleReplaceBtn!: SimpleButton;
|
private _toggleReplaceBtn!: SimpleButton;
|
||||||
private _matchesCount!: HTMLElement;
|
private _matchesCount!: HTMLElement;
|
||||||
@@ -103,13 +121,13 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
private _nextBtn!: SimpleButton;
|
private _nextBtn!: SimpleButton;
|
||||||
private _toggleSelectionFind!: SimpleCheckbox;
|
private _toggleSelectionFind!: SimpleCheckbox;
|
||||||
private _closeBtn!: SimpleButton;
|
private _closeBtn!: SimpleButton;
|
||||||
private _preserveCase!: Checkbox;
|
|
||||||
private _replaceBtn!: SimpleButton;
|
private _replaceBtn!: SimpleButton;
|
||||||
private _replaceAllBtn!: SimpleButton;
|
private _replaceAllBtn!: SimpleButton;
|
||||||
|
|
||||||
private _isVisible: boolean;
|
private _isVisible: boolean;
|
||||||
private _isReplaceVisible: boolean;
|
private _isReplaceVisible: boolean;
|
||||||
private _ignoreChangeEvent: boolean;
|
private _ignoreChangeEvent: boolean;
|
||||||
|
private _ctrlEnterReplaceAllWarningPrompted: boolean;
|
||||||
|
|
||||||
private readonly _findFocusTracker: dom.IFocusTracker;
|
private readonly _findFocusTracker: dom.IFocusTracker;
|
||||||
private readonly _findInputFocused: IContextKey<boolean>;
|
private readonly _findInputFocused: IContextKey<boolean>;
|
||||||
@@ -129,7 +147,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
contextViewProvider: IContextViewProvider,
|
contextViewProvider: IContextViewProvider,
|
||||||
keybindingService: IKeybindingService,
|
keybindingService: IKeybindingService,
|
||||||
contextKeyService: IContextKeyService,
|
contextKeyService: IContextKeyService,
|
||||||
themeService: IThemeService
|
themeService: IThemeService,
|
||||||
|
storageService: IStorageService,
|
||||||
|
notificationService: INotificationService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this._codeEditor = codeEditor;
|
this._codeEditor = codeEditor;
|
||||||
@@ -138,6 +158,10 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
this._contextViewProvider = contextViewProvider;
|
this._contextViewProvider = contextViewProvider;
|
||||||
this._keybindingService = keybindingService;
|
this._keybindingService = keybindingService;
|
||||||
this._contextKeyService = contextKeyService;
|
this._contextKeyService = contextKeyService;
|
||||||
|
this._storageService = storageService;
|
||||||
|
this._notificationService = notificationService;
|
||||||
|
|
||||||
|
this._ctrlEnterReplaceAllWarningPrompted = !!storageService.getBoolean(ctrlEnterReplaceAllWarningPromptedKey, StorageScope.GLOBAL);
|
||||||
|
|
||||||
this._isVisible = false;
|
this._isVisible = false;
|
||||||
this._isReplaceVisible = false;
|
this._isReplaceVisible = false;
|
||||||
@@ -149,6 +173,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
this._buildDomNode();
|
this._buildDomNode();
|
||||||
this._updateButtons();
|
this._updateButtons();
|
||||||
this._tryUpdateWidgetWidth();
|
this._tryUpdateWidgetWidth();
|
||||||
|
this._findInput.inputBox.layout();
|
||||||
|
|
||||||
this._register(this._codeEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => {
|
this._register(this._codeEditor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => {
|
||||||
if (e.readOnly) {
|
if (e.readOnly) {
|
||||||
@@ -203,7 +228,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
this._replaceInputFocused = CONTEXT_REPLACE_INPUT_FOCUSED.bindTo(contextKeyService);
|
this._replaceInputFocused = CONTEXT_REPLACE_INPUT_FOCUSED.bindTo(contextKeyService);
|
||||||
this._replaceFocusTracker = this._register(dom.trackFocus(this._replaceInputBox.inputElement));
|
this._replaceFocusTracker = this._register(dom.trackFocus(this._replaceInput.inputBox.inputElement));
|
||||||
this._register(this._replaceFocusTracker.onDidFocus(() => {
|
this._register(this._replaceFocusTracker.onDidFocus(() => {
|
||||||
this._replaceInputFocused.set(true);
|
this._replaceInputFocused.set(true);
|
||||||
this._updateSearchScope();
|
this._updateSearchScope();
|
||||||
@@ -264,6 +289,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
|
|
||||||
private _onStateChanged(e: FindReplaceStateChangedEvent): void {
|
private _onStateChanged(e: FindReplaceStateChangedEvent): void {
|
||||||
if (e.searchString) {
|
if (e.searchString) {
|
||||||
|
if (this._state.searchString.indexOf('\n') >= 0) {
|
||||||
|
dom.addClass(this._domNode, 'multipleline');
|
||||||
|
} else {
|
||||||
|
dom.removeClass(this._domNode, 'multipleline');
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this._ignoreChangeEvent = true;
|
this._ignoreChangeEvent = true;
|
||||||
this._findInput.setValue(this._state.searchString);
|
this._findInput.setValue(this._state.searchString);
|
||||||
@@ -273,7 +304,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
this._updateButtons();
|
this._updateButtons();
|
||||||
}
|
}
|
||||||
if (e.replaceString) {
|
if (e.replaceString) {
|
||||||
this._replaceInputBox.value = this._state.replaceString;
|
this._replaceInput.inputBox.value = this._state.replaceString;
|
||||||
}
|
}
|
||||||
if (e.isRevealed) {
|
if (e.isRevealed) {
|
||||||
if (this._state.isRevealed) {
|
if (this._state.isRevealed) {
|
||||||
@@ -286,8 +317,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
if (this._state.isReplaceRevealed) {
|
if (this._state.isReplaceRevealed) {
|
||||||
if (!this._codeEditor.getConfiguration().readOnly && !this._isReplaceVisible) {
|
if (!this._codeEditor.getConfiguration().readOnly && !this._isReplaceVisible) {
|
||||||
this._isReplaceVisible = true;
|
this._isReplaceVisible = true;
|
||||||
this._replaceInputBox.width = this._findInput.inputBox.width;
|
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
|
||||||
this._updateButtons();
|
this._updateButtons();
|
||||||
|
this._replaceInput.inputBox.layout();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this._isReplaceVisible) {
|
if (this._isReplaceVisible) {
|
||||||
@@ -296,6 +328,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((e.isRevealed || e.isReplaceRevealed) && (this._state.isRevealed || this._state.isReplaceRevealed)) {
|
||||||
|
if (this._tryUpdateHeight()) {
|
||||||
|
this._showViewZone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (e.isRegex) {
|
if (e.isRegex) {
|
||||||
this._findInput.setRegex(this._state.isRegex);
|
this._findInput.setRegex(this._state.isRegex);
|
||||||
}
|
}
|
||||||
@@ -337,7 +375,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
this._findInput.inputBox.addToHistory();
|
this._findInput.inputBox.addToHistory();
|
||||||
}
|
}
|
||||||
if (this._state.replaceString) {
|
if (this._state.replaceString) {
|
||||||
this._replaceInputBox.addToHistory();
|
this._replaceInput.inputBox.addToHistory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,7 +440,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
|
|
||||||
private _updateButtons(): void {
|
private _updateButtons(): void {
|
||||||
this._findInput.setEnabled(this._isVisible);
|
this._findInput.setEnabled(this._isVisible);
|
||||||
this._replaceInputBox.setEnabled(this._isVisible && this._isReplaceVisible);
|
this._replaceInput.setEnabled(this._isVisible && this._isReplaceVisible);
|
||||||
this._updateToggleSelectionFindButton();
|
this._updateToggleSelectionFindButton();
|
||||||
this._closeBtn.setEnabled(this._isVisible);
|
this._closeBtn.setEnabled(this._isVisible);
|
||||||
|
|
||||||
@@ -512,12 +550,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._codeEditor.changeViewZones((accessor) => {
|
this._codeEditor.changeViewZones((accessor) => {
|
||||||
if (this._state.isReplaceRevealed) {
|
viewZone.heightInPx = this._getHeight();
|
||||||
viewZone.heightInPx = FIND_REPLACE_AREA_HEIGHT;
|
|
||||||
} else {
|
|
||||||
viewZone.heightInPx = FIND_INPUT_AREA_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._viewZoneId = accessor.addZone(viewZone);
|
this._viewZoneId = accessor.addZone(viewZone);
|
||||||
// scroll top adjust to make sure the editor doesn't scroll when adding viewzone at the beginning.
|
// scroll top adjust to make sure the editor doesn't scroll when adding viewzone at the beginning.
|
||||||
this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + viewZone.heightInPx);
|
this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + viewZone.heightInPx);
|
||||||
@@ -525,30 +558,47 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _showViewZone(adjustScroll: boolean = true) {
|
private _showViewZone(adjustScroll: boolean = true) {
|
||||||
const viewZone = this._viewZone;
|
if (!this._isVisible) {
|
||||||
if (!this._isVisible || !viewZone) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const addExtraSpaceOnTop = this._codeEditor.getConfiguration().contribInfo.find.addExtraSpaceOnTop;
|
||||||
|
|
||||||
|
if (!addExtraSpaceOnTop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._viewZone === undefined) {
|
||||||
|
this._viewZone = new FindWidgetViewZone(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewZone = this._viewZone;
|
||||||
|
|
||||||
this._codeEditor.changeViewZones((accessor) => {
|
this._codeEditor.changeViewZones((accessor) => {
|
||||||
let scrollAdjustment = FIND_INPUT_AREA_HEIGHT;
|
|
||||||
|
|
||||||
if (this._viewZoneId !== undefined) {
|
if (this._viewZoneId !== undefined) {
|
||||||
if (this._state.isReplaceRevealed) {
|
// the view zone already exists, we need to update the height
|
||||||
viewZone.heightInPx = FIND_REPLACE_AREA_HEIGHT;
|
const newHeight = this._getHeight();
|
||||||
scrollAdjustment = FIND_REPLACE_AREA_HEIGHT - FIND_INPUT_AREA_HEIGHT;
|
if (newHeight === viewZone.heightInPx) {
|
||||||
} else {
|
return;
|
||||||
viewZone.heightInPx = FIND_INPUT_AREA_HEIGHT;
|
|
||||||
scrollAdjustment = FIND_INPUT_AREA_HEIGHT - FIND_REPLACE_AREA_HEIGHT;
|
|
||||||
}
|
}
|
||||||
accessor.removeZone(this._viewZoneId);
|
|
||||||
} else {
|
|
||||||
viewZone.heightInPx = FIND_INPUT_AREA_HEIGHT;
|
|
||||||
}
|
|
||||||
this._viewZoneId = accessor.addZone(viewZone);
|
|
||||||
|
|
||||||
if (adjustScroll) {
|
let scrollAdjustment = newHeight - viewZone.heightInPx;
|
||||||
this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + scrollAdjustment);
|
viewZone.heightInPx = newHeight;
|
||||||
|
accessor.layoutZone(this._viewZoneId);
|
||||||
|
|
||||||
|
if (adjustScroll) {
|
||||||
|
this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + scrollAdjustment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const scrollAdjustment = this._getHeight();
|
||||||
|
viewZone.heightInPx = scrollAdjustment;
|
||||||
|
this._viewZoneId = accessor.addZone(viewZone);
|
||||||
|
|
||||||
|
if (adjustScroll) {
|
||||||
|
this._codeEditor.setScrollTop(this._codeEditor.getScrollTop() + scrollAdjustment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -584,8 +634,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
inputValidationErrorBorder: theme.getColor(inputValidationErrorBorder),
|
inputValidationErrorBorder: theme.getColor(inputValidationErrorBorder),
|
||||||
};
|
};
|
||||||
this._findInput.style(inputStyles);
|
this._findInput.style(inputStyles);
|
||||||
this._replaceInputBox.style(inputStyles);
|
this._replaceInput.style(inputStyles);
|
||||||
this._preserveCase.style(inputStyles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _tryUpdateWidgetWidth() {
|
private _tryUpdateWidgetWidth() {
|
||||||
@@ -615,7 +664,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
if (widgetWidth > FIND_WIDGET_INITIAL_WIDTH) {
|
if (widgetWidth > FIND_WIDGET_INITIAL_WIDTH) {
|
||||||
// as the widget is resized by users, we may need to change the max width of the widget as the editor width changes.
|
// as the widget is resized by users, we may need to change the max width of the widget as the editor width changes.
|
||||||
this._domNode.style.maxWidth = `${editorWidth - 28 - minimapWidth - 15}px`;
|
this._domNode.style.maxWidth = `${editorWidth - 28 - minimapWidth - 15}px`;
|
||||||
this._replaceInputBox.inputElement.style.width = `${dom.getTotalWidth(this._findInput.inputBox.inputElement)}px`;
|
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -639,13 +688,47 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this._resized) {
|
if (this._resized) {
|
||||||
let findInputWidth = dom.getTotalWidth(this._findInput.inputBox.inputElement);
|
this._findInput.inputBox.layout();
|
||||||
|
let findInputWidth = this._findInput.inputBox.width;
|
||||||
if (findInputWidth > 0) {
|
if (findInputWidth > 0) {
|
||||||
this._replaceInputBox.inputElement.style.width = `${findInputWidth}px`;
|
this._replaceInput.width = findInputWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _getHeight(): number {
|
||||||
|
let totalheight = 0;
|
||||||
|
|
||||||
|
// find input margin top
|
||||||
|
totalheight += 4;
|
||||||
|
|
||||||
|
// find input height
|
||||||
|
totalheight += this._findInput.inputBox.height + 2 /** input box border */;
|
||||||
|
|
||||||
|
if (this._isReplaceVisible) {
|
||||||
|
// replace input margin
|
||||||
|
totalheight += 4;
|
||||||
|
|
||||||
|
totalheight += this._replaceInput.inputBox.height + 2 /** input box border */;
|
||||||
|
}
|
||||||
|
|
||||||
|
// margin bottom
|
||||||
|
totalheight += 4;
|
||||||
|
return totalheight;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _tryUpdateHeight(): boolean {
|
||||||
|
const totalHeight = this._getHeight();
|
||||||
|
if (this._cachedHeight !== null && this._cachedHeight === totalHeight) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._cachedHeight = totalHeight;
|
||||||
|
this._domNode.style.height = `${totalHeight}px`;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// ----- Public
|
// ----- Public
|
||||||
|
|
||||||
public focusFindInput(): void {
|
public focusFindInput(): void {
|
||||||
@@ -655,9 +738,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
}
|
}
|
||||||
|
|
||||||
public focusReplaceInput(): void {
|
public focusReplaceInput(): void {
|
||||||
this._replaceInputBox.select();
|
this._replaceInput.select();
|
||||||
// Edge browser requires focus() in addition to select()
|
// Edge browser requires focus() in addition to select()
|
||||||
this._replaceInputBox.focus();
|
this._replaceInput.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
public highlightFindOptions(): void {
|
public highlightFindOptions(): void {
|
||||||
@@ -692,22 +775,25 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _onFindInputKeyDown(e: IKeyboardEvent): void {
|
private _onFindInputKeyDown(e: IKeyboardEvent): void {
|
||||||
|
if (e.equals(KeyMod.WinCtrl | KeyCode.Enter)) {
|
||||||
|
const inputElement = this._findInput.inputBox.inputElement;
|
||||||
|
const start = inputElement.selectionStart;
|
||||||
|
const end = inputElement.selectionEnd;
|
||||||
|
const content = inputElement.value;
|
||||||
|
|
||||||
if (e.equals(KeyCode.Enter)) {
|
if (start && end) {
|
||||||
this._codeEditor.getAction(FIND_IDS.NextMatchFindAction).run().then(undefined, onUnexpectedError);
|
const value = content.substr(0, start) + '\n' + content.substr(end);
|
||||||
e.preventDefault();
|
this._findInput.inputBox.value = value;
|
||||||
return;
|
inputElement.setSelectionRange(start + 1, start + 1);
|
||||||
}
|
this._findInput.inputBox.layout();
|
||||||
|
e.preventDefault();
|
||||||
if (e.equals(KeyMod.Shift | KeyCode.Enter)) {
|
return;
|
||||||
this._codeEditor.getAction(FIND_IDS.PreviousMatchFindAction).run().then(undefined, onUnexpectedError);
|
}
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.equals(KeyCode.Tab)) {
|
if (e.equals(KeyCode.Tab)) {
|
||||||
if (this._isReplaceVisible) {
|
if (this._isReplaceVisible) {
|
||||||
this._replaceInputBox.focus();
|
this._replaceInput.focus();
|
||||||
} else {
|
} else {
|
||||||
this._findInput.focusOnCaseSensitive();
|
this._findInput.focusOnCaseSensitive();
|
||||||
}
|
}
|
||||||
@@ -720,20 +806,43 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.equals(KeyCode.UpArrow)) {
|
||||||
|
return stopPropagationForMultiLineUpwards(e, this._findInput.getValue(), this._findInput.domNode.querySelector('textarea'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.equals(KeyCode.DownArrow)) {
|
||||||
|
return stopPropagationForMultiLineDownwards(e, this._findInput.getValue(), this._findInput.domNode.querySelector('textarea'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onReplaceInputKeyDown(e: IKeyboardEvent): void {
|
private _onReplaceInputKeyDown(e: IKeyboardEvent): void {
|
||||||
|
if (e.equals(KeyMod.WinCtrl | KeyCode.Enter)) {
|
||||||
|
if (platform.isWindows && platform.isNative && !this._ctrlEnterReplaceAllWarningPrompted) {
|
||||||
|
// this is the first time when users press Ctrl + Enter to replace all
|
||||||
|
this._notificationService.info(
|
||||||
|
nls.localize('ctrlEnter.keybindingChanged',
|
||||||
|
'Ctrl+Enter now inserts line break instead of replacing all. You can modify the keybinding for editor.action.replaceAll to override this behavior.')
|
||||||
|
);
|
||||||
|
|
||||||
if (e.equals(KeyCode.Enter)) {
|
this._ctrlEnterReplaceAllWarningPrompted = true;
|
||||||
this._controller.replace();
|
this._storageService.store(ctrlEnterReplaceAllWarningPromptedKey, true, StorageScope.GLOBAL);
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.equals(KeyMod.CtrlCmd | KeyCode.Enter)) {
|
}
|
||||||
this._controller.replaceAll();
|
|
||||||
e.preventDefault();
|
const inputElement = this._replaceInput.inputBox.inputElement;
|
||||||
return;
|
const start = inputElement.selectionStart;
|
||||||
|
const end = inputElement.selectionEnd;
|
||||||
|
const content = inputElement.value;
|
||||||
|
|
||||||
|
if (start && end) {
|
||||||
|
const value = content.substr(0, start) + '\n' + content.substr(end);
|
||||||
|
this._replaceInput.inputBox.value = value;
|
||||||
|
inputElement.setSelectionRange(start + 1, start + 1);
|
||||||
|
this._replaceInput.inputBox.layout();
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.equals(KeyCode.Tab)) {
|
if (e.equals(KeyCode.Tab)) {
|
||||||
@@ -753,6 +862,14 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.equals(KeyCode.UpArrow)) {
|
||||||
|
return stopPropagationForMultiLineUpwards(e, this._replaceInput.inputBox.value, this._replaceInput.inputBox.element.querySelector('textarea'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.equals(KeyCode.DownArrow)) {
|
||||||
|
return stopPropagationForMultiLineDownwards(e, this._replaceInput.inputBox.value, this._replaceInput.inputBox.element.querySelector('textarea'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----- sash
|
// ----- sash
|
||||||
@@ -777,6 +894,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _buildDomNode(): void {
|
private _buildDomNode(): void {
|
||||||
|
const flexibleHeight = true;
|
||||||
|
const flexibleWidth = true;
|
||||||
// Find input
|
// Find input
|
||||||
this._findInput = this._register(new ContextScopedFindInput(null, this._contextViewProvider, {
|
this._findInput = this._register(new ContextScopedFindInput(null, this._contextViewProvider, {
|
||||||
width: FIND_INPUT_AREA_WIDTH,
|
width: FIND_INPUT_AREA_WIDTH,
|
||||||
@@ -796,7 +915,10 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
return { content: e.message };
|
return { content: e.message };
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
flexibleHeight,
|
||||||
|
flexibleWidth,
|
||||||
|
flexibleMaxHeight: 118
|
||||||
}, this._contextKeyService, true));
|
}, this._contextKeyService, true));
|
||||||
this._findInput.setRegex(!!this._state.isRegex);
|
this._findInput.setRegex(!!this._state.isRegex);
|
||||||
this._findInput.setCaseSensitive(!!this._state.matchCase);
|
this._findInput.setCaseSensitive(!!this._state.matchCase);
|
||||||
@@ -818,11 +940,24 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
this._register(this._findInput.onCaseSensitiveKeyDown((e) => {
|
this._register(this._findInput.onCaseSensitiveKeyDown((e) => {
|
||||||
if (e.equals(KeyMod.Shift | KeyCode.Tab)) {
|
if (e.equals(KeyMod.Shift | KeyCode.Tab)) {
|
||||||
if (this._isReplaceVisible) {
|
if (this._isReplaceVisible) {
|
||||||
this._replaceInputBox.focus();
|
this._replaceInput.focus();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
this._register(this._findInput.onRegexKeyDown((e) => {
|
||||||
|
if (e.equals(KeyCode.Tab)) {
|
||||||
|
if (this._isReplaceVisible) {
|
||||||
|
this._replaceInput.focusOnPreserve();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
this._register(this._findInput.inputBox.onDidHeightChange((e) => {
|
||||||
|
if (this._tryUpdateHeight()) {
|
||||||
|
this._showViewZone();
|
||||||
|
}
|
||||||
|
}));
|
||||||
if (platform.isLinux) {
|
if (platform.isLinux) {
|
||||||
this._register(this._findInput.onMouseDown((e) => this._onFindInputMouseDown(e)));
|
this._register(this._findInput.onMouseDown((e) => this._onFindInputMouseDown(e)));
|
||||||
}
|
}
|
||||||
@@ -852,13 +987,16 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
let findPart = document.createElement('div');
|
let findPart = document.createElement('div');
|
||||||
findPart.className = 'find-part';
|
findPart.className = 'find-part';
|
||||||
findPart.appendChild(this._findInput.domNode);
|
findPart.appendChild(this._findInput.domNode);
|
||||||
findPart.appendChild(this._matchesCount);
|
const actionsContainer = document.createElement('div');
|
||||||
findPart.appendChild(this._prevBtn.domNode);
|
actionsContainer.className = 'find-actions';
|
||||||
findPart.appendChild(this._nextBtn.domNode);
|
findPart.appendChild(actionsContainer);
|
||||||
|
actionsContainer.appendChild(this._matchesCount);
|
||||||
|
actionsContainer.appendChild(this._prevBtn.domNode);
|
||||||
|
actionsContainer.appendChild(this._nextBtn.domNode);
|
||||||
|
|
||||||
// Toggle selection button
|
// Toggle selection button
|
||||||
this._toggleSelectionFind = this._register(new SimpleCheckbox({
|
this._toggleSelectionFind = this._register(new SimpleCheckbox({
|
||||||
parent: findPart,
|
parent: actionsContainer,
|
||||||
title: NLS_TOGGLE_SELECTION_FIND_TITLE + this._keybindingLabelFor(FIND_IDS.ToggleSearchScopeCommand),
|
title: NLS_TOGGLE_SELECTION_FIND_TITLE + this._keybindingLabelFor(FIND_IDS.ToggleSearchScopeCommand),
|
||||||
onChange: () => {
|
onChange: () => {
|
||||||
if (this._toggleSelectionFind.checked) {
|
if (this._toggleSelectionFind.checked) {
|
||||||
@@ -898,34 +1036,45 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
findPart.appendChild(this._closeBtn.domNode);
|
actionsContainer.appendChild(this._closeBtn.domNode);
|
||||||
|
|
||||||
// Replace input
|
// Replace input
|
||||||
let replaceInput = document.createElement('div');
|
this._replaceInput = this._register(new ContextScopedReplaceInput(null, undefined, {
|
||||||
replaceInput.className = 'replace-input';
|
label: NLS_REPLACE_INPUT_LABEL,
|
||||||
replaceInput.style.width = REPLACE_INPUT_AREA_WIDTH + 'px';
|
|
||||||
this._replaceInputBox = this._register(new ContextScopedHistoryInputBox(replaceInput, undefined, {
|
|
||||||
ariaLabel: NLS_REPLACE_INPUT_LABEL,
|
|
||||||
placeholder: NLS_REPLACE_INPUT_PLACEHOLDER,
|
placeholder: NLS_REPLACE_INPUT_PLACEHOLDER,
|
||||||
history: []
|
history: [],
|
||||||
}, this._contextKeyService));
|
flexibleHeight,
|
||||||
|
flexibleWidth,
|
||||||
|
flexibleMaxHeight: 118
|
||||||
this._register(dom.addStandardDisposableListener(this._replaceInputBox.inputElement, 'keydown', (e) => this._onReplaceInputKeyDown(e)));
|
}, this._contextKeyService, true));
|
||||||
this._register(this._replaceInputBox.onDidChange(() => {
|
this._replaceInput.setPreserveCase(!!this._state.preserveCase);
|
||||||
this._state.change({ replaceString: this._replaceInputBox.value }, false);
|
this._register(this._replaceInput.onKeyDown((e) => this._onReplaceInputKeyDown(e)));
|
||||||
|
this._register(this._replaceInput.inputBox.onDidChange(() => {
|
||||||
|
this._state.change({ replaceString: this._replaceInput.inputBox.value }, false);
|
||||||
}));
|
}));
|
||||||
|
this._register(this._replaceInput.inputBox.onDidHeightChange((e) => {
|
||||||
this._preserveCase = this._register(new Checkbox({
|
if (this._isReplaceVisible && this._tryUpdateHeight()) {
|
||||||
actionClassName: 'monaco-preserve-case',
|
this._showViewZone();
|
||||||
title: NLS_PRESERVE_CASE_LABEL,
|
}
|
||||||
isChecked: false,
|
|
||||||
}));
|
}));
|
||||||
this._preserveCase.checked = !!this._state.preserveCase;
|
this._register(this._replaceInput.onDidOptionChange(() => {
|
||||||
this._register(this._preserveCase.onChange(viaKeyboard => {
|
this._state.change({
|
||||||
if (!viaKeyboard) {
|
preserveCase: this._replaceInput.getPreserveCase()
|
||||||
this._state.change({ preserveCase: !this._state.preserveCase }, false);
|
}, true);
|
||||||
this._replaceInputBox.focus();
|
}));
|
||||||
|
this._register(this._replaceInput.onPreserveCaseKeyDown((e) => {
|
||||||
|
if (e.equals(KeyCode.Tab)) {
|
||||||
|
if (this._prevBtn.isEnabled()) {
|
||||||
|
this._prevBtn.focus();
|
||||||
|
} else if (this._nextBtn.isEnabled()) {
|
||||||
|
this._nextBtn.focus();
|
||||||
|
} else if (this._toggleSelectionFind.isEnabled()) {
|
||||||
|
this._toggleSelectionFind.focus();
|
||||||
|
} else if (this._closeBtn.isEnabled()) {
|
||||||
|
this._closeBtn.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -953,17 +1102,16 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let controls = document.createElement('div');
|
|
||||||
controls.className = 'controls';
|
|
||||||
controls.style.display = 'block';
|
|
||||||
controls.appendChild(this._preserveCase.domNode);
|
|
||||||
replaceInput.appendChild(controls);
|
|
||||||
|
|
||||||
let replacePart = document.createElement('div');
|
let replacePart = document.createElement('div');
|
||||||
replacePart.className = 'replace-part';
|
replacePart.className = 'replace-part';
|
||||||
replacePart.appendChild(replaceInput);
|
replacePart.appendChild(this._replaceInput.domNode);
|
||||||
replacePart.appendChild(this._replaceBtn.domNode);
|
|
||||||
replacePart.appendChild(this._replaceAllBtn.domNode);
|
const replaceActionsContainer = document.createElement('div');
|
||||||
|
replaceActionsContainer.className = 'replace-actions';
|
||||||
|
replacePart.appendChild(replaceActionsContainer);
|
||||||
|
|
||||||
|
replaceActionsContainer.appendChild(this._replaceBtn.domNode);
|
||||||
|
replaceActionsContainer.appendChild(this._replaceAllBtn.domNode);
|
||||||
|
|
||||||
// Toggle replace button
|
// Toggle replace button
|
||||||
this._toggleReplaceBtn = this._register(new SimpleButton({
|
this._toggleReplaceBtn = this._register(new SimpleButton({
|
||||||
@@ -972,7 +1120,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
onTrigger: () => {
|
onTrigger: () => {
|
||||||
this._state.change({ isReplaceRevealed: !this._isReplaceVisible }, false);
|
this._state.change({ isReplaceRevealed: !this._isReplaceVisible }, false);
|
||||||
if (this._isReplaceVisible) {
|
if (this._isReplaceVisible) {
|
||||||
this._replaceInputBox.width = this._findInput.inputBox.width;
|
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
|
||||||
|
this._replaceInput.inputBox.layout();
|
||||||
}
|
}
|
||||||
this._showViewZone();
|
this._showViewZone();
|
||||||
}
|
}
|
||||||
@@ -1015,9 +1164,13 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._domNode.style.width = `${width}px`;
|
this._domNode.style.width = `${width}px`;
|
||||||
|
this._findInput.inputBox.width = inputBoxWidth;
|
||||||
if (this._isReplaceVisible) {
|
if (this._isReplaceVisible) {
|
||||||
this._replaceInputBox.width = inputBoxWidth;
|
this._replaceInput.width = dom.getTotalWidth(this._findInput.domNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._findInput.inputBox.layout();
|
||||||
|
this._tryUpdateHeight();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1077,6 +1230,10 @@ class SimpleCheckbox extends Widget {
|
|||||||
return this._domNode;
|
return this._domNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public isEnabled(): boolean {
|
||||||
|
return (this._domNode.tabIndex >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
public get checked(): boolean {
|
public get checked(): boolean {
|
||||||
return this._checkbox.checked;
|
return this._checkbox.checked;
|
||||||
}
|
}
|
||||||
@@ -1086,7 +1243,7 @@ class SimpleCheckbox extends Widget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public focus(): void {
|
public focus(): void {
|
||||||
this._checkbox.focus();
|
this._domNode.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
private enable(): void {
|
private enable(): void {
|
||||||
@@ -1245,4 +1402,11 @@ registerThemingParticipant((theme, collector) => {
|
|||||||
if (inputActiveBackground) {
|
if (inputActiveBackground) {
|
||||||
collector.addRule(`.monaco-editor .find-widget .monaco-checkbox .checkbox:checked + .label { background-color: ${inputActiveBackground.toString()}; }`);
|
collector.addRule(`.monaco-editor .find-widget .monaco-checkbox .checkbox:checked + .label { background-color: ${inputActiveBackground.toString()}; }`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This rule is used to override the outline color for synthetic-focus find input.
|
||||||
|
const focusOutline = theme.getColor(focusBorder);
|
||||||
|
if (focusOutline) {
|
||||||
|
collector.addRule(`.monaco-workbench .monaco-editor .find-widget .monaco-inputbox.synthetic-focus { outline-color: ${focusOutline}; }`);
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export class ParameterHintsModel extends Disposable {
|
|||||||
public readonly onChangedHints = this._onChangedHints.event;
|
public readonly onChangedHints = this._onChangedHints.event;
|
||||||
|
|
||||||
private readonly editor: ICodeEditor;
|
private readonly editor: ICodeEditor;
|
||||||
private enabled: boolean;
|
private triggerOnType = false;
|
||||||
private _state: ParameterHintState.State = ParameterHintState.Default;
|
private _state: ParameterHintState.State = ParameterHintState.Default;
|
||||||
private readonly _lastSignatureHelpResult = this._register(new MutableDisposable<modes.SignatureHelpResult>());
|
private readonly _lastSignatureHelpResult = this._register(new MutableDisposable<modes.SignatureHelpResult>());
|
||||||
private triggerChars = new CharacterSet();
|
private triggerChars = new CharacterSet();
|
||||||
@@ -68,7 +68,6 @@ export class ParameterHintsModel extends Disposable {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
this.enabled = false;
|
|
||||||
|
|
||||||
this.throttledDelayer = new Delayer(delay);
|
this.throttledDelayer = new Delayer(delay);
|
||||||
|
|
||||||
@@ -242,7 +241,7 @@ export class ParameterHintsModel extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onDidType(text: string) {
|
private onDidType(text: string) {
|
||||||
if (!this.enabled) {
|
if (!this.triggerOnType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,9 +271,9 @@ export class ParameterHintsModel extends Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onEditorConfigurationChange(): void {
|
private onEditorConfigurationChange(): void {
|
||||||
this.enabled = this.editor.getConfiguration().contribInfo.parameterHints.enabled;
|
this.triggerOnType = this.editor.getConfiguration().contribInfo.parameterHints.enabled;
|
||||||
|
|
||||||
if (!this.enabled) {
|
if (!this.triggerOnType) {
|
||||||
this.cancel();
|
this.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,4 +282,4 @@ export class ParameterHintsModel extends Disposable {
|
|||||||
this.cancel(true);
|
this.cancel(true);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,6 +97,10 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.monaco-editor .suggest-widget-deprecated span {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
/** Icon styles **/
|
/** Icon styles **/
|
||||||
|
|
||||||
.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close,
|
.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer';
|
|||||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
import { TimeoutTimer, CancelablePromise, createCancelablePromise, disposableTimeout } from 'vs/base/common/async';
|
import { TimeoutTimer, CancelablePromise, createCancelablePromise, disposableTimeout } from 'vs/base/common/async';
|
||||||
import { CompletionItemKind, completionKindToCssClass } from 'vs/editor/common/modes';
|
import { CompletionItemKind, completionKindToCssClass, CompletionItemKindModifier } from 'vs/editor/common/modes';
|
||||||
import { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
import { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||||
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
|
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
|
||||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||||
@@ -38,6 +38,7 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { FileKind } from 'vs/platform/files/common/files';
|
import { FileKind } from 'vs/platform/files/common/files';
|
||||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||||
|
import { flatten } from 'vs/base/common/arrays';
|
||||||
|
|
||||||
const expandSuggestionDocsByDefault = false;
|
const expandSuggestionDocsByDefault = false;
|
||||||
|
|
||||||
@@ -60,7 +61,6 @@ export const editorSuggestWidgetForeground = registerColor('editorSuggestWidget.
|
|||||||
export const editorSuggestWidgetSelectedBackground = registerColor('editorSuggestWidget.selectedBackground', { dark: listFocusBackground, light: listFocusBackground, hc: listFocusBackground }, nls.localize('editorSuggestWidgetSelectedBackground', 'Background color of the selected entry in the suggest widget.'));
|
export const editorSuggestWidgetSelectedBackground = registerColor('editorSuggestWidget.selectedBackground', { dark: listFocusBackground, light: listFocusBackground, hc: listFocusBackground }, nls.localize('editorSuggestWidgetSelectedBackground', 'Background color of the selected entry in the suggest widget.'));
|
||||||
export const editorSuggestWidgetHighlightForeground = registerColor('editorSuggestWidget.highlightForeground', { dark: listHighlightForeground, light: listHighlightForeground, hc: listHighlightForeground }, nls.localize('editorSuggestWidgetHighlightForeground', 'Color of the match highlights in the suggest widget.'));
|
export const editorSuggestWidgetHighlightForeground = registerColor('editorSuggestWidget.highlightForeground', { dark: listHighlightForeground, light: listHighlightForeground, hc: listHighlightForeground }, nls.localize('editorSuggestWidgetHighlightForeground', 'Color of the match highlights in the suggest widget.'));
|
||||||
|
|
||||||
|
|
||||||
const colorRegExp = /^(#([\da-f]{3}){1,2}|(rgb|hsl)a\(\s*(\d{1,3}%?\s*,\s*){3}(1|0?\.\d+)\)|(rgb|hsl)\(\s*\d{1,3}%?(\s*,\s*\d{1,3}%?){2}\s*\))$/i;
|
const colorRegExp = /^(#([\da-f]{3}){1,2}|(rgb|hsl)a\(\s*(\d{1,3}%?\s*,\s*){3}(1|0?\.\d+)\)|(rgb|hsl)\(\s*\d{1,3}%?(\s*,\s*\d{1,3}%?){2}\s*\))$/i;
|
||||||
function extractColor(item: CompletionItem, out: string[]): boolean {
|
function extractColor(item: CompletionItem, out: string[]): boolean {
|
||||||
if (item.completion.label.match(colorRegExp)) {
|
if (item.completion.label.match(colorRegExp)) {
|
||||||
@@ -173,18 +173,18 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
|||||||
} else if (suggestion.kind === CompletionItemKind.File && this._themeService.getIconTheme().hasFileIcons) {
|
} else if (suggestion.kind === CompletionItemKind.File && this._themeService.getIconTheme().hasFileIcons) {
|
||||||
// special logic for 'file' completion items
|
// special logic for 'file' completion items
|
||||||
data.icon.className = 'icon hide';
|
data.icon.className = 'icon hide';
|
||||||
labelOptions.extraClasses = ([] as string[]).concat(
|
labelOptions.extraClasses = flatten([
|
||||||
getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FILE),
|
getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FILE),
|
||||||
getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FILE)
|
getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FILE)
|
||||||
);
|
]);
|
||||||
|
|
||||||
} else if (suggestion.kind === CompletionItemKind.Folder && this._themeService.getIconTheme().hasFolderIcons) {
|
} else if (suggestion.kind === CompletionItemKind.Folder && this._themeService.getIconTheme().hasFolderIcons) {
|
||||||
// special logic for 'folder' completion items
|
// special logic for 'folder' completion items
|
||||||
data.icon.className = 'icon hide';
|
data.icon.className = 'icon hide';
|
||||||
labelOptions.extraClasses = ([] as string[]).concat(
|
labelOptions.extraClasses = flatten([
|
||||||
getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FOLDER),
|
getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FOLDER),
|
||||||
getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FOLDER)
|
getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FOLDER)
|
||||||
);
|
]);
|
||||||
} else {
|
} else {
|
||||||
// normal icon
|
// normal icon
|
||||||
data.icon.className = 'icon hide';
|
data.icon.className = 'icon hide';
|
||||||
@@ -193,6 +193,10 @@ class Renderer implements IListRenderer<CompletionItem, ISuggestionTemplateData>
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (suggestion.kindModifier && suggestion.kindModifier & CompletionItemKindModifier.Deprecated) {
|
||||||
|
labelOptions.extraClasses = (labelOptions.extraClasses || []).concat(['suggest-widget-deprecated']);
|
||||||
|
}
|
||||||
|
|
||||||
data.iconLabel.setLabel(suggestion.label, undefined, labelOptions);
|
data.iconLabel.setLabel(suggestion.label, undefined, labelOptions);
|
||||||
data.typeLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, '');
|
data.typeLabel.textContent = (suggestion.detail || '').replace(/\n.*$/m, '');
|
||||||
|
|
||||||
|
|||||||
@@ -38,9 +38,6 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
|||||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||||
import { clearAllFontInfos } from 'vs/editor/browser/config/configuration';
|
import { clearAllFontInfos } from 'vs/editor/browser/config/configuration';
|
||||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
|
||||||
import { IProductService } from 'vs/platform/product/common/product';
|
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
|
||||||
|
|
||||||
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||||
|
|
||||||
@@ -54,13 +51,7 @@ function withAllStandaloneServices<T extends editorCommon.IEditor>(domElement: H
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!services.has(IOpenerService)) {
|
if (!services.has(IOpenerService)) {
|
||||||
services.set(IOpenerService, new OpenerService(
|
services.set(IOpenerService, new OpenerService(services.get(ICodeEditorService), services.get(ICommandService)));
|
||||||
services.get(ICodeEditorService),
|
|
||||||
services.get(ICommandService),
|
|
||||||
services.get(IStorageService),
|
|
||||||
services.get(IDialogService),
|
|
||||||
services.get(IProductService)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = callback(services);
|
let result = callback(services);
|
||||||
|
|||||||
@@ -562,6 +562,7 @@ export function createMonacoLanguagesAPI(): typeof monaco.languages {
|
|||||||
// enums
|
// enums
|
||||||
DocumentHighlightKind: standaloneEnums.DocumentHighlightKind,
|
DocumentHighlightKind: standaloneEnums.DocumentHighlightKind,
|
||||||
CompletionItemKind: standaloneEnums.CompletionItemKind,
|
CompletionItemKind: standaloneEnums.CompletionItemKind,
|
||||||
|
CompletionItemKindModifier: standaloneEnums.CompletionItemKindModifier,
|
||||||
CompletionItemInsertTextRule: standaloneEnums.CompletionItemInsertTextRule,
|
CompletionItemInsertTextRule: standaloneEnums.CompletionItemInsertTextRule,
|
||||||
SymbolKind: standaloneEnums.SymbolKind,
|
SymbolKind: standaloneEnums.SymbolKind,
|
||||||
IndentAction: standaloneEnums.IndentAction,
|
IndentAction: standaloneEnums.IndentAction,
|
||||||
|
|||||||
@@ -7,18 +7,13 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
import { OpenerService } from 'vs/editor/browser/services/openerService';
|
import { OpenerService } from 'vs/editor/browser/services/openerService';
|
||||||
import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices';
|
import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices';
|
||||||
import { CommandsRegistry, ICommandService, NullCommandService } from 'vs/platform/commands/common/commands';
|
import { CommandsRegistry, ICommandService, NullCommandService } from 'vs/platform/commands/common/commands';
|
||||||
import { deepClone } from 'vs/base/common/objects';
|
|
||||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
|
||||||
import { IProductService } from 'vs/platform/product/common/product';
|
|
||||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
|
||||||
|
|
||||||
suite('OpenerService', function () {
|
suite('OpenerService', function () {
|
||||||
|
|
||||||
const editorService = new TestCodeEditorService();
|
const editorService = new TestCodeEditorService();
|
||||||
|
|
||||||
let lastCommand: { id: string, args: any[] } | undefined;
|
let lastCommand: { id: string; args: any[] } | undefined;
|
||||||
|
|
||||||
const commandService = new class implements ICommandService {
|
const commandService = new (class implements ICommandService {
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
onWillExecuteCommand = () => ({ dispose: () => { } });
|
onWillExecuteCommand = () => ({ dispose: () => { } });
|
||||||
onDidExecuteCommand = () => ({ dispose: () => { } });
|
onDidExecuteCommand = () => ({ dispose: () => { } });
|
||||||
@@ -26,79 +21,20 @@ suite('OpenerService', function () {
|
|||||||
lastCommand = { id, args };
|
lastCommand = { id, args };
|
||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
};
|
})();
|
||||||
|
|
||||||
function getStorageService(trustedDomainsSetting: string[]) {
|
|
||||||
let _settings = deepClone(trustedDomainsSetting);
|
|
||||||
|
|
||||||
return new class implements IStorageService {
|
|
||||||
get = () => JSON.stringify(_settings);
|
|
||||||
store = (key: string, val: string) => _settings = JSON.parse(val);
|
|
||||||
|
|
||||||
// Don't care
|
|
||||||
_serviceBrand: any;
|
|
||||||
|
|
||||||
onDidChangeStorage = () => ({ dispose: () => { } });
|
|
||||||
onWillSaveState = () => ({ dispose: () => { } });
|
|
||||||
|
|
||||||
getBoolean = () => true;
|
|
||||||
getNumber = () => 0;
|
|
||||||
remove = () => { };
|
|
||||||
logStorage = () => { };
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDialogService() {
|
|
||||||
return new class implements IDialogService {
|
|
||||||
_showInvoked = 0;
|
|
||||||
show = () => {
|
|
||||||
this._showInvoked++;
|
|
||||||
return Promise.resolve({} as any);
|
|
||||||
}
|
|
||||||
get confirmInvoked() { return this._showInvoked; }
|
|
||||||
|
|
||||||
// Don't care
|
|
||||||
_serviceBrand: any;
|
|
||||||
confirm = () => {
|
|
||||||
return Promise.resolve({} as any);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getProductService(): IProductService {
|
|
||||||
return new class {
|
|
||||||
nameShort: 'VS Code';
|
|
||||||
|
|
||||||
_serviceBrand: any;
|
|
||||||
} as IProductService;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
setup(function () {
|
setup(function () {
|
||||||
lastCommand = undefined;
|
lastCommand = undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('delegate to editorService, scheme:///fff', function () {
|
test('delegate to editorService, scheme:///fff', function () {
|
||||||
const openerService = new OpenerService(
|
const openerService = new OpenerService(editorService, NullCommandService);
|
||||||
editorService,
|
|
||||||
NullCommandService,
|
|
||||||
getStorageService([]),
|
|
||||||
getDialogService(),
|
|
||||||
getProductService()
|
|
||||||
);
|
|
||||||
openerService.open(URI.parse('another:///somepath'));
|
openerService.open(URI.parse('another:///somepath'));
|
||||||
assert.equal(editorService.lastInput!.options!.selection, undefined);
|
assert.equal(editorService.lastInput!.options!.selection, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('delegate to editorService, scheme:///fff#L123', function () {
|
test('delegate to editorService, scheme:///fff#L123', function () {
|
||||||
|
const openerService = new OpenerService(editorService, NullCommandService);
|
||||||
const openerService = new OpenerService(
|
|
||||||
editorService,
|
|
||||||
NullCommandService,
|
|
||||||
getStorageService([]),
|
|
||||||
getDialogService(),
|
|
||||||
getProductService()
|
|
||||||
);
|
|
||||||
|
|
||||||
openerService.open(URI.parse('file:///somepath#L23'));
|
openerService.open(URI.parse('file:///somepath#L23'));
|
||||||
assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
|
assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
|
||||||
@@ -120,14 +56,7 @@ suite('OpenerService', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('delegate to editorService, scheme:///fff#123,123', function () {
|
test('delegate to editorService, scheme:///fff#123,123', function () {
|
||||||
|
const openerService = new OpenerService(editorService, NullCommandService);
|
||||||
const openerService = new OpenerService(
|
|
||||||
editorService,
|
|
||||||
NullCommandService,
|
|
||||||
getStorageService([]),
|
|
||||||
getDialogService(),
|
|
||||||
getProductService()
|
|
||||||
);
|
|
||||||
|
|
||||||
openerService.open(URI.parse('file:///somepath#23'));
|
openerService.open(URI.parse('file:///somepath#23'));
|
||||||
assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
|
assert.equal(editorService.lastInput!.options!.selection!.startLineNumber, 23);
|
||||||
@@ -145,14 +74,7 @@ suite('OpenerService', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('delegate to commandsService, command:someid', function () {
|
test('delegate to commandsService, command:someid', function () {
|
||||||
|
const openerService = new OpenerService(editorService, commandService);
|
||||||
const openerService = new OpenerService(
|
|
||||||
editorService,
|
|
||||||
commandService,
|
|
||||||
getStorageService([]),
|
|
||||||
getDialogService(),
|
|
||||||
getProductService()
|
|
||||||
);
|
|
||||||
|
|
||||||
const id = `aCommand${Math.random()}`;
|
const id = `aCommand${Math.random()}`;
|
||||||
CommandsRegistry.registerCommand(id, function () { });
|
CommandsRegistry.registerCommand(id, function () { });
|
||||||
@@ -173,69 +95,107 @@ suite('OpenerService', function () {
|
|||||||
assert.equal(lastCommand!.args[1], true);
|
assert.equal(lastCommand!.args[1], true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('links are protected by dialog.show', function () {
|
test('links are protected by validators', async function () {
|
||||||
const dialogService = getDialogService();
|
const openerService = new OpenerService(editorService, commandService);
|
||||||
const openerService = new OpenerService(
|
|
||||||
editorService,
|
|
||||||
commandService,
|
|
||||||
getStorageService([]),
|
|
||||||
dialogService,
|
|
||||||
getProductService()
|
|
||||||
);
|
|
||||||
|
|
||||||
openerService.open(URI.parse('https://www.microsoft.com'));
|
openerService.registerValidator({ shouldOpen: () => Promise.resolve(false) });
|
||||||
assert.equal(dialogService.confirmInvoked, 1);
|
|
||||||
|
const httpResult = await openerService.open(URI.parse('https://www.microsoft.com'));
|
||||||
|
const httpsResult = await openerService.open(URI.parse('https://www.microsoft.com'));
|
||||||
|
assert.equal(httpResult, false);
|
||||||
|
assert.equal(httpsResult, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('links on the whitelisted domains can be opened without dialog.show', function () {
|
test('links validated by validators go to openers', async function () {
|
||||||
const dialogService = getDialogService();
|
const openerService = new OpenerService(editorService, commandService);
|
||||||
const openerService = new OpenerService(
|
|
||||||
editorService,
|
|
||||||
commandService,
|
|
||||||
getStorageService(['https://microsoft.com']),
|
|
||||||
dialogService,
|
|
||||||
getProductService()
|
|
||||||
);
|
|
||||||
|
|
||||||
openerService.open(URI.parse('https://microsoft.com'));
|
openerService.registerValidator({ shouldOpen: () => Promise.resolve(true) });
|
||||||
openerService.open(URI.parse('https://microsoft.com/'));
|
|
||||||
openerService.open(URI.parse('https://microsoft.com/en-us/'));
|
|
||||||
openerService.open(URI.parse('https://microsoft.com/en-us/?foo=bar'));
|
|
||||||
openerService.open(URI.parse('https://microsoft.com/en-us/?foo=bar#baz'));
|
|
||||||
|
|
||||||
assert.equal(dialogService.confirmInvoked, 0);
|
let openCount = 0;
|
||||||
|
openerService.registerOpener({
|
||||||
|
open: (resource: URI) => {
|
||||||
|
openCount++;
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await openerService.open(URI.parse('http://microsoft.com'));
|
||||||
|
assert.equal(openCount, 1);
|
||||||
|
await openerService.open(URI.parse('https://microsoft.com'));
|
||||||
|
assert.equal(openCount, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('variations of links are protected by dialog confirmation', function () {
|
test('links validated by multiple validators', async function () {
|
||||||
const dialogService = getDialogService();
|
const openerService = new OpenerService(editorService, commandService);
|
||||||
const openerService = new OpenerService(
|
|
||||||
editorService,
|
|
||||||
commandService,
|
|
||||||
getStorageService(['https://microsoft.com']),
|
|
||||||
dialogService,
|
|
||||||
getProductService()
|
|
||||||
);
|
|
||||||
|
|
||||||
openerService.open(URI.parse('http://microsoft.com'));
|
let v1 = 0;
|
||||||
openerService.open(URI.parse('https://www.microsoft.com'));
|
openerService.registerValidator({
|
||||||
|
shouldOpen: () => {
|
||||||
|
v1++;
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
assert.equal(dialogService.confirmInvoked, 2);
|
let v2 = 0;
|
||||||
|
openerService.registerValidator({
|
||||||
|
shouldOpen: () => {
|
||||||
|
v2++;
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let openCount = 0;
|
||||||
|
openerService.registerOpener({
|
||||||
|
open: (resource: URI) => {
|
||||||
|
openCount++;
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await openerService.open(URI.parse('http://microsoft.com'));
|
||||||
|
assert.equal(openCount, 1);
|
||||||
|
assert.equal(v1, 1);
|
||||||
|
assert.equal(v2, 1);
|
||||||
|
await openerService.open(URI.parse('https://microsoft.com'));
|
||||||
|
assert.equal(openCount, 2);
|
||||||
|
assert.equal(v1, 2);
|
||||||
|
assert.equal(v2, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('* removes all link protection', function () {
|
test('links invalidated by first validator do not continue validating', async function () {
|
||||||
const dialogService = getDialogService();
|
const openerService = new OpenerService(editorService, commandService);
|
||||||
const openerService = new OpenerService(
|
|
||||||
editorService,
|
|
||||||
commandService,
|
|
||||||
getStorageService(['*']),
|
|
||||||
dialogService,
|
|
||||||
getProductService()
|
|
||||||
);
|
|
||||||
|
|
||||||
openerService.open(URI.parse('https://code.visualstudio.com/'));
|
let v1 = 0;
|
||||||
openerService.open(URI.parse('https://www.microsoft.com'));
|
openerService.registerValidator({
|
||||||
openerService.open(URI.parse('https://www.github.com'));
|
shouldOpen: () => {
|
||||||
|
v1++;
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
assert.equal(dialogService.confirmInvoked, 0);
|
let v2 = 0;
|
||||||
|
openerService.registerValidator({
|
||||||
|
shouldOpen: () => {
|
||||||
|
v2++;
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let openCount = 0;
|
||||||
|
openerService.registerOpener({
|
||||||
|
open: (resource: URI) => {
|
||||||
|
openCount++;
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await openerService.open(URI.parse('http://microsoft.com'));
|
||||||
|
assert.equal(openCount, 0);
|
||||||
|
assert.equal(v1, 1);
|
||||||
|
assert.equal(v2, 0);
|
||||||
|
await openerService.open(URI.parse('https://microsoft.com'));
|
||||||
|
assert.equal(openCount, 0);
|
||||||
|
assert.equal(v1, 2);
|
||||||
|
assert.equal(v2, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Vendored
+9
@@ -4790,6 +4790,10 @@ declare namespace monaco.languages {
|
|||||||
Snippet = 25
|
Snippet = 25
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CompletionItemKindModifier {
|
||||||
|
Deprecated = 1
|
||||||
|
}
|
||||||
|
|
||||||
export enum CompletionItemInsertTextRule {
|
export enum CompletionItemInsertTextRule {
|
||||||
/**
|
/**
|
||||||
* Adjust whitespace/indentation of multiline insert texts to
|
* Adjust whitespace/indentation of multiline insert texts to
|
||||||
@@ -4818,6 +4822,11 @@ declare namespace monaco.languages {
|
|||||||
* an icon is chosen by the editor.
|
* an icon is chosen by the editor.
|
||||||
*/
|
*/
|
||||||
kind: CompletionItemKind;
|
kind: CompletionItemKind;
|
||||||
|
/**
|
||||||
|
* A modifier to the `kind` which affect how the item
|
||||||
|
* is rendered, e.g. Deprecated is rendered with a strikeout
|
||||||
|
*/
|
||||||
|
kindModifier?: CompletionItemKindModifier;
|
||||||
/**
|
/**
|
||||||
* A human-readable string with additional information
|
* A human-readable string with additional information
|
||||||
* about this item, like type or symbol information.
|
* about this item, like type or symbol information.
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview
|
|||||||
import { IHistoryNavigationWidget } from 'vs/base/browser/history';
|
import { IHistoryNavigationWidget } from 'vs/base/browser/history';
|
||||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||||
|
import { ReplaceInput, IReplaceInputOptions } from 'vs/base/browser/ui/findinput/replaceInput';
|
||||||
|
|
||||||
export const HistoryNavigationWidgetContext = 'historyNavigationWidget';
|
export const HistoryNavigationWidgetContext = 'historyNavigationWidget';
|
||||||
export const HistoryNavigationEnablementContext = 'historyNavigationEnabled';
|
export const HistoryNavigationEnablementContext = 'historyNavigationEnabled';
|
||||||
@@ -60,6 +61,16 @@ export class ContextScopedFindInput extends FindInput {
|
|||||||
super(container, contextViewProvider, showFindOptions, options);
|
super(container, contextViewProvider, showFindOptions, options);
|
||||||
this._register(createAndBindHistoryNavigationWidgetScopedContextKeyService(contextKeyService, <IContextScopedHistoryNavigationWidget>{ target: this.inputBox.element, historyNavigator: this.inputBox }).scopedContextKeyService);
|
this._register(createAndBindHistoryNavigationWidgetScopedContextKeyService(contextKeyService, <IContextScopedHistoryNavigationWidget>{ target: this.inputBox.element, historyNavigator: this.inputBox }).scopedContextKeyService);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ContextScopedReplaceInput extends ReplaceInput {
|
||||||
|
|
||||||
|
constructor(container: HTMLElement | null, contextViewProvider: IContextViewProvider | undefined, options: IReplaceInputOptions,
|
||||||
|
@IContextKeyService contextKeyService: IContextKeyService, showReplaceOptions: boolean = false
|
||||||
|
) {
|
||||||
|
super(container, contextViewProvider, showReplaceOptions, options);
|
||||||
|
this._register(createAndBindHistoryNavigationWidgetScopedContextKeyService(contextKeyService, <IContextScopedHistoryNavigationWidget>{ target: this.inputBox.element, historyNavigator: this.inputBox }).scopedContextKeyService);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,16 +76,27 @@ export function collectWorkspaceStats(folder: string, filter: string[]): Promise
|
|||||||
return done(results);
|
return done(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (token.count > MAX_FILES) {
|
||||||
|
token.count += files.length;
|
||||||
|
token.maxReached = true;
|
||||||
|
return done(results);
|
||||||
|
}
|
||||||
|
|
||||||
let pending = files.length;
|
let pending = files.length;
|
||||||
if (pending === 0) {
|
if (pending === 0) {
|
||||||
return done(results);
|
return done(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const file of files) {
|
let filesToRead = files;
|
||||||
if (token.maxReached) {
|
if (token.count + files.length > MAX_FILES) {
|
||||||
return done(results);
|
token.maxReached = true;
|
||||||
}
|
pending = MAX_FILES - token.count;
|
||||||
|
filesToRead = files.slice(0, pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
token.count += files.length;
|
||||||
|
|
||||||
|
for (const file of filesToRead) {
|
||||||
stat(join(dir, file), (err, stats) => {
|
stat(join(dir, file), (err, stats) => {
|
||||||
// Ignore files that can't be read
|
// Ignore files that can't be read
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -108,11 +119,6 @@ export function collectWorkspaceStats(folder: string, filter: string[]): Promise
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (token.count >= MAX_FILES) {
|
|
||||||
token.maxReached = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
token.count++;
|
|
||||||
results.push(file);
|
results.push(file);
|
||||||
|
|
||||||
if (--pending === 0) {
|
if (--pending === 0) {
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { ILogService, LogLevel, AbstractLogService } from 'vs/platform/log/common/log';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
|
import { Queue } from 'vs/base/common/async';
|
||||||
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
|
|
||||||
|
export class FileLogService extends AbstractLogService implements ILogService {
|
||||||
|
|
||||||
|
_serviceBrand: any;
|
||||||
|
|
||||||
|
private readonly queue: Queue<void>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly name: string,
|
||||||
|
private readonly resource: URI,
|
||||||
|
level: LogLevel,
|
||||||
|
@IFileService private readonly fileService: IFileService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this.setLevel(level);
|
||||||
|
this.queue = this._register(new Queue<void>());
|
||||||
|
}
|
||||||
|
|
||||||
|
trace(): void {
|
||||||
|
if (this.getLevel() <= LogLevel.Trace) {
|
||||||
|
this._log(LogLevel.Trace, this.format(arguments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(): void {
|
||||||
|
if (this.getLevel() <= LogLevel.Debug) {
|
||||||
|
this._log(LogLevel.Debug, this.format(arguments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info(): void {
|
||||||
|
if (this.getLevel() <= LogLevel.Info) {
|
||||||
|
this._log(LogLevel.Info, this.format(arguments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
warn(): void {
|
||||||
|
if (this.getLevel() <= LogLevel.Warning) {
|
||||||
|
this._log(LogLevel.Warning, this.format(arguments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error(): void {
|
||||||
|
if (this.getLevel() <= LogLevel.Error) {
|
||||||
|
const arg = arguments[0];
|
||||||
|
|
||||||
|
if (arg instanceof Error) {
|
||||||
|
const array = Array.prototype.slice.call(arguments) as any[];
|
||||||
|
array[0] = arg.stack;
|
||||||
|
this._log(LogLevel.Error, this.format(array));
|
||||||
|
} else {
|
||||||
|
this._log(LogLevel.Error, this.format(arguments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
critical(): void {
|
||||||
|
if (this.getLevel() <= LogLevel.Critical) {
|
||||||
|
this._log(LogLevel.Critical, this.format(arguments));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flush(): Promise<void> {
|
||||||
|
return this.queue.queue(() => Promise.resolve());
|
||||||
|
}
|
||||||
|
|
||||||
|
log(level: LogLevel, args: any[]): void {
|
||||||
|
this._log(level, this.format(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _log(level: LogLevel, message: string): void {
|
||||||
|
this.queue.queue(async () => {
|
||||||
|
let content = await this.loadContent();
|
||||||
|
content += `[${this.getCurrentTimestamp()}] [${this.name}] [${this.stringifyLogLevel(level)}] ${message}\n`;
|
||||||
|
await this.fileService.writeFile(this.resource, VSBuffer.fromString(content));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCurrentTimestamp(): string {
|
||||||
|
const toTwoDigits = (v: number) => v < 10 ? `0${v}` : v;
|
||||||
|
const toThreeDigits = (v: number) => v < 10 ? `00${v}` : v < 100 ? `0${v}` : v;
|
||||||
|
const currentTime = new Date();
|
||||||
|
return `${currentTime.getFullYear()}-${toTwoDigits(currentTime.getMonth() + 1)}-${toTwoDigits(currentTime.getDate())} ${toTwoDigits(currentTime.getHours())}:${toTwoDigits(currentTime.getMinutes())}:${toTwoDigits(currentTime.getSeconds())}.${toThreeDigits(currentTime.getMilliseconds())}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async loadContent(): Promise<string> {
|
||||||
|
try {
|
||||||
|
const content = await this.fileService.readFile(this.resource);
|
||||||
|
return content.value.toString();
|
||||||
|
} catch (e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private stringifyLogLevel(level: LogLevel): string {
|
||||||
|
switch (level) {
|
||||||
|
case LogLevel.Critical: return 'critical';
|
||||||
|
case LogLevel.Debug: return 'debug';
|
||||||
|
case LogLevel.Error: return 'error';
|
||||||
|
case LogLevel.Info: return 'info';
|
||||||
|
case LogLevel.Trace: return 'trace';
|
||||||
|
case LogLevel.Warning: return 'warning';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
private format(args: any): string {
|
||||||
|
let result = '';
|
||||||
|
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
let a = args[i];
|
||||||
|
|
||||||
|
if (typeof a === 'object') {
|
||||||
|
try {
|
||||||
|
a = JSON.stringify(a);
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
result += (i > 0 ? ' ' : '') + a;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,10 @@ export interface IOpener {
|
|||||||
open(resource: URI, options?: { openExternal?: boolean }): Promise<boolean>;
|
open(resource: URI, options?: { openExternal?: boolean }): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IValidator {
|
||||||
|
shouldOpen(resource: URI): Promise<boolean>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IOpenerService {
|
export interface IOpenerService {
|
||||||
|
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
@@ -23,6 +27,12 @@ export interface IOpenerService {
|
|||||||
*/
|
*/
|
||||||
registerOpener(opener: IOpener): IDisposable;
|
registerOpener(opener: IOpener): IDisposable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a participant that can validate if the URI resource be opened.
|
||||||
|
* validators are run before openers.
|
||||||
|
*/
|
||||||
|
registerValidator(validator: IValidator): IDisposable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a resource, like a webaddress, a document uri, or executes command.
|
* Opens a resource, like a webaddress, a document uri, or executes command.
|
||||||
*
|
*
|
||||||
@@ -36,5 +46,6 @@ export interface IOpenerService {
|
|||||||
export const NullOpenerService: IOpenerService = Object.freeze({
|
export const NullOpenerService: IOpenerService = Object.freeze({
|
||||||
_serviceBrand: undefined,
|
_serviceBrand: undefined,
|
||||||
registerOpener() { return { dispose() { } }; },
|
registerOpener() { return { dispose() { } }; },
|
||||||
|
registerValidator() { return { dispose() { } }; },
|
||||||
open() { return Promise.resolve(false); },
|
open() { return Promise.resolve(false); },
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||||
|
import { RemoteAuthorities } from 'vs/base/common/network';
|
||||||
|
|
||||||
export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverService {
|
export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverService {
|
||||||
|
|
||||||
@@ -15,13 +16,14 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS
|
|||||||
resolveAuthority(authority: string): Promise<ResolverResult> {
|
resolveAuthority(authority: string): Promise<ResolverResult> {
|
||||||
if (authority.indexOf(':') >= 0) {
|
if (authority.indexOf(':') >= 0) {
|
||||||
const pieces = authority.split(':');
|
const pieces = authority.split(':');
|
||||||
return Promise.resolve({
|
return Promise.resolve(this._createResolvedAuthority(authority, pieces[0], parseInt(pieces[1], 10)));
|
||||||
authority: { authority, host: pieces[0], port: parseInt(pieces[1], 10) }
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return Promise.resolve({
|
return Promise.resolve(this._createResolvedAuthority(authority, authority, 80));
|
||||||
authority: { authority, host: authority, port: 80 }
|
}
|
||||||
});
|
|
||||||
|
private _createResolvedAuthority(authority: string, host: string, port: number): ResolverResult {
|
||||||
|
RemoteAuthorities.set(authority, host, port);
|
||||||
|
return { authority: { authority, host, port } };
|
||||||
}
|
}
|
||||||
|
|
||||||
clearResolvedAuthority(authority: string): void {
|
clearResolvedAuthority(authority: string): void {
|
||||||
|
|||||||
Vendored
+11
@@ -1141,4 +1141,15 @@ declare module 'vscode' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region Deprecated support
|
||||||
|
|
||||||
|
export interface CompletionItem {
|
||||||
|
/**
|
||||||
|
* Indicates if this item is deprecated.
|
||||||
|
*/
|
||||||
|
deprecated?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -330,6 +330,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
|||||||
return {
|
return {
|
||||||
label: data.a,
|
label: data.a,
|
||||||
kind: data.b,
|
kind: data.b,
|
||||||
|
kindModifier: data.n ? modes.CompletionItemKindModifier.Deprecated : undefined,
|
||||||
detail: data.c,
|
detail: data.c,
|
||||||
documentation: data.d,
|
documentation: data.d,
|
||||||
sortText: data.e,
|
sortText: data.e,
|
||||||
@@ -366,7 +367,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
|||||||
};
|
};
|
||||||
if (supportsResolveDetails) {
|
if (supportsResolveDetails) {
|
||||||
provider.resolveCompletionItem = (model, position, suggestion, token) => {
|
provider.resolveCompletionItem = (model, position, suggestion, token) => {
|
||||||
return this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion._id, token).then(result => {
|
return this._proxy.$resolveCompletionItem(handle, model.uri, position, suggestion._id!, token).then(result => {
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return suggestion;
|
return suggestion;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,20 +3,46 @@
|
|||||||
* 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 { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { IExtHostContext, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
import { IExtHostContext, ExtHostContext, MainThreadLogShape, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
|
import { UriComponents, URI } from 'vs/base/common/uri';
|
||||||
|
import { FileLogService } from 'vs/platform/log/common/fileLogService';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { basename } from 'vs/base/common/path';
|
||||||
|
|
||||||
@extHostCustomer
|
@extHostNamedCustomer(MainContext.MainThreadLog)
|
||||||
export class MainThreadLogService extends Disposable {
|
export class MainThreadLogService implements MainThreadLogShape {
|
||||||
|
|
||||||
|
private readonly _loggers = new Map<string, FileLogService>();
|
||||||
|
private readonly _logListener: IDisposable;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
extHostContext: IExtHostContext,
|
extHostContext: IExtHostContext,
|
||||||
@ILogService logService: ILogService,
|
@ILogService private readonly _logService: ILogService,
|
||||||
|
@IInstantiationService private readonly _instaService: IInstantiationService,
|
||||||
) {
|
) {
|
||||||
super();
|
const proxy = extHostContext.getProxy(ExtHostContext.ExtHostLogService);
|
||||||
this._register(logService.onDidChangeLogLevel(level => extHostContext.getProxy(ExtHostContext.ExtHostLogService).$setLevel(level)));
|
this._logListener = _logService.onDidChangeLogLevel(level => {
|
||||||
|
proxy.$setLevel(level);
|
||||||
|
this._loggers.forEach(value => value.setLevel(level));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
dispose(): void {
|
||||||
|
this._logListener.dispose();
|
||||||
|
this._loggers.forEach(value => value.dispose());
|
||||||
|
this._loggers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
$log(file: UriComponents, level: LogLevel, message: any[]): void {
|
||||||
|
const uri = URI.revive(file);
|
||||||
|
let logger = this._loggers.get(uri.toString());
|
||||||
|
if (!logger) {
|
||||||
|
logger = this._instaService.createInstance(FileLogService, basename(file.path), URI.revive(file), this._logService.getLevel());
|
||||||
|
this._loggers.set(uri.toString(), logger);
|
||||||
|
}
|
||||||
|
logger.log(level, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
viewStates[handle] = {
|
viewStates[handle] = {
|
||||||
visible: input === group.activeEditor,
|
visible: input === group.activeEditor,
|
||||||
active: input === activeInput,
|
active: input === activeInput,
|
||||||
position: editorGroupToViewColumn(this._editorGroupService, group.id || 0),
|
position: editorGroupToViewColumn(this._editorGroupService, group.id),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -304,10 +304,6 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onDidClickLink(handle: WebviewPanelHandle, link: URI): void {
|
private onDidClickLink(handle: WebviewPanelHandle, link: URI): void {
|
||||||
if (!link) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const webview = this.getWebviewEditorInput(handle);
|
const webview = this.getWebviewEditorInput(handle);
|
||||||
if (this.isSupportedLink(webview, link)) {
|
if (this.isSupportedLink(webview, link)) {
|
||||||
this._openerService.open(link);
|
this._openerService.open(link);
|
||||||
|
|||||||
@@ -939,6 +939,7 @@ export interface ISuggestDataDto {
|
|||||||
k/* commitCharacters */?: string[];
|
k/* commitCharacters */?: string[];
|
||||||
l/* additionalTextEdits */?: ISingleEditOperation[];
|
l/* additionalTextEdits */?: ISingleEditOperation[];
|
||||||
m/* command */?: modes.Command;
|
m/* command */?: modes.Command;
|
||||||
|
n/* deprecated */?: boolean;
|
||||||
// not-standard
|
// not-standard
|
||||||
x?: ChainedCacheId;
|
x?: ChainedCacheId;
|
||||||
}
|
}
|
||||||
@@ -1287,6 +1288,10 @@ export interface ExtHostLogServiceShape {
|
|||||||
$setLevel(level: LogLevel): void;
|
$setLevel(level: LogLevel): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MainThreadLogShape {
|
||||||
|
$log(file: UriComponents, level: LogLevel, args: any[]): void;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ExtHostOutputServiceShape {
|
export interface ExtHostOutputServiceShape {
|
||||||
$setVisibleChannel(channelId: string | null): void;
|
$setVisibleChannel(channelId: string | null): void;
|
||||||
}
|
}
|
||||||
@@ -1329,6 +1334,7 @@ export const MainContext = {
|
|||||||
MainThreadKeytar: createMainId<MainThreadKeytarShape>('MainThreadKeytar'),
|
MainThreadKeytar: createMainId<MainThreadKeytarShape>('MainThreadKeytar'),
|
||||||
MainThreadLanguageFeatures: createMainId<MainThreadLanguageFeaturesShape>('MainThreadLanguageFeatures'),
|
MainThreadLanguageFeatures: createMainId<MainThreadLanguageFeaturesShape>('MainThreadLanguageFeatures'),
|
||||||
MainThreadLanguages: createMainId<MainThreadLanguagesShape>('MainThreadLanguages'),
|
MainThreadLanguages: createMainId<MainThreadLanguagesShape>('MainThreadLanguages'),
|
||||||
|
MainThreadLog: createMainId<MainThreadLogShape>('MainThread'),
|
||||||
MainThreadMessageService: createMainId<MainThreadMessageServiceShape>('MainThreadMessageService'),
|
MainThreadMessageService: createMainId<MainThreadMessageServiceShape>('MainThreadMessageService'),
|
||||||
MainThreadOutputService: createMainId<MainThreadOutputServiceShape>('MainThreadOutputService'),
|
MainThreadOutputService: createMainId<MainThreadOutputServiceShape>('MainThreadOutputService'),
|
||||||
MainThreadProgress: createMainId<MainThreadProgressShape>('MainThreadProgress'),
|
MainThreadProgress: createMainId<MainThreadProgressShape>('MainThreadProgress'),
|
||||||
|
|||||||
@@ -736,6 +736,7 @@ class SuggestAdapter {
|
|||||||
k: item.commitCharacters,
|
k: item.commitCharacters,
|
||||||
l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
|
l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
|
||||||
m: this._commands.toInternal(item.command, disposables),
|
m: this._commands.toInternal(item.command, disposables),
|
||||||
|
n: item.deprecated
|
||||||
};
|
};
|
||||||
|
|
||||||
// 'insertText'-logic
|
// 'insertText'-logic
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHost
|
|||||||
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
||||||
import { endsWith, startsWith } from 'vs/base/common/strings';
|
import { endsWith, startsWith } from 'vs/base/common/strings';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { Schemas } from 'vs/base/common/network';
|
|
||||||
import { joinPath } from 'vs/base/common/resources';
|
import { joinPath } from 'vs/base/common/resources';
|
||||||
import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor';
|
import { RequireInterceptor } from 'vs/workbench/api/common/extHostRequireInterceptor';
|
||||||
|
|
||||||
@@ -128,7 +127,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
|
|||||||
const next = joinPath(parent, '..', ensureSuffix(mod, '.js'));
|
const next = joinPath(parent, '..', ensureSuffix(mod, '.js'));
|
||||||
moduleStack.push(next);
|
moduleStack.push(next);
|
||||||
const trap = ExportsTrap.Instance.add(next.toString());
|
const trap = ExportsTrap.Instance.add(next.toString());
|
||||||
importScripts(asDomUri(next).toString(true));
|
importScripts(next.toString(true));
|
||||||
moduleStack.pop();
|
moduleStack.pop();
|
||||||
|
|
||||||
return trap.claim();
|
return trap.claim();
|
||||||
@@ -139,7 +138,7 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
|
|||||||
module = module.with({ path: ensureSuffix(module.path, '.js') });
|
module = module.with({ path: ensureSuffix(module.path, '.js') });
|
||||||
moduleStack.push(module);
|
moduleStack.push(module);
|
||||||
const trap = ExportsTrap.Instance.add(module.toString());
|
const trap = ExportsTrap.Instance.add(module.toString());
|
||||||
importScripts(asDomUri(module).toString(true));
|
importScripts(module.toString(true));
|
||||||
moduleStack.pop();
|
moduleStack.pop();
|
||||||
return Promise.resolve<T>(trap.claim());
|
return Promise.resolve<T>(trap.claim());
|
||||||
|
|
||||||
@@ -153,16 +152,6 @@ export class ExtHostExtensionService extends AbstractExtHostExtensionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
function ensureSuffix(path: string, suffix: string): string {
|
||||||
return endsWith(path, suffix) ? path : path + suffix;
|
return endsWith(path, suffix) ? path : path + suffix;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,24 +4,33 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { ILogService, LogLevel, AbstractLogService } from 'vs/platform/log/common/log';
|
import { ILogService, LogLevel, AbstractLogService } from 'vs/platform/log/common/log';
|
||||||
import { ExtHostLogServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
import { ExtHostLogServiceShape, MainThreadLogShape, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||||
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
|
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
|
||||||
import * as vscode from 'vscode';
|
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||||
|
import { joinPath } from 'vs/base/common/resources';
|
||||||
|
import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions';
|
||||||
|
import { UriComponents } from 'vs/base/common/uri';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
|
||||||
export class ExtHostLogService extends AbstractLogService implements ILogService, ExtHostLogServiceShape {
|
export class ExtHostLogService extends AbstractLogService implements ILogService, ExtHostLogServiceShape {
|
||||||
|
|
||||||
_serviceBrand: any;
|
_serviceBrand: any;
|
||||||
|
|
||||||
private readonly _logChannel: vscode.OutputChannel;
|
private readonly _proxy: MainThreadLogShape;
|
||||||
|
private readonly _logFile: UriComponents;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@IExtHostRpcService rpc: IExtHostRpcService,
|
||||||
@IExtHostInitDataService initData: IExtHostInitDataService,
|
@IExtHostInitDataService initData: IExtHostInitDataService,
|
||||||
@IExtHostOutputService extHostOutputService: IExtHostOutputService
|
@IExtHostOutputService extHostOutputService: IExtHostOutputService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
const logFile = joinPath(initData.logsLocation, `${ExtensionHostLogFileName}.log`);
|
||||||
|
this._proxy = rpc.getProxy(MainContext.MainThreadLog);
|
||||||
|
this._logFile = logFile.toJSON();
|
||||||
this.setLevel(initData.logLevel);
|
this.setLevel(initData.logLevel);
|
||||||
this._logChannel = extHostOutputService.createOutputChannel('Log (Worker Extension Host)');
|
extHostOutputService.createOutputChannelFromLogFile(localize('name', "Worker Extension Host"), logFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
$setLevel(level: LogLevel): void {
|
$setLevel(level: LogLevel): void {
|
||||||
@@ -30,55 +39,37 @@ export class ExtHostLogService extends AbstractLogService implements ILogService
|
|||||||
|
|
||||||
trace(_message: string, ..._args: any[]): void {
|
trace(_message: string, ..._args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Trace) {
|
if (this.getLevel() <= LogLevel.Trace) {
|
||||||
this._logChannel.appendLine(this._format(arguments));
|
this._proxy.$log(this._logFile, LogLevel.Trace, Array.from(arguments));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug(_message: string, ..._args: any[]): void {
|
debug(_message: string, ..._args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Debug) {
|
if (this.getLevel() <= LogLevel.Debug) {
|
||||||
this._logChannel.appendLine(this._format(arguments));
|
this._proxy.$log(this._logFile, LogLevel.Debug, Array.from(arguments));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info(_message: string, ..._args: any[]): void {
|
info(_message: string, ..._args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Info) {
|
if (this.getLevel() <= LogLevel.Info) {
|
||||||
this._logChannel.appendLine(this._format(arguments));
|
this._proxy.$log(this._logFile, LogLevel.Info, Array.from(arguments));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
warn(_message: string, ..._args: any[]): void {
|
warn(_message: string, ..._args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Warning) {
|
if (this.getLevel() <= LogLevel.Warning) {
|
||||||
this._logChannel.appendLine(this._format(arguments));
|
this._proxy.$log(this._logFile, LogLevel.Warning, Array.from(arguments));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error(_message: string | Error, ..._args: any[]): void {
|
error(_message: string | Error, ..._args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Error) {
|
if (this.getLevel() <= LogLevel.Error) {
|
||||||
this._logChannel.appendLine(this._format(arguments));
|
this._proxy.$log(this._logFile, LogLevel.Error, Array.from(arguments));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
critical(_message: string | Error, ..._args: any[]): void {
|
critical(_message: string | Error, ..._args: any[]): void {
|
||||||
if (this.getLevel() <= LogLevel.Critical) {
|
if (this.getLevel() <= LogLevel.Critical) {
|
||||||
this._logChannel.appendLine(String(arguments));
|
this._proxy.$log(this._logFile, LogLevel.Critical, Array.from(arguments));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _format(args: any): string {
|
|
||||||
let result = '';
|
|
||||||
|
|
||||||
for (let i = 0; i < args.length; i++) {
|
|
||||||
let a = args[i];
|
|
||||||
|
|
||||||
if (typeof a === 'object') {
|
|
||||||
try {
|
|
||||||
a = JSON.stringify(a);
|
|
||||||
} catch (e) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
result += (i > 0 ? ' ' : '') + a;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { domContentLoaded, addDisposableListener, EventType, addClass } from 'vs
|
|||||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||||
import { ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
import { SimpleLogService } from 'vs/workbench/browser/web.simpleservices';
|
|
||||||
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService';
|
||||||
import { Workbench } from 'vs/workbench/browser/workbench';
|
import { Workbench } from 'vs/workbench/browser/workbench';
|
||||||
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||||
@@ -42,6 +41,10 @@ import { getThemeTypeSelector, DARK, HIGH_CONTRAST, LIGHT } from 'vs/platform/th
|
|||||||
import { InMemoryUserDataProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider';
|
import { InMemoryUserDataProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider';
|
||||||
import { registerWindowDriver } from 'vs/platform/driver/browser/driver';
|
import { registerWindowDriver } from 'vs/platform/driver/browser/driver';
|
||||||
import { StaticExtensionsService, IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions';
|
import { StaticExtensionsService, IStaticExtensionsService } from 'vs/workbench/services/extensions/common/staticExtensions';
|
||||||
|
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
|
||||||
|
import { FileLogService } from 'vs/platform/log/common/fileLogService';
|
||||||
|
import { toLocalISOString } from 'vs/base/common/date';
|
||||||
|
import { INDEXEDDB_LOG_SCHEME, IndexedDBLogProvider } from 'vs/workbench/services/log/browser/indexedDBLogProvider';
|
||||||
|
|
||||||
class CodeRendererMain extends Disposable {
|
class CodeRendererMain extends Disposable {
|
||||||
|
|
||||||
@@ -117,13 +120,14 @@ class CodeRendererMain extends Disposable {
|
|||||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
|
||||||
// Log
|
// Log
|
||||||
const logService = new SimpleLogService();
|
const logsPath = URI.file(toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')).with({ scheme: INDEXEDDB_LOG_SCHEME });
|
||||||
|
const logService = new BufferLogService();
|
||||||
serviceCollection.set(ILogService, logService);
|
serviceCollection.set(ILogService, logService);
|
||||||
|
|
||||||
const payload = await this.resolveWorkspaceInitializationPayload();
|
const payload = await this.resolveWorkspaceInitializationPayload();
|
||||||
|
|
||||||
// Environment
|
// Environment
|
||||||
const environmentService = new BrowserWorkbenchEnvironmentService(payload.id, this.configuration);
|
const environmentService = new BrowserWorkbenchEnvironmentService({ workspaceId: payload.id, logsPath, ...this.configuration });
|
||||||
serviceCollection.set(IWorkbenchEnvironmentService, environmentService);
|
serviceCollection.set(IWorkbenchEnvironmentService, environmentService);
|
||||||
|
|
||||||
// Product
|
// Product
|
||||||
@@ -146,6 +150,10 @@ class CodeRendererMain extends Disposable {
|
|||||||
const fileService = this._register(new FileService(logService));
|
const fileService = this._register(new FileService(logService));
|
||||||
serviceCollection.set(IFileService, fileService);
|
serviceCollection.set(IFileService, fileService);
|
||||||
|
|
||||||
|
// Logger
|
||||||
|
fileService.registerProvider(INDEXEDDB_LOG_SCHEME, new IndexedDBLogProvider());
|
||||||
|
logService.logger = new FileLogService('window', environmentService.logFile, logService.getLevel(), fileService);
|
||||||
|
|
||||||
// Static Extensions
|
// Static Extensions
|
||||||
const staticExtensions = new StaticExtensionsService(this.configuration.staticExtensions || []);
|
const staticExtensions = new StaticExtensionsService(this.configuration.staticExtensions || []);
|
||||||
serviceCollection.set(IStaticExtensionsService, staticExtensions);
|
serviceCollection.set(IStaticExtensionsService, staticExtensions);
|
||||||
|
|||||||
@@ -8,10 +8,9 @@ import * as browser from 'vs/base/browser/browser';
|
|||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
|
||||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||||
import { IURLHandler, IURLService } from 'vs/platform/url/common/url';
|
import { IURLHandler, IURLService } from 'vs/platform/url/common/url';
|
||||||
import { ConsoleLogService, ILogService } from 'vs/platform/log/common/log';
|
import { ILogService } from 'vs/platform/log/common/log';
|
||||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
import { IUpdateService, State } from 'vs/platform/update/common/update';
|
import { IUpdateService, State } from 'vs/platform/update/common/update';
|
||||||
@@ -31,7 +30,6 @@ 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';
|
||||||
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';
|
||||||
@@ -40,55 +38,6 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
|
|||||||
// tslint:disable-next-line: import-patterns
|
// tslint:disable-next-line: import-patterns
|
||||||
import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats';
|
import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/common/workspaceStats';
|
||||||
|
|
||||||
//#region Extension Tips
|
|
||||||
|
|
||||||
export class SimpleExtensionTipsService implements IExtensionTipsService {
|
|
||||||
_serviceBrand: any;
|
|
||||||
|
|
||||||
onRecommendationChange = Event.None;
|
|
||||||
|
|
||||||
getAllRecommendationsWithReason(): { [id: string]: { reasonId: ExtensionRecommendationReason; reasonText: string; }; } {
|
|
||||||
return Object.create(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
getFileBasedRecommendations(): IExtensionRecommendation[] {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
getOtherRecommendations(): Promise<IExtensionRecommendation[]> {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getWorkspaceRecommendations(): Promise<IExtensionRecommendation[]> {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getKeymapRecommendations(): IExtensionRecommendation[] {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleIgnoredRecommendation(extensionId: string, shouldIgnore: boolean): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllIgnoredRecommendations(): { global: string[]; workspace: string[]; } {
|
|
||||||
return { global: [], workspace: [] };
|
|
||||||
}
|
|
||||||
|
|
||||||
// {{SQL CARBON EDIT}}
|
|
||||||
getRecommendedExtensionsByScenario(scenarioType: string): Promise<IExtensionRecommendation[]> {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
promptRecommendedExtensionsByScenario(scenarioType: string): void {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// {{SQL CARBON EDIT}} - End
|
|
||||||
}
|
|
||||||
|
|
||||||
registerSingleton(IExtensionTipsService, SimpleExtensionTipsService, true);
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region Extension URL Handler
|
//#region Extension URL Handler
|
||||||
|
|
||||||
export const IExtensionUrlHandler = createDecorator<IExtensionUrlHandler>('inactiveExtensionUrlHandler');
|
export const IExtensionUrlHandler = createDecorator<IExtensionUrlHandler>('inactiveExtensionUrlHandler');
|
||||||
@@ -112,12 +61,6 @@ registerSingleton(IExtensionUrlHandler, SimpleExtensionURLHandler, true);
|
|||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region Log
|
|
||||||
|
|
||||||
export class SimpleLogService extends ConsoleLogService { }
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region Update
|
//#region Update
|
||||||
|
|
||||||
export class SimpleUpdateService implements IUpdateService {
|
export class SimpleUpdateService implements IUpdateService {
|
||||||
@@ -192,7 +135,6 @@ export class SimpleWindowService extends Disposable implements IWindowService {
|
|||||||
@IStorageService private readonly storageService: IStorageService,
|
@IStorageService private readonly storageService: IStorageService,
|
||||||
@IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService,
|
@IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService,
|
||||||
@ILogService private readonly logService: ILogService,
|
@ILogService private readonly logService: ILogService,
|
||||||
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService
|
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -388,7 +330,7 @@ export class SimpleWindowService extends Disposable implements IWindowService {
|
|||||||
for (let i = 0; i < _uris.length; i++) {
|
for (let i = 0; i < _uris.length; i++) {
|
||||||
const uri = _uris[i];
|
const uri = _uris[i];
|
||||||
if ('folderUri' in uri) {
|
if ('folderUri' in uri) {
|
||||||
const newAddress = `${document.location.origin}/?folder=${uri.folderUri.path}${this.workbenchEnvironmentService.configuration.connectionToken ? `&tkn=${this.workbenchEnvironmentService.configuration.connectionToken}` : ''}`;
|
const newAddress = `${document.location.origin}/?folder=${uri.folderUri.path}`;
|
||||||
if (openFolderInNewWindow) {
|
if (openFolderInNewWindow) {
|
||||||
window.open(newAddress);
|
window.open(newAddress);
|
||||||
} else {
|
} else {
|
||||||
@@ -475,7 +417,6 @@ export class SimpleWindowsService implements IWindowsService {
|
|||||||
readonly onRecentlyOpenedChange: Event<void> = Event.None;
|
readonly onRecentlyOpenedChange: Event<void> = Event.None;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
|
||||||
@IDialogService private readonly dialogService: IDialogService,
|
@IDialogService private readonly dialogService: IDialogService,
|
||||||
@IProductService private readonly productService: IProductService,
|
@IProductService private readonly productService: IProductService,
|
||||||
@IClipboardService private readonly clipboardService: IClipboardService
|
@IClipboardService private readonly clipboardService: IClipboardService
|
||||||
@@ -667,11 +608,6 @@ export class SimpleWindowsService implements IWindowsService {
|
|||||||
addQueryParameter('ibe', ibe);
|
addQueryParameter('ibe', ibe);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add connection token
|
|
||||||
if (this.workbenchEnvironmentService.configuration.connectionToken) {
|
|
||||||
addQueryParameter('tkn', this.workbenchEnvironmentService.configuration.connectionToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.open(newAddress);
|
window.open(newAddress);
|
||||||
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import * as dom from 'vs/base/browser/dom';
|
|||||||
import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput';
|
import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findInput';
|
||||||
import { Widget } from 'vs/base/browser/ui/widget';
|
import { Widget } from 'vs/base/browser/ui/widget';
|
||||||
import { Delayer } from 'vs/base/common/async';
|
import { Delayer } from 'vs/base/common/async';
|
||||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||||
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||||
import { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';
|
import { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||||
import { SimpleButton } from 'vs/editor/contrib/find/findWidget';
|
import { SimpleButton } from 'vs/editor/contrib/find/findWidget';
|
||||||
@@ -42,8 +42,7 @@ export abstract class SimpleFindWidget extends Widget {
|
|||||||
@IContextViewService private readonly _contextViewService: IContextViewService,
|
@IContextViewService private readonly _contextViewService: IContextViewService,
|
||||||
@IContextKeyService contextKeyService: IContextKeyService,
|
@IContextKeyService contextKeyService: IContextKeyService,
|
||||||
private readonly _state: FindReplaceState = new FindReplaceState(),
|
private readonly _state: FindReplaceState = new FindReplaceState(),
|
||||||
showOptionButtons?: boolean,
|
showOptionButtons?: boolean
|
||||||
private readonly _invertDefaultDirection: boolean = false
|
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -94,20 +93,6 @@ export abstract class SimpleFindWidget extends Widget {
|
|||||||
this.findFirst();
|
this.findFirst();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._register(this._findInput.onKeyDown((e) => {
|
|
||||||
if (e.equals(KeyCode.Enter)) {
|
|
||||||
this.find(this._invertDefaultDirection);
|
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.equals(KeyMod.Shift | KeyCode.Enter)) {
|
|
||||||
this.find(!this._invertDefaultDirection);
|
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.prevBtn = this._register(new SimpleButton({
|
this.prevBtn = this._register(new SimpleButton({
|
||||||
label: NLS_PREVIOUS_MATCH_BTN_LABEL,
|
label: NLS_PREVIOUS_MATCH_BTN_LABEL,
|
||||||
className: 'previous',
|
className: 'previous',
|
||||||
|
|||||||
@@ -593,13 +593,13 @@ class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem
|
|||||||
return isDebugModel(element) || isDebugSession(element) || (element instanceof Thread && element.stopped);
|
return isDebugModel(element) || isDebugSession(element) || (element instanceof Thread && element.stopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
getChildren(element: IDebugModel | CallStackItem): Promise<CallStackItem[]> {
|
async getChildren(element: IDebugModel | CallStackItem): Promise<CallStackItem[]> {
|
||||||
if (isDebugModel(element)) {
|
if (isDebugModel(element)) {
|
||||||
const sessions = element.getSessions();
|
const sessions = element.getSessions();
|
||||||
if (sessions.length === 0) {
|
if (sessions.length === 0) {
|
||||||
return Promise.resolve([]);
|
return Promise.resolve([]);
|
||||||
}
|
}
|
||||||
if (sessions.length > 1 || this.debugService.getViewModel().isMultiSessionView()) {
|
if (sessions.length > 1) {
|
||||||
return Promise.resolve(sessions.filter(s => !s.parentSession));
|
return Promise.resolve(sessions.filter(s => !s.parentSession));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,9 +609,10 @@ class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem
|
|||||||
} else if (isDebugSession(element)) {
|
} else if (isDebugSession(element)) {
|
||||||
const childSessions = this.debugService.getModel().getSessions().filter(s => s.parentSession === element);
|
const childSessions = this.debugService.getModel().getSessions().filter(s => s.parentSession === element);
|
||||||
const threads: CallStackItem[] = element.getAllThreads();
|
const threads: CallStackItem[] = element.getAllThreads();
|
||||||
if (threads.length === 1 && childSessions.length === 0) {
|
if (threads.length === 1) {
|
||||||
// Do not show thread when there is only one to be compact.
|
// Do not show thread when there is only one to be compact.
|
||||||
return this.getThreadChildren(<Thread>threads[0]);
|
const children = await this.getThreadChildren(<Thread>threads[0]);
|
||||||
|
return children.concat(childSessions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(threads.concat(childSessions));
|
return Promise.resolve(threads.concat(childSessions));
|
||||||
|
|||||||
@@ -245,6 +245,9 @@ export class DebugHoverWidget implements IContentWidget {
|
|||||||
this.layoutTreeAndContainer();
|
this.layoutTreeAndContainer();
|
||||||
this.editor.layoutContentWidget(this);
|
this.editor.layoutContentWidget(this);
|
||||||
this.scrollbar.scanDomNode();
|
this.scrollbar.scanDomNode();
|
||||||
|
this.tree.scrollTop = 0;
|
||||||
|
this.tree.scrollLeft = 0;
|
||||||
|
|
||||||
if (focus) {
|
if (focus) {
|
||||||
this.editor.render();
|
this.editor.render();
|
||||||
this.tree.domFocus();
|
this.tree.domFocus();
|
||||||
|
|||||||
@@ -479,11 +479,11 @@ export class DebugService implements IDebugService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private launchOrAttachToSession(session: IDebugSession, focus = true): Promise<void> {
|
private launchOrAttachToSession(session: IDebugSession, forceFocus = false): Promise<void> {
|
||||||
const dbgr = this.configurationManager.getDebugger(session.configuration.type);
|
const dbgr = this.configurationManager.getDebugger(session.configuration.type);
|
||||||
return session.initialize(dbgr!).then(() => {
|
return session.initialize(dbgr!).then(() => {
|
||||||
return session.launchOrAttach(session.configuration).then(() => {
|
return session.launchOrAttach(session.configuration).then(() => {
|
||||||
if (focus) {
|
if (forceFocus || !this.viewModel.focusedSession) {
|
||||||
this.focusStackFrame(undefined, undefined, session);
|
this.focusStackFrame(undefined, undefined, session);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -572,7 +572,7 @@ export class DebugService implements IDebugService {
|
|||||||
return runTasks().then(taskResult => taskResult === TaskRunResult.Success ? this.extensionHostDebugService.reload(session.getId()) : undefined);
|
return runTasks().then(taskResult => taskResult === TaskRunResult.Success ? this.extensionHostDebugService.reload(session.getId()) : undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldFocus = this.viewModel.focusedSession && session.getId() === this.viewModel.focusedSession.getId();
|
const shouldFocus = !!this.viewModel.focusedSession && session.getId() === this.viewModel.focusedSession.getId();
|
||||||
// If the restart is automatic -> disconnect, otherwise -> terminate #55064
|
// If the restart is automatic -> disconnect, otherwise -> terminate #55064
|
||||||
return (isAutoRestart ? session.disconnect(true) : session.terminate(true)).then(() => {
|
return (isAutoRestart ? session.disconnect(true) : session.terminate(true)).then(() => {
|
||||||
|
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution {
|
|||||||
private registerListeners(): void {
|
private registerListeners(): void {
|
||||||
this._register(this.debugService.onDidChangeState(() => this.updateScheduler.schedule()));
|
this._register(this.debugService.onDidChangeState(() => this.updateScheduler.schedule()));
|
||||||
this._register(this.debugService.getViewModel().onDidFocusSession(() => this.updateScheduler.schedule()));
|
this._register(this.debugService.getViewModel().onDidFocusSession(() => this.updateScheduler.schedule()));
|
||||||
|
this._register(this.debugService.onDidNewSession(() => this.updateScheduler.schedule()));
|
||||||
this._register(this.configurationService.onDidChangeConfiguration(e => this.onDidConfigurationChange(e)));
|
this._register(this.configurationService.onDidChangeConfiguration(e => this.onDidConfigurationChange(e)));
|
||||||
this._register(this.actionBar.actionRunner.onDidRun((e: IRunEvent) => {
|
this._register(this.actionBar.actionRunner.onDidRun((e: IRunEvent) => {
|
||||||
// check for error
|
// check for error
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
|
|||||||
import { getDefaultValue } from 'vs/platform/configuration/common/configurationRegistry';
|
import { getDefaultValue } from 'vs/platform/configuration/common/configurationRegistry';
|
||||||
import { isUndefined } from 'vs/base/common/types';
|
import { isUndefined } from 'vs/base/common/types';
|
||||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import { IWebviewService, Webview } from 'vs/workbench/contrib/webview/browser/webview';
|
import { IWebviewService, Webview, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/webview/browser/webview';
|
||||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
import { renderDashboardContributions } from 'sql/workbench/parts/extensions/browser/contributionRenders'; // {{SQL CARBON EDIT}}
|
import { renderDashboardContributions } from 'sql/workbench/parts/extensions/browser/contributionRenders'; // {{SQL CARBON EDIT}}
|
||||||
import { generateUuid } from 'vs/base/common/uuid';
|
import { generateUuid } from 'vs/base/common/uuid';
|
||||||
@@ -536,6 +536,12 @@ export class ExtensionEditor extends BaseEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runFindAction(previous: boolean): void {
|
||||||
|
if (this.activeElement && (<Webview>this.activeElement).runFindAction) {
|
||||||
|
(<Webview>this.activeElement).runFindAction(previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private onNavbarChange(extension: IExtension, { id, focus }: { id: string | null, focus: boolean }, template: IExtensionEditorTemplate): void {
|
private onNavbarChange(extension: IExtension, { id, focus }: { id: string | null, focus: boolean }, template: IExtensionEditorTemplate): void {
|
||||||
if (this.editorLoadComplete) {
|
if (this.editorLoadComplete) {
|
||||||
/* __GDPR__
|
/* __GDPR__
|
||||||
@@ -1326,28 +1332,66 @@ export class ExtensionEditor extends BaseEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const contextKeyExpr = ContextKeyExpr.and(ContextKeyExpr.equals('activeEditor', ExtensionEditor.ID), ContextKeyExpr.not('editorFocus'));
|
||||||
class ShowExtensionEditorFindCommand extends Command {
|
class ShowExtensionEditorFindCommand extends Command {
|
||||||
public runCommand(accessor: ServicesAccessor, args: any): void {
|
public runCommand(accessor: ServicesAccessor, args: any): void {
|
||||||
const extensionEditor = this.getExtensionEditor(accessor);
|
const extensionEditor = getExtensionEditor(accessor);
|
||||||
if (extensionEditor) {
|
if (extensionEditor) {
|
||||||
extensionEditor.showFind();
|
extensionEditor.showFind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getExtensionEditor(accessor: ServicesAccessor): ExtensionEditor | null {
|
|
||||||
const activeControl = accessor.get(IEditorService).activeControl as ExtensionEditor;
|
|
||||||
if (activeControl instanceof ExtensionEditor) {
|
|
||||||
return activeControl;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const showCommand = new ShowExtensionEditorFindCommand({
|
(new ShowExtensionEditorFindCommand({
|
||||||
id: 'editor.action.extensioneditor.showfind',
|
id: 'editor.action.extensioneditor.showfind',
|
||||||
precondition: ContextKeyExpr.and(ContextKeyExpr.equals('activeEditor', ExtensionEditor.ID), ContextKeyExpr.not('editorFocus')),
|
precondition: contextKeyExpr,
|
||||||
kbOpts: {
|
kbOpts: {
|
||||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_F,
|
primary: KeyMod.CtrlCmd | KeyCode.KEY_F,
|
||||||
weight: KeybindingWeight.EditorContrib
|
weight: KeybindingWeight.EditorContrib
|
||||||
}
|
}
|
||||||
});
|
})).register();
|
||||||
showCommand.register();
|
|
||||||
|
class StartExtensionEditorFindNextCommand extends Command {
|
||||||
|
public runCommand(accessor: ServicesAccessor, args: any): void {
|
||||||
|
const extensionEditor = getExtensionEditor(accessor);
|
||||||
|
if (extensionEditor) {
|
||||||
|
extensionEditor.runFindAction(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(new StartExtensionEditorFindNextCommand({
|
||||||
|
id: 'editor.action.extensioneditor.findNext',
|
||||||
|
precondition: ContextKeyExpr.and(
|
||||||
|
contextKeyExpr,
|
||||||
|
KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED),
|
||||||
|
kbOpts: {
|
||||||
|
primary: KeyCode.Enter,
|
||||||
|
weight: KeybindingWeight.EditorContrib
|
||||||
|
}
|
||||||
|
})).register();
|
||||||
|
|
||||||
|
class StartExtensionEditorFindPreviousCommand extends Command {
|
||||||
|
public runCommand(accessor: ServicesAccessor, args: any): void {
|
||||||
|
const extensionEditor = getExtensionEditor(accessor);
|
||||||
|
if (extensionEditor) {
|
||||||
|
extensionEditor.runFindAction(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(new StartExtensionEditorFindPreviousCommand({
|
||||||
|
id: 'editor.action.extensioneditor.findPrevious',
|
||||||
|
precondition: ContextKeyExpr.and(
|
||||||
|
contextKeyExpr,
|
||||||
|
KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED),
|
||||||
|
kbOpts: {
|
||||||
|
primary: KeyMod.Shift | KeyCode.Enter,
|
||||||
|
weight: KeybindingWeight.EditorContrib
|
||||||
|
}
|
||||||
|
})).register();
|
||||||
|
|
||||||
|
function getExtensionEditor(accessor: ServicesAccessor): ExtensionEditor | null {
|
||||||
|
const activeControl = accessor.get(IEditorService).activeControl as ExtensionEditor;
|
||||||
|
if (activeControl instanceof ExtensionEditor) {
|
||||||
|
return activeControl;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,11 +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 { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
|
||||||
import { IExtensionTipsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
|
||||||
import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/browser/extensionTipsService';
|
|
||||||
|
|
||||||
// Singletons
|
|
||||||
registerSingleton(IExtensionTipsService, ExtensionTipsService);
|
|
||||||
@@ -3100,7 +3100,6 @@ export class InstallLocalExtensionsInRemoteAction extends Action {
|
|||||||
private extensions: IExtension[] | undefined = undefined;
|
private extensions: IExtension[] | undefined = undefined;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly selectAndInstall: boolean,
|
|
||||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||||
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
@IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
|
||||||
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
|
@IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService,
|
||||||
@@ -3122,9 +3121,7 @@ export class InstallLocalExtensionsInRemoteAction extends Action {
|
|||||||
|
|
||||||
get label(): string {
|
get label(): string {
|
||||||
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
if (this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||||
return this.selectAndInstall ?
|
return localize('select and install local extensions', "Install Local Extensions in {0}...", this.extensionManagementServerService.remoteExtensionManagementServer.label);
|
||||||
localize('select and install local extensions', "Install Local Extensions in {0}...", this.extensionManagementServerService.remoteExtensionManagementServer.label)
|
|
||||||
: localize('install local extensions', "Install Local Extensions in {0}", this.extensionManagementServerService.remoteExtensionManagementServer.label);
|
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -3140,12 +3137,7 @@ export class InstallLocalExtensionsInRemoteAction extends Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async run(): Promise<void> {
|
async run(): Promise<void> {
|
||||||
if (this.selectAndInstall) {
|
return this.selectAndInstallLocalExtensions();
|
||||||
return this.selectAndInstallLocalExtensions();
|
|
||||||
} else {
|
|
||||||
const extensionsToInstall = await this.queryExtensionsToInstall();
|
|
||||||
return this.installLocalExtensions(extensionsToInstall);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async queryExtensionsToInstall(): Promise<IExtension[]> {
|
private async queryExtensionsToInstall(): Promise<IExtension[]> {
|
||||||
|
|||||||
@@ -961,7 +961,7 @@ export class ServerExtensionsView extends ExtensionsListView {
|
|||||||
|
|
||||||
getActions(): IAction[] {
|
getActions(): IAction[] {
|
||||||
if (this.extensionManagementServerService.remoteExtensionManagementServer && 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));
|
||||||
installLocalExtensionsInRemoteAction.class = 'octicon octicon-cloud-download';
|
installLocalExtensionsInRemoteAction.class = 'octicon octicon-cloud-download';
|
||||||
return [installLocalExtensionsInRemoteAction];
|
return [installLocalExtensionsInRemoteAction];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export class RemoteExtensionsInstaller extends Disposable implements IWorkbenchC
|
|||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
|
if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||||
const installLocalExtensionsInRemoteAction = instantiationService.createInstance(InstallLocalExtensionsInRemoteAction, true);
|
const installLocalExtensionsInRemoteAction = instantiationService.createInstance(InstallLocalExtensionsInRemoteAction);
|
||||||
CommandsRegistry.registerCommand('workbench.extensions.installLocalExtensions', () => installLocalExtensionsInRemoteAction.run());
|
CommandsRegistry.registerCommand('workbench.extensions.installLocalExtensions', () => installLocalExtensionsInRemoteAction.run());
|
||||||
let disposable = Disposable.None;
|
let disposable = Disposable.None;
|
||||||
const appendMenuItem = () => {
|
const appendMenuItem = () => {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { IDecorationsProvider, IDecorationData } from 'vs/workbench/services/dec
|
|||||||
import { listInvalidItemForeground } from 'vs/platform/theme/common/colorRegistry';
|
import { listInvalidItemForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
import { IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
import { IExplorerService } from 'vs/workbench/contrib/files/common/files';
|
||||||
|
import { explorerRootErrorEmitter } from 'vs/workbench/contrib/files/browser/views/explorerViewer';
|
||||||
|
|
||||||
export class ExplorerDecorationsProvider implements IDecorationsProvider {
|
export class ExplorerDecorationsProvider implements IDecorationsProvider {
|
||||||
readonly label: string = localize('label', "Explorer");
|
readonly label: string = localize('label', "Explorer");
|
||||||
@@ -30,6 +31,9 @@ export class ExplorerDecorationsProvider implements IDecorationsProvider {
|
|||||||
this._onDidChange.fire([change.item.resource]);
|
this._onDidChange.fire([change.item.resource]);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
this.toDispose.add(explorerRootErrorEmitter.event((resource => {
|
||||||
|
this._onDidChange.fire([resource]);
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
get onDidChange(): Event<URI[]> {
|
get onDidChange(): Event<URI[]> {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import { first } from 'vs/base/common/arrays';
|
|||||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||||
import { IFileService, FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
|
import { IFileService, FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
|
||||||
import { dispose } from 'vs/base/common/lifecycle';
|
import { dispose } from 'vs/base/common/lifecycle';
|
||||||
|
import { timeout } from 'vs/base/common/async';
|
||||||
|
|
||||||
export class ExplorerView extends ViewletPanel {
|
export class ExplorerView extends ViewletPanel {
|
||||||
static readonly ID: string = 'workbench.explorer.fileView';
|
static readonly ID: string = 'workbench.explorer.fileView';
|
||||||
@@ -522,6 +523,8 @@ export class ExplorerView extends ViewletPanel {
|
|||||||
|
|
||||||
while (item && item.resource.toString() !== resource.toString()) {
|
while (item && item.resource.toString() !== resource.toString()) {
|
||||||
await this.tree.expand(item);
|
await this.tree.expand(item);
|
||||||
|
// Tree returns too early from the expand, need to wait for next tick #77106
|
||||||
|
await timeout(0);
|
||||||
item = first(values(item.children), i => isEqualOrParent(resource, i.resource));
|
item = first(values(item.children), i => isEqualOrParent(resource, i.resource));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
|||||||
import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces';
|
import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces';
|
||||||
import { findValidPasteFileTarget } from 'vs/workbench/contrib/files/browser/fileActions';
|
import { findValidPasteFileTarget } from 'vs/workbench/contrib/files/browser/fileActions';
|
||||||
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
||||||
|
import { Emitter } from 'vs/base/common/event';
|
||||||
|
|
||||||
export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {
|
export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {
|
||||||
|
|
||||||
@@ -60,6 +61,7 @@ export class ExplorerDelegate implements IListVirtualDelegate<ExplorerItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const explorerRootErrorEmitter = new Emitter<URI>();
|
||||||
export class ExplorerDataSource implements IAsyncDataSource<ExplorerItem | ExplorerItem[], ExplorerItem> {
|
export class ExplorerDataSource implements IAsyncDataSource<ExplorerItem | ExplorerItem[], ExplorerItem> {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -87,8 +89,9 @@ export class ExplorerDataSource implements IAsyncDataSource<ExplorerItem | Explo
|
|||||||
// Single folder create a dummy explorer item to show error
|
// Single folder create a dummy explorer item to show error
|
||||||
const placeholder = new ExplorerItem(element.resource, undefined, false);
|
const placeholder = new ExplorerItem(element.resource, undefined, false);
|
||||||
placeholder.isError = true;
|
placeholder.isError = true;
|
||||||
|
|
||||||
return [placeholder];
|
return [placeholder];
|
||||||
|
} else {
|
||||||
|
explorerRootErrorEmitter.fire(element.resource);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Do not show error for roots since we already use an explorer decoration to notify user
|
// Do not show error for roots since we already use an explorer decoration to notify user
|
||||||
|
|||||||
@@ -247,9 +247,14 @@ export class ExplorerItem {
|
|||||||
// Resolve metadata only when the mtime is needed since this can be expensive
|
// Resolve metadata only when the mtime is needed since this can be expensive
|
||||||
// Mtime is only used when the sort order is 'modified'
|
// Mtime is only used when the sort order is 'modified'
|
||||||
const resolveMetadata = explorerService.sortOrder === 'modified';
|
const resolveMetadata = explorerService.sortOrder === 'modified';
|
||||||
const stat = await fileService.resolve(this.resource, { resolveSingleChildDescendants: true, resolveMetadata });
|
try {
|
||||||
const resolved = ExplorerItem.create(stat, this);
|
const stat = await fileService.resolve(this.resource, { resolveSingleChildDescendants: true, resolveMetadata });
|
||||||
ExplorerItem.mergeLocalWithDisk(resolved, this);
|
const resolved = ExplorerItem.create(stat, this);
|
||||||
|
ExplorerItem.mergeLocalWithDisk(resolved, this);
|
||||||
|
} catch (e) {
|
||||||
|
this.isError = true;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
this._isDirectoryResolved = true;
|
this._isDirectoryResolved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,90 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import * as nls from 'vs/nls';
|
import * as nls from 'vs/nls';
|
||||||
|
import { join } from 'vs/base/common/path';
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions';
|
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions';
|
||||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||||
import { SetLogLevelAction } from 'vs/workbench/contrib/logs/common/logsActions';
|
import { SetLogLevelAction, OpenLogsFolderAction, OpenSessionLogFileAction } from 'vs/workbench/contrib/logs/common/logsActions';
|
||||||
|
import * as Constants from 'vs/workbench/contrib/logs/common/logConstants';
|
||||||
|
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||||
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
import { IFileService, FileChangeType } from 'vs/platform/files/common/files';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { IOutputChannelRegistry, Extensions as OutputExt } from 'vs/workbench/contrib/output/common/output';
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
|
||||||
|
import { dirname } from 'vs/base/common/resources';
|
||||||
|
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||||
|
import { isWeb } from 'vs/base/common/platform';
|
||||||
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { LogsDataCleaner } from 'vs/workbench/contrib/logs/common/logsDataCleaner';
|
||||||
|
|
||||||
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions);
|
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions);
|
||||||
const devCategory = nls.localize('developer', "Developer");
|
const devCategory = nls.localize('developer', "Developer");
|
||||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SetLogLevelAction, SetLogLevelAction.ID, SetLogLevelAction.LABEL), 'Developer: Set Log Level...', devCategory);
|
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SetLogLevelAction, SetLogLevelAction.ID, SetLogLevelAction.LABEL), 'Developer: Set Log Level...', devCategory);
|
||||||
|
|
||||||
|
class LogOutputChannels extends Disposable implements IWorkbenchContribution {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||||
|
@ILogService private readonly logService: ILogService,
|
||||||
|
@IFileService private readonly fileService: IFileService,
|
||||||
|
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
if (isWeb) {
|
||||||
|
this.registerWebContributions();
|
||||||
|
} else {
|
||||||
|
this.registerNativeContributions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerWebContributions(): void {
|
||||||
|
Registry.as<IOutputChannelRegistry>(OutputExt.OutputChannels).registerChannel({ id: Constants.rendererLogChannelId, label: nls.localize('rendererLog', "Window"), file: this.environmentService.logFile, log: true });
|
||||||
|
this.instantiationService.createInstance(LogsDataCleaner);
|
||||||
|
|
||||||
|
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions);
|
||||||
|
const devCategory = nls.localize('developer', "Developer");
|
||||||
|
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenSessionLogFileAction, OpenSessionLogFileAction.ID, OpenSessionLogFileAction.LABEL), 'Developer: Open Log File (Session)...', devCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerNativeContributions(): void {
|
||||||
|
this.registerLogChannel(Constants.mainLogChannelId, nls.localize('mainLog', "Main"), URI.file(join(this.environmentService.logsPath, `main.log`)));
|
||||||
|
this.registerLogChannel(Constants.sharedLogChannelId, nls.localize('sharedLog', "Shared"), URI.file(join(this.environmentService.logsPath, `sharedprocess.log`)));
|
||||||
|
this.registerLogChannel(Constants.rendererLogChannelId, nls.localize('rendererLog', "Window"), this.environmentService.logFile);
|
||||||
|
|
||||||
|
const registerTelemetryChannel = (level: LogLevel) => {
|
||||||
|
if (level === LogLevel.Trace && !Registry.as<IOutputChannelRegistry>(OutputExt.OutputChannels).getChannel(Constants.telemetryLogChannelId)) {
|
||||||
|
this.registerLogChannel(Constants.telemetryLogChannelId, nls.localize('telemetryLog', "Telemetry"), URI.file(join(this.environmentService.logsPath, `telemetry.log`)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
registerTelemetryChannel(this.logService.getLevel());
|
||||||
|
this.logService.onDidChangeLogLevel(registerTelemetryChannel);
|
||||||
|
|
||||||
|
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions);
|
||||||
|
const devCategory = nls.localize('developer', "Developer");
|
||||||
|
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Developer: Open Logs Folder', devCategory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async registerLogChannel(id: string, label: string, file: URI): Promise<void> {
|
||||||
|
const outputChannelRegistry = Registry.as<IOutputChannelRegistry>(OutputExt.OutputChannels);
|
||||||
|
const exists = await this.fileService.exists(file);
|
||||||
|
if (exists) {
|
||||||
|
outputChannelRegistry.registerChannel({ id, label, file, log: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const watcher = this.fileService.watch(dirname(file));
|
||||||
|
const disposable = this.fileService.onFileChanges(e => {
|
||||||
|
if (e.contains(file, FileChangeType.ADDED)) {
|
||||||
|
watcher.dispose();
|
||||||
|
disposable.dispose();
|
||||||
|
outputChannelRegistry.registerChannel({ id, label, file, log: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, LifecyclePhase.Restored);
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ import { join } from 'vs/base/common/path';
|
|||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||||
import { ILogService, LogLevel, DEFAULT_LOG_LEVEL } from 'vs/platform/log/common/log';
|
import { ILogService, LogLevel, DEFAULT_LOG_LEVEL } from 'vs/platform/log/common/log';
|
||||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
import { dirname, basename, isEqual } from 'vs/base/common/resources';
|
||||||
|
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
|
||||||
export class OpenLogsFolderAction extends Action {
|
export class OpenLogsFolderAction extends Action {
|
||||||
|
|
||||||
@@ -73,3 +77,68 @@ export class SetLogLevelAction extends Action {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class OpenSessionLogFileAction extends Action {
|
||||||
|
|
||||||
|
static ID = 'workbench.action.openSessionLogFile';
|
||||||
|
static LABEL = nls.localize('openSessionLogFile', "Open Log File (Session)...");
|
||||||
|
|
||||||
|
constructor(id: string, label: string,
|
||||||
|
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||||
|
@IFileService private readonly fileService: IFileService,
|
||||||
|
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||||
|
@IEditorService private readonly editorService: IEditorService,
|
||||||
|
) {
|
||||||
|
super(id, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(): Promise<void> {
|
||||||
|
const sessionResult = await this.quickInputService.pick(
|
||||||
|
this.getSessions().then(sessions => sessions.map((s, index) => (<IQuickPickItem>{
|
||||||
|
id: s.toString(),
|
||||||
|
label: basename(s),
|
||||||
|
description: index === 0 ? nls.localize('current', "Current") : undefined
|
||||||
|
}))),
|
||||||
|
{
|
||||||
|
canPickMany: false,
|
||||||
|
placeHolder: nls.localize('sessions placeholder', "Select Session")
|
||||||
|
});
|
||||||
|
if (sessionResult) {
|
||||||
|
const logFileResult = await this.quickInputService.pick(
|
||||||
|
this.getLogFiles(URI.parse(sessionResult.id!)).then(logFiles => logFiles.map(s => (<IQuickPickItem>{
|
||||||
|
id: s.toString(),
|
||||||
|
label: basename(s)
|
||||||
|
}))),
|
||||||
|
{
|
||||||
|
canPickMany: false,
|
||||||
|
placeHolder: nls.localize('log placeholder', "Select Log file")
|
||||||
|
});
|
||||||
|
if (logFileResult) {
|
||||||
|
return this.editorService.openEditor({ resource: URI.parse(logFileResult.id!) }).then(() => undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getSessions(): Promise<URI[]> {
|
||||||
|
const logsPath = URI.file(this.environmentService.logsPath).with({ scheme: this.environmentService.logFile.scheme });
|
||||||
|
const result: URI[] = [logsPath];
|
||||||
|
const stat = await this.fileService.resolve(dirname(logsPath));
|
||||||
|
if (stat.children) {
|
||||||
|
result.push(...stat.children
|
||||||
|
.filter(stat => !isEqual(stat.resource, logsPath) && stat.isDirectory && /^\d{8}T\d{6}$/.test(stat.name))
|
||||||
|
.sort()
|
||||||
|
.reverse()
|
||||||
|
.map(d => d.resource));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getLogFiles(session: URI): Promise<URI[]> {
|
||||||
|
const stat = await this.fileService.resolve(session);
|
||||||
|
if (stat.children) {
|
||||||
|
return stat.children.filter(stat => !stat.isDirectory).map(stat => stat.resource);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { IFileService } from 'vs/platform/files/common/files';
|
||||||
|
import { basename, dirname } from 'vs/base/common/resources';
|
||||||
|
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||||
|
|
||||||
|
export class LogsDataCleaner extends Disposable {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
|
||||||
|
@IFileService private readonly fileService: IFileService,
|
||||||
|
@ILifecycleService private readonly lifecycleService: ILifecycleService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this.cleanUpOldLogsSoon();
|
||||||
|
}
|
||||||
|
|
||||||
|
private cleanUpOldLogsSoon(): void {
|
||||||
|
let handle: NodeJS.Timeout | undefined = setTimeout(async () => {
|
||||||
|
handle = undefined;
|
||||||
|
const logsPath = URI.file(this.environmentService.logsPath).with({ scheme: this.environmentService.logFile.scheme });
|
||||||
|
const stat = await this.fileService.resolve(dirname(logsPath));
|
||||||
|
if (stat.children) {
|
||||||
|
const currentLog = basename(logsPath);
|
||||||
|
const allSessions = stat.children.filter(stat => stat.isDirectory && /^\d{8}T\d{6}$/.test(stat.name));
|
||||||
|
const oldSessions = allSessions.sort().filter((d, i) => d.name !== currentLog);
|
||||||
|
const toDelete = oldSessions.slice(0, Math.max(0, oldSessions.length - 49));
|
||||||
|
Promise.all(toDelete.map(stat => this.fileService.del(stat.resource, { recursive: true })));
|
||||||
|
}
|
||||||
|
}, 10 * 1000);
|
||||||
|
this.lifecycleService.onWillShutdown(() => {
|
||||||
|
if (handle) {
|
||||||
|
clearTimeout(handle);
|
||||||
|
handle = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,68 +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 * as nls from 'vs/nls';
|
|
||||||
import { join } from 'vs/base/common/path';
|
|
||||||
import { Registry } from 'vs/platform/registry/common/platform';
|
|
||||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
|
||||||
import { IOutputChannelRegistry, Extensions as OutputExt, } from 'vs/workbench/contrib/output/common/output';
|
|
||||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
|
||||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
|
||||||
import { Disposable } from 'vs/base/common/lifecycle';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
|
||||||
import * as Constants from 'vs/workbench/contrib/logs/common/logConstants';
|
|
||||||
import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actions';
|
|
||||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
|
||||||
import { OpenLogsFolderAction } from 'vs/workbench/contrib/logs/common/logsActions';
|
|
||||||
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
|
|
||||||
import { IFileService, FileChangeType } from 'vs/platform/files/common/files';
|
|
||||||
import { dirname } from 'vs/base/common/resources';
|
|
||||||
|
|
||||||
class LogOutputChannels extends Disposable implements IWorkbenchContribution {
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
|
|
||||||
@ILogService logService: ILogService,
|
|
||||||
@IFileService private readonly fileService: IFileService
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
this.registerLogChannel(Constants.mainLogChannelId, nls.localize('mainLog', "Main"), URI.file(join(environmentService.logsPath, `main.log`)));
|
|
||||||
this.registerLogChannel(Constants.sharedLogChannelId, nls.localize('sharedLog', "Shared"), URI.file(join(environmentService.logsPath, `sharedprocess.log`)));
|
|
||||||
this.registerLogChannel(Constants.rendererLogChannelId, nls.localize('rendererLog', "Window"), URI.file(join(environmentService.logsPath, `renderer${environmentService.configuration.windowId}.log`)));
|
|
||||||
|
|
||||||
const registerTelemetryChannel = (level: LogLevel) => {
|
|
||||||
if (level === LogLevel.Trace && !Registry.as<IOutputChannelRegistry>(OutputExt.OutputChannels).getChannel(Constants.telemetryLogChannelId)) {
|
|
||||||
this.registerLogChannel(Constants.telemetryLogChannelId, nls.localize('telemetryLog', "Telemetry"), URI.file(join(environmentService.logsPath, `telemetry.log`)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
registerTelemetryChannel(logService.getLevel());
|
|
||||||
logService.onDidChangeLogLevel(registerTelemetryChannel);
|
|
||||||
|
|
||||||
const workbenchActionsRegistry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionExtensions.WorkbenchActions);
|
|
||||||
const devCategory = nls.localize('developer', "Developer");
|
|
||||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Developer: Open Logs Folder', devCategory);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async registerLogChannel(id: string, label: string, file: URI): Promise<void> {
|
|
||||||
const outputChannelRegistry = Registry.as<IOutputChannelRegistry>(OutputExt.OutputChannels);
|
|
||||||
const exists = await this.fileService.exists(file);
|
|
||||||
if (exists) {
|
|
||||||
outputChannelRegistry.registerChannel({ id, label, file, log: true });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const watcher = this.fileService.watch(dirname(file));
|
|
||||||
const disposable = this.fileService.onFileChanges(e => {
|
|
||||||
if (e.contains(file, FileChangeType.ADDED)) {
|
|
||||||
watcher.dispose();
|
|
||||||
disposable.dispose();
|
|
||||||
outputChannelRegistry.registerChannel({ id, label, file, log: true });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, LifecyclePhase.Restored);
|
|
||||||
@@ -109,7 +109,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
|
|||||||
) {
|
) {
|
||||||
super(KeybindingsEditor.ID, telemetryService, themeService, storageService);
|
super(KeybindingsEditor.ID, telemetryService, themeService, storageService);
|
||||||
this.delayedFiltering = new Delayer<void>(300);
|
this.delayedFiltering = new Delayer<void>(300);
|
||||||
this._register(keybindingsService.onDidUpdateKeybindings(() => this.render(true)));
|
this._register(keybindingsService.onDidUpdateKeybindings(() => this.render(!!this.keybindingFocusContextKey.get())));
|
||||||
|
|
||||||
this.keybindingsEditorContextKey = CONTEXT_KEYBINDINGS_EDITOR.bindTo(this.contextKeyService);
|
this.keybindingsEditorContextKey = CONTEXT_KEYBINDINGS_EDITOR.bindTo(this.contextKeyService);
|
||||||
this.searchFocusContextKey = CONTEXT_KEYBINDINGS_SEARCH_FOCUS.bindTo(this.contextKeyService);
|
this.searchFocusContextKey = CONTEXT_KEYBINDINGS_SEARCH_FOCUS.bindTo(this.contextKeyService);
|
||||||
@@ -537,7 +537,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
|
|||||||
}
|
}
|
||||||
this.unAssignedKeybindingItemToRevealAndFocus = null;
|
this.unAssignedKeybindingItemToRevealAndFocus = null;
|
||||||
} else if (currentSelectedIndex !== -1 && currentSelectedIndex < this.listEntries.length) {
|
} else if (currentSelectedIndex !== -1 && currentSelectedIndex < this.listEntries.length) {
|
||||||
this.selectEntry(currentSelectedIndex);
|
this.selectEntry(currentSelectedIndex, preserveFocus);
|
||||||
} else if (this.editorService.activeControl === this && !preserveFocus) {
|
} else if (this.editorService.activeControl === this && !preserveFocus) {
|
||||||
this.focus();
|
this.focus();
|
||||||
}
|
}
|
||||||
@@ -597,11 +597,13 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private selectEntry(keybindingItemEntry: IKeybindingItemEntry | number): void {
|
private selectEntry(keybindingItemEntry: IKeybindingItemEntry | number, focus: boolean = true): void {
|
||||||
const index = typeof keybindingItemEntry === 'number' ? keybindingItemEntry : this.getIndexOf(keybindingItemEntry);
|
const index = typeof keybindingItemEntry === 'number' ? keybindingItemEntry : this.getIndexOf(keybindingItemEntry);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this.keybindingsList.getHTMLElement().focus();
|
if (focus) {
|
||||||
this.keybindingsList.setFocus([index]);
|
this.keybindingsList.getHTMLElement().focus();
|
||||||
|
this.keybindingsList.setFocus([index]);
|
||||||
|
}
|
||||||
this.keybindingsList.setSelection([index]);
|
this.keybindingsList.setSelection([index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ export class TOCRenderer implements ITreeRenderer<SettingsTreeGroupElement, neve
|
|||||||
const label = element.label;
|
const label = element.label;
|
||||||
|
|
||||||
template.labelElement.textContent = label;
|
template.labelElement.textContent = label;
|
||||||
|
template.labelElement.title = label;
|
||||||
|
|
||||||
if (count) {
|
if (count) {
|
||||||
template.countElement.textContent = ` (${count})`;
|
template.countElement.textContent = ` (${count})`;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ self.addEventListener('activate', event => {
|
|||||||
//#region --- fetching/caching
|
//#region --- fetching/caching
|
||||||
|
|
||||||
const _cacheName = 'vscode-extension-resources';
|
const _cacheName = 'vscode-extension-resources';
|
||||||
const _resourcePrefix = '/vscode-remote';
|
const _resourcePrefix = '/vscode-remote-resource';
|
||||||
const _pendingFetch = new Map<string, Function>();
|
const _pendingFetch = new Map<string, Function>();
|
||||||
|
|
||||||
self.addEventListener('message', event => {
|
self.addEventListener('message', event => {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
// statement.
|
// statement.
|
||||||
|
|
||||||
// trigger service worker updates
|
// trigger service worker updates
|
||||||
const _tag = '52278406-3ca9-48af-a8fb-8495add5bb4e';
|
const _tag = '23549971-9b8d-41bb-92ae-d7f6a68c9702';
|
||||||
|
|
||||||
// loader world
|
// loader world
|
||||||
const baseUrl = '../../../../../';
|
const baseUrl = '../../../../../';
|
||||||
|
|||||||
@@ -530,7 +530,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNe
|
|||||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find next', category);
|
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find next', category);
|
||||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID, FindNext.LABEL, {
|
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindNext, FindNext.ID, FindNext.LABEL, {
|
||||||
primary: KeyCode.F3,
|
primary: KeyCode.F3,
|
||||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3] }
|
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_G, secondary: [KeyCode.F3, KeyMod.Shift | KeyCode.Enter] }
|
||||||
}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find next');
|
}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find next');
|
||||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID_TERMINAL_FOCUS, FindPrevious.LABEL, {
|
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID_TERMINAL_FOCUS, FindPrevious.LABEL, {
|
||||||
primary: KeyMod.Shift | KeyCode.F3,
|
primary: KeyMod.Shift | KeyCode.F3,
|
||||||
@@ -538,7 +538,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, Fi
|
|||||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find previous', category);
|
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Find previous', category);
|
||||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, {
|
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FindPrevious, FindPrevious.ID, FindPrevious.LABEL, {
|
||||||
primary: KeyMod.Shift | KeyCode.F3,
|
primary: KeyMod.Shift | KeyCode.F3,
|
||||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3] },
|
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G, secondary: [KeyMod.Shift | KeyCode.F3, KeyCode.Enter] },
|
||||||
}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find previous');
|
}, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED), 'Terminal: Find previous');
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class TerminalFindWidget extends SimpleFindWidget {
|
|||||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||||
@ITerminalService private readonly _terminalService: ITerminalService
|
@ITerminalService private readonly _terminalService: ITerminalService
|
||||||
) {
|
) {
|
||||||
super(_contextViewService, _contextKeyService, findState, true, true);
|
super(_contextViewService, _contextKeyService, findState, true);
|
||||||
this._register(findState.onFindReplaceStateChange(() => {
|
this._register(findState.onFindReplaceStateChange(() => {
|
||||||
this.show();
|
this.show();
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
|||||||
|
|
||||||
export class TerminalService extends CommonTerminalService implements ITerminalService {
|
export class TerminalService extends CommonTerminalService implements ITerminalService {
|
||||||
private _configHelper: IBrowserTerminalConfigHelper;
|
private _configHelper: IBrowserTerminalConfigHelper;
|
||||||
|
private _terminalContainer: HTMLElement | undefined;
|
||||||
|
|
||||||
public get configHelper(): ITerminalConfigHelper { return this._configHelper; }
|
public get configHelper(): ITerminalConfigHelper { return this._configHelper; }
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ export abstract class TerminalService implements ITerminalService {
|
|||||||
protected _isShuttingDown: boolean;
|
protected _isShuttingDown: boolean;
|
||||||
protected _terminalFocusContextKey: IContextKey<boolean>;
|
protected _terminalFocusContextKey: IContextKey<boolean>;
|
||||||
protected _findWidgetVisible: IContextKey<boolean>;
|
protected _findWidgetVisible: IContextKey<boolean>;
|
||||||
protected _terminalContainer: HTMLElement | undefined;
|
|
||||||
protected _terminalTabs: ITerminalTab[] = [];
|
protected _terminalTabs: ITerminalTab[] = [];
|
||||||
protected _backgroundedTerminalInstances: ITerminalInstance[] = [];
|
protected _backgroundedTerminalInstances: ITerminalInstance[] = [];
|
||||||
protected get _terminalInstances(): ITerminalInstance[] {
|
protected get _terminalInstances(): ITerminalInstance[] {
|
||||||
|
|||||||
@@ -14,17 +14,24 @@ import { Action } from 'vs/base/common/actions';
|
|||||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||||
|
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||||
|
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||||
|
import { IProductService } from 'vs/platform/product/common/product';
|
||||||
|
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||||
|
import { equalsIgnoreCase } from 'vs/base/common/strings';
|
||||||
|
import { Schemas } from 'vs/base/common/network';
|
||||||
|
import Severity from 'vs/base/common/severity';
|
||||||
|
|
||||||
export class OpenUrlAction extends Action {
|
export class OpenUrlAction extends Action {
|
||||||
|
|
||||||
static readonly ID = 'workbench.action.url.openUrl';
|
static readonly ID = 'workbench.action.url.openUrl';
|
||||||
static readonly LABEL = localize('openUrl', "Open URL");
|
static readonly LABEL = localize('openUrl', 'Open URL');
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
id: string,
|
id: string,
|
||||||
label: string,
|
label: string,
|
||||||
@IURLService private readonly urlService: IURLService,
|
@IURLService private readonly urlService: IURLService,
|
||||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
@IQuickInputService private readonly quickInputService: IQuickInputService
|
||||||
) {
|
) {
|
||||||
super(id, label);
|
super(id, label);
|
||||||
}
|
}
|
||||||
@@ -45,7 +52,7 @@ Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions).registe
|
|||||||
|
|
||||||
const VSCODE_DOMAIN = 'https://code.visualstudio.com';
|
const VSCODE_DOMAIN = 'https://code.visualstudio.com';
|
||||||
|
|
||||||
const configureTrustedDomainsHandler = (
|
const configureTrustedDomainsHandler = async (
|
||||||
quickInputService: IQuickInputService,
|
quickInputService: IQuickInputService,
|
||||||
storageService: IStorageService,
|
storageService: IStorageService,
|
||||||
domainToConfigure?: string
|
domainToConfigure?: string
|
||||||
@@ -66,7 +73,7 @@ const configureTrustedDomainsHandler = (
|
|||||||
type: 'item',
|
type: 'item',
|
||||||
label: d,
|
label: d,
|
||||||
id: d,
|
id: d,
|
||||||
picked: true,
|
picked: true
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -91,23 +98,24 @@ const configureTrustedDomainsHandler = (
|
|||||||
specialQuickPickItems.push(<IQuickPickItem>domainToConfigureItem);
|
specialQuickPickItems.push(<IQuickPickItem>domainToConfigureItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
const quickPickItems: (IQuickPickItem | IQuickPickSeparator)[] = domainQuickPickItems.length === 0
|
const quickPickItems: (IQuickPickItem | IQuickPickSeparator)[] =
|
||||||
? specialQuickPickItems
|
domainQuickPickItems.length === 0
|
||||||
: [...specialQuickPickItems, { type: 'separator' }, ...domainQuickPickItems];
|
? specialQuickPickItems
|
||||||
|
: [...specialQuickPickItems, { type: 'separator' }, ...domainQuickPickItems];
|
||||||
|
|
||||||
return quickInputService.pick(quickPickItems, {
|
const pickedResult = await quickInputService.pick(quickPickItems, {
|
||||||
canPickMany: true,
|
canPickMany: true,
|
||||||
activeItem: domainToConfigureItem
|
activeItem: domainToConfigureItem
|
||||||
}).then(result => {
|
|
||||||
if (result) {
|
|
||||||
const pickedDomains = result.map(r => r.id);
|
|
||||||
storageService.store('http.trustedDomains', JSON.stringify(pickedDomains), StorageScope.GLOBAL);
|
|
||||||
|
|
||||||
return pickedDomains;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (pickedResult) {
|
||||||
|
const pickedDomains: string[] = pickedResult.map(r => r.id!);
|
||||||
|
storageService.store('http.trustedDomains', JSON.stringify(pickedDomains), StorageScope.GLOBAL);
|
||||||
|
|
||||||
|
return pickedDomains;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
};
|
};
|
||||||
|
|
||||||
const configureTrustedDomainCommand = {
|
const configureTrustedDomainCommand = {
|
||||||
@@ -131,3 +139,93 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
|
|||||||
title: configureTrustedDomainCommand.description.description
|
title: configureTrustedDomainCommand.description.description
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
class OpenerValidatorContributions implements IWorkbenchContribution {
|
||||||
|
constructor(
|
||||||
|
@IOpenerService private readonly _openerService: IOpenerService,
|
||||||
|
@IStorageService private readonly _storageService: IStorageService,
|
||||||
|
@IDialogService private readonly _dialogService: IDialogService,
|
||||||
|
@IProductService private readonly _productService: IProductService,
|
||||||
|
@IQuickInputService private readonly _quickInputService: IQuickInputService
|
||||||
|
) {
|
||||||
|
this._openerService.registerValidator({ shouldOpen: r => this.validateLink(r) });
|
||||||
|
}
|
||||||
|
|
||||||
|
async validateLink(resource: URI): Promise<boolean> {
|
||||||
|
const { scheme, authority } = resource;
|
||||||
|
|
||||||
|
if (!equalsIgnoreCase(scheme, Schemas.http) && !equalsIgnoreCase(scheme, Schemas.https)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let trustedDomains: string[] = [VSCODE_DOMAIN];
|
||||||
|
try {
|
||||||
|
const trustedDomainsSrc = this._storageService.get('http.trustedDomains', StorageScope.GLOBAL);
|
||||||
|
if (trustedDomainsSrc) {
|
||||||
|
trustedDomains = JSON.parse(trustedDomainsSrc);
|
||||||
|
}
|
||||||
|
} catch (err) { }
|
||||||
|
|
||||||
|
const domainToOpen = `${scheme}://${authority}`;
|
||||||
|
|
||||||
|
if (isDomainTrusted(domainToOpen, trustedDomains)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
const choice = await this._dialogService.show(
|
||||||
|
Severity.Info,
|
||||||
|
localize(
|
||||||
|
'openExternalLinkAt',
|
||||||
|
'Do you want {0} to open the external website?\n{1}',
|
||||||
|
this._productService.nameShort,
|
||||||
|
resource.toString(true)
|
||||||
|
),
|
||||||
|
[
|
||||||
|
localize('openLink', 'Open Link'),
|
||||||
|
localize('cancel', 'Cancel'),
|
||||||
|
localize('configureTrustedDomains', 'Configure Trusted Domains')
|
||||||
|
],
|
||||||
|
{
|
||||||
|
cancelId: 1
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Open Link
|
||||||
|
if (choice === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Configure Trusted Domains
|
||||||
|
else if (choice === 2) {
|
||||||
|
const pickedDomains = await configureTrustedDomainsHandler(this._quickInputService, this._storageService, domainToOpen);
|
||||||
|
if (pickedDomains.indexOf(domainToOpen) !== -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(
|
||||||
|
OpenerValidatorContributions,
|
||||||
|
LifecyclePhase.Restored
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a domain like https://www.microsoft.com matches
|
||||||
|
* the list of trusted domains.
|
||||||
|
*/
|
||||||
|
function isDomainTrusted(domain: string, trustedDomains: string[]) {
|
||||||
|
for (let i = 0; i < trustedDomains.length; i++) {
|
||||||
|
if (trustedDomains[i] === '*') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trustedDomains[i] === domain) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ export class DynamicWebviewEditorOverlay extends Disposable implements WebviewEd
|
|||||||
reload(): void { this.withWebview(webview => webview.reload()); }
|
reload(): void { this.withWebview(webview => webview.reload()); }
|
||||||
showFind(): void { this.withWebview(webview => webview.showFind()); }
|
showFind(): void { this.withWebview(webview => webview.showFind()); }
|
||||||
hideFind(): void { this.withWebview(webview => webview.hideFind()); }
|
hideFind(): void { this.withWebview(webview => webview.hideFind()); }
|
||||||
|
runFindAction(previous: boolean): void { this.withWebview(webview => webview.runFindAction(previous)); }
|
||||||
|
|
||||||
public getInnerWebview() {
|
public getInnerWebview() {
|
||||||
return this._webview.value;
|
return this._webview.value;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } fro
|
|||||||
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
|
import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
|
||||||
import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
|
import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
|
||||||
import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory';
|
import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory';
|
||||||
import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, webviewDeveloperCategory } from 'vs/workbench/contrib/webview/browser/webview';
|
import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, webviewDeveloperCategory, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/webview/browser/webview';
|
||||||
import { HideWebViewEditorFindCommand, ReloadWebviewAction, ShowWebViewEditorFindWidgetCommand } from '../browser/webviewCommands';
|
import { HideWebViewEditorFindCommand, ReloadWebviewAction, ShowWebViewEditorFindWidgetCommand, WebViewEditorFindNextCommand, WebViewEditorFindPreviousCommand } from '../browser/webviewCommands';
|
||||||
import { WebviewEditor } from '../browser/webviewEditor';
|
import { WebviewEditor } from '../browser/webviewEditor';
|
||||||
import { WebviewEditorInput } from '../browser/webviewEditorInput';
|
import { WebviewEditorInput } from '../browser/webviewEditorInput';
|
||||||
import { IWebviewEditorService, WebviewEditorService } from '../browser/webviewEditorService';
|
import { IWebviewEditorService, WebviewEditorService } from '../browser/webviewEditorService';
|
||||||
@@ -58,6 +58,28 @@ function registerWebViewCommands(editorId: string): void {
|
|||||||
weight: KeybindingWeight.EditorContrib
|
weight: KeybindingWeight.EditorContrib
|
||||||
}
|
}
|
||||||
})).register();
|
})).register();
|
||||||
|
|
||||||
|
(new WebViewEditorFindNextCommand({
|
||||||
|
id: WebViewEditorFindNextCommand.ID,
|
||||||
|
precondition: ContextKeyExpr.and(
|
||||||
|
contextKeyExpr,
|
||||||
|
KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED),
|
||||||
|
kbOpts: {
|
||||||
|
primary: KeyCode.Enter,
|
||||||
|
weight: KeybindingWeight.EditorContrib
|
||||||
|
}
|
||||||
|
})).register();
|
||||||
|
|
||||||
|
(new WebViewEditorFindPreviousCommand({
|
||||||
|
id: WebViewEditorFindPreviousCommand.ID,
|
||||||
|
precondition: ContextKeyExpr.and(
|
||||||
|
contextKeyExpr,
|
||||||
|
KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED),
|
||||||
|
kbOpts: {
|
||||||
|
primary: KeyMod.Shift | KeyCode.Enter,
|
||||||
|
weight: KeybindingWeight.EditorContrib
|
||||||
|
}
|
||||||
|
})).register();
|
||||||
}
|
}
|
||||||
|
|
||||||
registerWebViewCommands(WebviewEditor.ID);
|
registerWebViewCommands(WebviewEditor.ID);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
|||||||
* Set when the find widget in a webview is visible.
|
* Set when the find widget in a webview is visible.
|
||||||
*/
|
*/
|
||||||
export const KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE = new RawContextKey<boolean>('webviewFindWidgetVisible', false);
|
export const KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE = new RawContextKey<boolean>('webviewFindWidgetVisible', false);
|
||||||
|
export const KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED = new RawContextKey<boolean>('webviewFindWidgetFocused', false);
|
||||||
|
|
||||||
export const IWebviewService = createDecorator<IWebviewService>('webviewService');
|
export const IWebviewService = createDecorator<IWebviewService>('webviewService');
|
||||||
|
|
||||||
@@ -83,6 +84,7 @@ export interface Webview extends IDisposable {
|
|||||||
|
|
||||||
showFind(): void;
|
showFind(): void;
|
||||||
hideFind(): void;
|
hideFind(): void;
|
||||||
|
runFindAction(previous: boolean): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebviewElement extends Webview {
|
export interface WebviewElement extends Webview {
|
||||||
|
|||||||
@@ -32,6 +32,27 @@ export class HideWebViewEditorFindCommand extends Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class WebViewEditorFindNextCommand extends Command {
|
||||||
|
public static readonly ID = 'editor.action.webvieweditor.findNext';
|
||||||
|
|
||||||
|
public runCommand(accessor: ServicesAccessor, args: any): void {
|
||||||
|
const webViewEditor = getActiveWebviewEditor(accessor);
|
||||||
|
if (webViewEditor) {
|
||||||
|
webViewEditor.find(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WebViewEditorFindPreviousCommand extends Command {
|
||||||
|
public static readonly ID = 'editor.action.webvieweditor.findPrevious';
|
||||||
|
|
||||||
|
public runCommand(accessor: ServicesAccessor, args: any): void {
|
||||||
|
const webViewEditor = getActiveWebviewEditor(accessor);
|
||||||
|
if (webViewEditor) {
|
||||||
|
webViewEditor.find(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
export class ReloadWebviewAction extends Action {
|
export class ReloadWebviewAction extends Action {
|
||||||
static readonly ID = 'workbench.action.webview.reloadWebviewAction';
|
static readonly ID = 'workbench.action.webview.reloadWebviewAction';
|
||||||
static readonly LABEL = nls.localize('refreshWebviewLabel', "Reload Webviews");
|
static readonly LABEL = nls.localize('refreshWebviewLabel', "Reload Webviews");
|
||||||
@@ -62,4 +83,4 @@ function getActiveWebviewEditor(accessor: ServicesAccessor): WebviewEditor | nul
|
|||||||
const editorService = accessor.get(IEditorService);
|
const editorService = accessor.get(IEditorService);
|
||||||
const activeControl = editorService.activeControl as WebviewEditor;
|
const activeControl = editorService.activeControl as WebviewEditor;
|
||||||
return activeControl.isWebviewEditor ? activeControl : null;
|
return activeControl.isWebviewEditor ? activeControl : null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ export class WebviewEditor extends BaseEditor {
|
|||||||
|
|
||||||
private readonly _scopedContextKeyService = this._register(new MutableDisposable<IContextKeyService>());
|
private readonly _scopedContextKeyService = this._register(new MutableDisposable<IContextKeyService>());
|
||||||
private _findWidgetVisible: IContextKey<boolean>;
|
private _findWidgetVisible: IContextKey<boolean>;
|
||||||
|
|
||||||
private _editorFrame?: HTMLElement;
|
private _editorFrame?: HTMLElement;
|
||||||
private _content?: HTMLElement;
|
private _content?: HTMLElement;
|
||||||
|
|
||||||
@@ -79,6 +78,12 @@ export class WebviewEditor extends BaseEditor {
|
|||||||
this.withWebview(webview => webview.hideFind());
|
this.withWebview(webview => webview.hideFind());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public find(previous: boolean) {
|
||||||
|
this.withWebview(webview => {
|
||||||
|
webview.runFindAction(previous);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public reload() {
|
public reload() {
|
||||||
this.withWebview(webview => webview.reload());
|
this.withWebview(webview => webview.reload());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -268,6 +268,10 @@ export class IFrameWebview extends Disposable implements Webview {
|
|||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runFindAction(previous: boolean): void {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
public set state(state: string | undefined) {
|
public set state(state: string | undefined) {
|
||||||
this.content = {
|
this.content = {
|
||||||
html: this.content.html,
|
html: this.content.html,
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { SimpleFindWidget } from 'vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget';
|
import { SimpleFindWidget } from 'vs/workbench/contrib/codeEditor/browser/find/simpleFindWidget';
|
||||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||||
|
import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED } from 'vs/workbench/contrib/webview/browser/webview';
|
||||||
|
|
||||||
export interface WebviewFindDelegate {
|
export interface WebviewFindDelegate {
|
||||||
find(value: string, previous: boolean): void;
|
find(value: string, previous: boolean): void;
|
||||||
@@ -15,6 +16,7 @@ export interface WebviewFindDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class WebviewFindWidget extends SimpleFindWidget {
|
export class WebviewFindWidget extends SimpleFindWidget {
|
||||||
|
protected _findWidgetFocused: IContextKey<boolean>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _delegate: WebviewFindDelegate,
|
private readonly _delegate: WebviewFindDelegate,
|
||||||
@@ -22,6 +24,7 @@ export class WebviewFindWidget extends SimpleFindWidget {
|
|||||||
@IContextKeyService contextKeyService: IContextKeyService
|
@IContextKeyService contextKeyService: IContextKeyService
|
||||||
) {
|
) {
|
||||||
super(contextViewService, contextKeyService);
|
super(contextViewService, contextKeyService);
|
||||||
|
this._findWidgetFocused = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_FOCUSED.bindTo(contextKeyService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public find(previous: boolean) {
|
public find(previous: boolean) {
|
||||||
@@ -47,9 +50,13 @@ export class WebviewFindWidget extends SimpleFindWidget {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected onFocusTrackerFocus() { }
|
protected onFocusTrackerFocus() {
|
||||||
|
this._findWidgetFocused.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
protected onFocusTrackerBlur() { }
|
protected onFocusTrackerBlur() {
|
||||||
|
this._findWidgetFocused.reset();
|
||||||
|
}
|
||||||
|
|
||||||
protected onFindInputFocusTrackerFocus() { }
|
protected onFindInputFocusTrackerFocus() { }
|
||||||
|
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case 'did-click-link':
|
case 'did-click-link':
|
||||||
let [uri] = event.args;
|
const [uri] = event.args;
|
||||||
this._onDidClickLink.fire(URI.parse(uri));
|
this._onDidClickLink.fire(URI.parse(uri));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -334,12 +334,10 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview {
|
|||||||
clientY: rawEvent.clientY + bounds.top,
|
clientY: rawEvent.clientY + bounds.top,
|
||||||
}));
|
}));
|
||||||
return;
|
return;
|
||||||
}
|
} catch {
|
||||||
catch (TypeError) {
|
|
||||||
// CustomEvent was treated as MouseEvent so don't do anything - https://github.com/microsoft/vscode/issues/78915
|
// CustomEvent was treated as MouseEvent so don't do anything - https://github.com/microsoft/vscode/issues/78915
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'did-set-content':
|
case 'did-set-content':
|
||||||
@@ -640,6 +638,12 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public runFindAction(previous: boolean) {
|
||||||
|
if (this._webviewFindWidget) {
|
||||||
|
this._webviewFindWidget.find(previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public reload() {
|
public reload() {
|
||||||
this.doUpdateContent();
|
this.doUpdateContent();
|
||||||
}
|
}
|
||||||
|
|||||||
-16
@@ -5,7 +5,6 @@ The core editor in VS Code is packed with features. This page highlights a numb
|
|||||||
* [IntelliSense](#intellisense) - get code assistance and parameter suggestions for your code and external modules.
|
* [IntelliSense](#intellisense) - get code assistance and parameter suggestions for your code and external modules.
|
||||||
* [Line Actions](#line-actions) - quickly move lines around to re-order your code.
|
* [Line Actions](#line-actions) - quickly move lines around to re-order your code.
|
||||||
* [Rename Refactoring](#rename-refactoring) - quickly rename symbols across your code base.
|
* [Rename Refactoring](#rename-refactoring) - quickly rename symbols across your code base.
|
||||||
* [Refactoring via Extraction](#refactoring-via-extraction) - quickly extract common code into a separate function or constant.
|
|
||||||
* [Formatting](#formatting) - keep your code looking great with inbuilt document & selection formatting.
|
* [Formatting](#formatting) - keep your code looking great with inbuilt document & selection formatting.
|
||||||
* [Code Folding](#code-folding) - focus on the most relevant parts of your code by folding other areas.
|
* [Code Folding](#code-folding) - focus on the most relevant parts of your code by folding other areas.
|
||||||
* [Errors and Warnings](#errors-and-warnings) - see errors and warning as you type.
|
* [Errors and Warnings](#errors-and-warnings) - see errors and warning as you type.
|
||||||
@@ -90,21 +89,6 @@ function Book(title, author) {
|
|||||||
> **JSDoc Tip:** VS Code's IntelliSense uses JSDoc comments to provide richer suggestions. The types and documentation from JSDoc comments show up when you hover over a reference to `Book` or in IntelliSense when you create a new instance of `Book`.
|
> **JSDoc Tip:** VS Code's IntelliSense uses JSDoc comments to provide richer suggestions. The types and documentation from JSDoc comments show up when you hover over a reference to `Book` or in IntelliSense when you create a new instance of `Book`.
|
||||||
|
|
||||||
|
|
||||||
### Refactoring via Extraction
|
|
||||||
Sometimes you want to refactor already written code into a separate function or constant to reuse it later. Select the lines you want to refactor out and press kb(editor.action.quickFix) or click the little light bulb and choose one of the respective `Extract to...` options. Try it by selecting the code inside the `if`-clause on line 3 or any other common code you want to refactor out.
|
|
||||||
|
|
||||||
```js
|
|
||||||
function findFirstEvenNumber(arr) {
|
|
||||||
for (const el of arr) {
|
|
||||||
if (typeof el === 'number' && el % 2 === 0) {
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Formatting
|
### Formatting
|
||||||
Keeping your code looking great is hard without a good formatter. Luckily it's easy to format content, either for the entire document with kb(editor.action.formatDocument) or for the current selection with kb(editor.action.formatSelection). Both of these options are also available through the right-click context menu.
|
Keeping your code looking great is hard without a good formatter. Luckily it's easy to format content, either for the entire document with kb(editor.action.formatDocument) or for the current selection with kb(editor.action.formatSelection). Both of these options are also available through the right-click context menu.
|
||||||
|
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ export class EditorService extends Disposable implements EditorServiceImpl {
|
|||||||
// Respect option to reveal an editor if it is already visible in any group
|
// Respect option to reveal an editor if it is already visible in any group
|
||||||
if (options && options.revealIfVisible) {
|
if (options && options.revealIfVisible) {
|
||||||
for (const group of groupsByLastActive) {
|
for (const group of groupsByLastActive) {
|
||||||
if (input.matches(group.activeEditor)) {
|
if (group.isActive(input)) {
|
||||||
targetGroup = group;
|
targetGroup = group;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -283,11 +283,16 @@ export class EditorService extends Disposable implements EditorServiceImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Respect option to reveal an editor if it is open (not necessarily visible)
|
// Respect option to reveal an editor if it is open (not necessarily visible)
|
||||||
if ((options && options.revealIfOpened) || this.configurationService.getValue<boolean>('workbench.editor.revealIfOpen')) {
|
if (!targetGroup) {
|
||||||
for (const group of groupsByLastActive) {
|
if ((options && options.revealIfOpened) || this.configurationService.getValue<boolean>('workbench.editor.revealIfOpen')) {
|
||||||
if (group.isOpened(input)) {
|
for (const group of groupsByLastActive) {
|
||||||
targetGroup = group;
|
if (group.isOpened(input) && group.isActive(input)) {
|
||||||
break;
|
targetGroup = group;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (group.isOpened(input) && !targetGroup) {
|
||||||
|
targetGroup = group;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,11 +62,9 @@ export class BrowserWindowConfiguration implements IWindowConfiguration {
|
|||||||
termProgram?: string;
|
termProgram?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBrowserWindowConfiguration {
|
interface IBrowserWorkbenchEnvironemntConstructionOptions extends IWorkbenchConstructionOptions {
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
remoteAuthority?: string;
|
logsPath: URI;
|
||||||
webviewEndpoint?: string;
|
|
||||||
connectionToken?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironmentService {
|
export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironmentService {
|
||||||
@@ -75,8 +73,10 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
|
|||||||
|
|
||||||
readonly configuration: IWindowConfiguration = new BrowserWindowConfiguration();
|
readonly configuration: IWindowConfiguration = new BrowserWindowConfiguration();
|
||||||
|
|
||||||
constructor(workspaceId: string, public readonly options: IWorkbenchConstructionOptions) {
|
constructor(readonly options: IBrowserWorkbenchEnvironemntConstructionOptions) {
|
||||||
this.args = { _: [] };
|
this.args = { _: [] };
|
||||||
|
this.logsPath = options.logsPath.path;
|
||||||
|
this.logFile = joinPath(options.logsPath, 'window.log');
|
||||||
this.appRoot = '/web/';
|
this.appRoot = '/web/';
|
||||||
this.appNameLong = 'Visual Studio Code - Web';
|
this.appNameLong = 'Visual Studio Code - Web';
|
||||||
|
|
||||||
@@ -88,10 +88,8 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
|
|||||||
this.keyboardLayoutResource = joinPath(this.userRoamingDataHome, 'keyboardLayout.json');
|
this.keyboardLayoutResource = joinPath(this.userRoamingDataHome, 'keyboardLayout.json');
|
||||||
this.localeResource = joinPath(this.userRoamingDataHome, 'locale.json');
|
this.localeResource = joinPath(this.userRoamingDataHome, 'locale.json');
|
||||||
this.backupHome = joinPath(this.userRoamingDataHome, BACKUPS);
|
this.backupHome = joinPath(this.userRoamingDataHome, BACKUPS);
|
||||||
this.configuration.backupWorkspaceResource = joinPath(this.backupHome, workspaceId);
|
this.configuration.backupWorkspaceResource = joinPath(this.backupHome, options.workspaceId);
|
||||||
this.configuration.connectionToken = options.connectionToken || this.getConnectionTokenFromLocation();
|
this.configuration.connectionToken = options.connectionToken || getCookieValue('vscode-tkn');
|
||||||
|
|
||||||
this.logsPath = '/web/logs';
|
|
||||||
|
|
||||||
this.debugExtensionHost = {
|
this.debugExtensionHost = {
|
||||||
port: null,
|
port: null,
|
||||||
@@ -183,6 +181,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
|
|||||||
driverVerbose: boolean;
|
driverVerbose: boolean;
|
||||||
webviewEndpoint?: string;
|
webviewEndpoint?: string;
|
||||||
galleryMachineIdResource?: URI;
|
galleryMachineIdResource?: URI;
|
||||||
|
readonly logFile: URI;
|
||||||
|
|
||||||
get webviewResourceRoot(): string {
|
get webviewResourceRoot(): string {
|
||||||
return this.webviewEndpoint ? this.webviewEndpoint + '/vscode-resource{{resource}}' : 'vscode-resource:{{resource}}';
|
return this.webviewEndpoint ? this.webviewEndpoint + '/vscode-resource{{resource}}' : 'vscode-resource:{{resource}}';
|
||||||
@@ -191,21 +190,12 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
|
|||||||
get webviewCspSource(): string {
|
get webviewCspSource(): string {
|
||||||
return this.webviewEndpoint ? this.webviewEndpoint : 'vscode-resource:';
|
return this.webviewEndpoint ? this.webviewEndpoint : 'vscode-resource:';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private getConnectionTokenFromLocation(): string | undefined {
|
|
||||||
// TODO: Check with @alexd where the token will be: search or hash?
|
/**
|
||||||
let connectionToken: string | undefined = undefined;
|
* See https://stackoverflow.com/a/25490531
|
||||||
if (document.location.search) {
|
*/
|
||||||
connectionToken = this.getConnectionToken(document.location.search);
|
function getCookieValue(name: string): string | undefined {
|
||||||
}
|
const m = document.cookie.match('(^|[^;]+)\\s*' + name + '\\s*=\\s*([^;]+)');
|
||||||
if (!connectionToken && document.location.hash) {
|
return m ? m.pop() : undefined;
|
||||||
connectionToken = this.getConnectionToken(document.location.hash);
|
|
||||||
}
|
|
||||||
return connectionToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getConnectionToken(str: string): string | undefined {
|
|
||||||
const m = str.match(/[#&?]tkn=([^&]+)/);
|
|
||||||
return m ? m[1] : undefined;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/co
|
|||||||
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
|
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
|
||||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||||
import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api';
|
import { IWorkbenchConstructionOptions } from 'vs/workbench/workbench.web.api';
|
||||||
|
import { URI } from 'vs/base/common/uri';
|
||||||
|
|
||||||
export const IWorkbenchEnvironmentService = createDecorator<IWorkbenchEnvironmentService>('environmentService');
|
export const IWorkbenchEnvironmentService = createDecorator<IWorkbenchEnvironmentService>('environmentService');
|
||||||
|
|
||||||
@@ -16,5 +17,7 @@ export interface IWorkbenchEnvironmentService extends IEnvironmentService {
|
|||||||
|
|
||||||
readonly configuration: IWindowConfiguration;
|
readonly configuration: IWindowConfiguration;
|
||||||
|
|
||||||
|
readonly logFile: URI;
|
||||||
|
|
||||||
readonly options?: IWorkbenchConstructionOptions;
|
readonly options?: IWorkbenchConstructionOptions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { URI } from 'vs/base/common/uri';
|
|||||||
import { Schemas } from 'vs/base/common/network';
|
import { Schemas } from 'vs/base/common/network';
|
||||||
import { toBackupWorkspaceResource } from 'vs/workbench/services/backup/common/backup';
|
import { toBackupWorkspaceResource } from 'vs/workbench/services/backup/common/backup';
|
||||||
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
import { join } from 'vs/base/common/path';
|
||||||
|
|
||||||
export class WorkbenchEnvironmentService extends EnvironmentService implements IWorkbenchEnvironmentService {
|
export class WorkbenchEnvironmentService extends EnvironmentService implements IWorkbenchEnvironmentService {
|
||||||
|
|
||||||
@@ -31,4 +32,7 @@ export class WorkbenchEnvironmentService extends EnvironmentService implements I
|
|||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
get userRoamingDataHome(): URI { return this.appSettingsHome.with({ scheme: Schemas.userData }); }
|
get userRoamingDataHome(): URI { return this.appSettingsHome.with({ scheme: Schemas.userData }); }
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
get logFile(): URI { return URI.file(join(this.logsPath, `renderer${this.configuration.windowId}.log`)); }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
|
|||||||
const result: ExtensionHostProcessManager[] = [];
|
const result: ExtensionHostProcessManager[] = [];
|
||||||
|
|
||||||
const webExtensions = this.getExtensions().then(extensions => extensions.filter(ext => isWebExtension(ext, this._configService)));
|
const webExtensions = this.getExtensions().then(extensions => extensions.filter(ext => isWebExtension(ext, this._configService)));
|
||||||
const webHostProcessWorker = this._instantiationService.createInstance(WebWorkerExtensionHostStarter, true, webExtensions, URI.parse('empty:value')); //todo@joh
|
const webHostProcessWorker = this._instantiationService.createInstance(WebWorkerExtensionHostStarter, true, webExtensions, URI.file(this._environmentService.logsPath).with({ scheme: this._environmentService.logFile.scheme }));
|
||||||
const webHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, webHostProcessWorker, null, initialActivationEvents);
|
const webHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, webHostProcessWorker, null, initialActivationEvents);
|
||||||
result.push(webHostProcessManager);
|
result.push(webHostProcessManager);
|
||||||
|
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ export class BrowserKeyboardMapperFactoryBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setActiveKeyMapping(keymap: IKeyboardMapping | null) {
|
setActiveKeyMapping(keymap: IKeyboardMapping | null) {
|
||||||
|
let keymapUpdated = false;
|
||||||
let matchedKeyboardLayout = this.getMatchedKeymapInfo(keymap);
|
let matchedKeyboardLayout = this.getMatchedKeymapInfo(keymap);
|
||||||
if (matchedKeyboardLayout) {
|
if (matchedKeyboardLayout) {
|
||||||
// let score = matchedKeyboardLayout.score;
|
// let score = matchedKeyboardLayout.score;
|
||||||
@@ -209,18 +210,21 @@ export class BrowserKeyboardMapperFactoryBase {
|
|||||||
|
|
||||||
if (!this._activeKeymapInfo) {
|
if (!this._activeKeymapInfo) {
|
||||||
this._activeKeymapInfo = matchedKeyboardLayout.result;
|
this._activeKeymapInfo = matchedKeyboardLayout.result;
|
||||||
|
keymapUpdated = true;
|
||||||
} else if (keymap) {
|
} else if (keymap) {
|
||||||
if (matchedKeyboardLayout.result.getScore(keymap) > this._activeKeymapInfo.getScore(keymap)) {
|
if (matchedKeyboardLayout.result.getScore(keymap) > this._activeKeymapInfo.getScore(keymap)) {
|
||||||
this._activeKeymapInfo = matchedKeyboardLayout.result;
|
this._activeKeymapInfo = matchedKeyboardLayout.result;
|
||||||
|
keymapUpdated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._activeKeymapInfo) {
|
if (!this._activeKeymapInfo) {
|
||||||
this._activeKeymapInfo = this.getUSStandardLayout();
|
this._activeKeymapInfo = this.getUSStandardLayout();
|
||||||
|
keymapUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._activeKeymapInfo) {
|
if (!this._activeKeymapInfo || !keymapUpdated) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user