Merge remote-tracking branch 'origin/master' into rebornix/notebook

This commit is contained in:
rebornix
2020-03-16 14:08:26 -07:00
280 changed files with 5858 additions and 3031 deletions
@@ -8,3 +8,4 @@ about: Suggest an idea for this project
<!-- Please search existing issues to avoid creating duplicates. -->
<!-- Describe the feature you'd like. -->
<!-- Please include the latest version of VS Code you've confirmed to not have this feature -->
+167
View File
@@ -0,0 +1,167 @@
[
{
"type": "comment",
"name": "question",
"allowUsers": [
"cleidigh",
"usernamehw",
"gjsjohnmurray",
"IllusionMH"
],
"action": "updateLabels",
"addLabel": "*question"
},
{
"type": "label",
"name": "*question",
"action": "close",
"comment": "Please ask your question on [StackOverflow](https://aka.ms/vscodestackoverflow). We have a great community over [there](https://aka.ms/vscodestackoverflow). They have already answered thousands of questions and are happy to answer yours as well. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!"
},
{
"type": "label",
"name": "*dev-question",
"action": "close",
"comment": "We have a great developer community [over on slack](https://aka.ms/vscode-dev-community) where extension authors help each other. This is a great place for you to ask questions and find support.\n\nHappy Coding!"
},
{
"type": "label",
"name": "*extension-candidate",
"action": "close",
"comment": "We try to keep VS Code lean and we think the functionality you're asking for is great for a VS Code extension. Maybe you can already find one that suits you in the [VS Code Marketplace](https://aka.ms/vscodemarketplace). Just in case, in a few simple steps you can get started [writing your own extension](https://aka.ms/vscodewritingextensions). See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!"
},
{
"type": "label",
"name": "*not-reproducible",
"action": "close",
"comment": "We closed this issue because we are unable to reproduce the problem with the steps you describe. Chances are we've already fixed your problem in a recent version of VS Code. If not, please ask us to reopen the issue and provide us with more detail. Our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines might help you with that.\n\nHappy Coding!"
},
{
"type": "label",
"name": "*out-of-scope",
"action": "close",
"comment": "We closed this issue because we don't plan to address it in the foreseeable future. You can find more detailed information about our decision-making process [here](https://aka.ms/vscode-out-of-scope). If you disagree and feel that this issue is crucial: We are happy to listen and to reconsider.\n\nIf you wonder what we are up to, please see our [roadmap](https://aka.ms/vscoderoadmap) and [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nThanks for your understanding and happy coding!"
},
{
"type": "comment",
"name": "causedByExtension",
"allowUsers": [
"cleidigh",
"usernamehw",
"gjsjohnmurray",
"IllusionMH"
],
"action": "updateLabels",
"addLabel": "*caused-by-extension"
},
{
"type": "label",
"name": "*caused-by-extension",
"action": "close",
"comment": "This issue is caused by an extension, please file it with the repository (or contact) the extension has linked in its overview in VS Code or the [marketplace](https://aka.ms/vscodemarketplace) for VS Code. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!"
},
{
"type": "label",
"name": "*as-designed",
"action": "close",
"comment": "The described behavior is how it is expected to work. If you disagree, please explain what is expected and what is not in more detail. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!"
},
{
"type": "label",
"name": "*english-please",
"action": "close",
"comment": "This issue is being closed because its description is not in English, that makes it hard for us to work on it. Please open a new issue with an English description. You might find [Bing Translator](https://www.bing.com/translator) useful."
},
{
"type": "comment",
"name": "duplicate",
"allowUsers": [
"cleidigh",
"usernamehw",
"gjsjohnmurray",
"IllusionMH"
],
"action": "updateLabels",
"addLabel": "*duplicate"
},
{
"type": "label",
"name": "*duplicate",
"action": "close",
"comment": "Thanks for creating this issue! We figured it's covering the same as another one we already have. Thus, we closed this one as a duplicate. You can search for existing issues [here](https://aka.ms/vscodeissuesearch). See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!"
},
{
"type": "comment",
"name": "confirm",
"allowUsers": [
"cleidigh",
"usernamehw",
"gjsjohnmurray",
"IllusionMH"
],
"action": "updateLabels",
"addLabel": "confirmed",
"removeLabel": "confirmation-pending"
},
{
"type": "comment",
"name": "confirmationPending",
"allowUsers": [
"cleidigh",
"usernamehw",
"gjsjohnmurray",
"IllusionMH"
],
"action": "updateLabels",
"addLabel": "confirmation-pending",
"removeLabel": "confirmed"
},
{
"type": "comment",
"name": "needsMoreInfo",
"allowUsers": [
"cleidigh",
"usernamehw",
"gjsjohnmurray",
"IllusionMH"
],
"action": "updateLabels",
"addLabel": "~needs more info"
},
{
"type": "label",
"name": "~needs version info",
"action": "updateLabels",
"addLabel": "needs more info",
"removeLabel": "~needs version info",
"comment": "Thanks for creating this issue! We figured it's missing some basic information, such as a version number, or in some other way doesn't follow our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines. Please take the time to review these and update the issue.\n\nHappy Coding!"
},
{
"type": "label",
"name": "~needs more info",
"action": "updateLabels",
"addLabel": "needs more info",
"removeLabel": "~needs more info",
"comment": "Thanks for creating this issue! We figured it's missing some basic information or in some other way doesn't follow our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines. Please take the time to review these and update the issue.\n\nHappy Coding!"
},
{
"type": "comment",
"name": "a11ymas",
"allowUsers": [
"AccessibilityTestingTeam-TCS",
"dixitsonali95",
"Mohini78",
"ChitrarupaSharma",
"mspatil110",
"umasarath52",
"v-umnaik"
],
"action": "updateLabels",
"addLabel": "a11ymas"
},
{
"type": "label",
"name": "*off-topic",
"action": "close",
"comment": "Thanks for creating this issue. We think this issue is unactionable or unrelated to the goals of this project. Please follow our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!"
}
]
+13
View File
@@ -1,3 +1,16 @@
# {
# perform: true,
# commands: [
# {
# type: 'comment',
# name: 'findDuplicates',
# allowUsers: ['cleidigh', 'usernamehw', 'gjsjohnmurray', 'IllusionMH'],
# action: 'comment',
# comment: "Potential duplicates:\n${potentialDuplicates}"
# }
# ]
# }
{
perform: true,
commands: [
-5
View File
@@ -1,5 +0,0 @@
{
perform: true,
target_owner: 'chrmarti',
target_repo: 'testissues'
}
+21
View File
@@ -0,0 +1,21 @@
name: Commands
on:
issue_comment:
types: [created]
issues:
types: [labeled]
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions
uses: actions/checkout@v2
with:
repository: 'JacksonKearl/vscode-triage-github-actions'
ref: v2
# - name: Run Commands
# uses: ./commands
# with:
# token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
# config-path: commands
+26
View File
@@ -0,0 +1,26 @@
name: CopyCat
on:
issues:
types: [opened]
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions
uses: actions/checkout@v2
with:
repository: 'JacksonKearl/vscode-triage-github-actions'
ref: v2
# - name: Run CopyCat (JacksonKearl/testissues)
# uses: ./copycat
# with:
# token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
# owner: JacksonKearl
# repo: testissues
# - name: Run CopyCat (chrmarti/testissues)
# uses: ./copycat
# with:
# token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
# owner: chrmarti
# repo: testissues
+20
View File
@@ -0,0 +1,20 @@
name: Needs Version Info
on:
issues:
types: [opened]
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions
uses: actions/checkout@v2
with:
repository: 'JacksonKearl/vscode-triage-github-actions'
ref: v2
# - name: Run Needs Version Info
# uses: ./needs-more-info
# with:
# token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
# matcher: '\b(\d\.\d{2,3}\.\d|insiders?|1\.\d\d\d?)\b'
# label: ~needs version info
+1 -1
View File
@@ -46,7 +46,7 @@
},
{
"name": "ms-vscode.js-debug-nightly",
"version": "2020.3.317",
"version": "2020.3.1117",
"forQualities": [
"insider"
],
+7 -4
View File
@@ -114,7 +114,7 @@ let XLF = /** @class */ (() => {
for (let file in this.files) {
this.appendNewLine(`<file original="${file}" source-language="en" datatype="plaintext"><body>`, 2);
for (let item of this.files[file]) {
this.addStringItem(item);
this.addStringItem(file, item);
}
this.appendNewLine('</body></file>', 2);
}
@@ -154,9 +154,12 @@ let XLF = /** @class */ (() => {
this.files[original].push({ id: realKey, message: message, comment: comment });
}
}
addStringItem(item) {
if (!item.id || !item.message) {
throw new Error(`No item ID or value specified: ${JSON.stringify(item)}`);
addStringItem(file, item) {
if (!item.id || item.message === undefined || item.message === null) {
throw new Error(`No item ID or value specified: ${JSON.stringify(item)}. File: ${file}`);
}
if (item.message.length === 0) {
log(`Item with id ${item.id} in file ${file} has an empty message.`);
}
this.appendNewLine(`<trans-unit id="${item.id}">`, 4);
this.appendNewLine(`<source xml:lang="en">${item.message}</source>`, 6);
+7 -4
View File
@@ -201,7 +201,7 @@ export class XLF {
for (let file in this.files) {
this.appendNewLine(`<file original="${file}" source-language="en" datatype="plaintext"><body>`, 2);
for (let item of this.files[file]) {
this.addStringItem(item);
this.addStringItem(file, item);
}
this.appendNewLine('</body></file>', 2);
}
@@ -243,9 +243,12 @@ export class XLF {
}
}
private addStringItem(item: Item): void {
if (!item.id || !item.message) {
throw new Error(`No item ID or value specified: ${JSON.stringify(item)}`);
private addStringItem(file: string, item: Item): void {
if (!item.id || item.message === undefined || item.message === null) {
throw new Error(`No item ID or value specified: ${JSON.stringify(item)}. File: ${file}`);
}
if (item.message.length === 0) {
log(`Item with id ${item.id} in file ${file} has an empty message.`);
}
this.appendNewLine(`<trans-unit id="${item.id}">`, 4);
+1 -1
View File
@@ -333,7 +333,7 @@ function markNodes(languageService, options) {
}
setColor(node, 2 /* Black */);
black_queue.push(node);
if (options.shakeLevel === 2 /* ClassMembers */ && (ts.isMethodDeclaration(node) || ts.isMethodSignature(node) || ts.isPropertySignature(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node))) {
if (options.shakeLevel === 2 /* ClassMembers */ && (ts.isMethodDeclaration(node) || ts.isMethodSignature(node) || ts.isPropertySignature(node) || ts.isPropertyDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node))) {
const references = languageService.getReferencesAtPosition(node.getSourceFile().fileName, node.name.pos + node.name.getLeadingTriviaWidth());
if (references) {
for (let i = 0, len = references.length; i < len; i++) {
+1 -1
View File
@@ -436,7 +436,7 @@ function markNodes(languageService: ts.LanguageService, options: ITreeShakingOpt
setColor(node, NodeColor.Black);
black_queue.push(node);
if (options.shakeLevel === ShakeLevel.ClassMembers && (ts.isMethodDeclaration(node) || ts.isMethodSignature(node) || ts.isPropertySignature(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node))) {
if (options.shakeLevel === ShakeLevel.ClassMembers && (ts.isMethodDeclaration(node) || ts.isMethodSignature(node) || ts.isPropertySignature(node) || ts.isPropertyDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node))) {
const references = languageService.getReferencesAtPosition(node.getSourceFile().fileName, node.name.pos + node.name.getLeadingTriviaWidth());
if (references) {
for (let i = 0, len = references.length; i < len; i++) {
+2 -2
View File
@@ -40,10 +40,10 @@
"iconv-lite": "0.4.23",
"mime": "^1.3.4",
"minimatch": "3.0.4",
"minimist": "^1.2.0",
"minimist": "^1.2.2",
"request": "^2.85.0",
"terser": "4.3.8",
"typescript": "3.9.0-dev.20200304",
"typescript": "^3.9.0-dev.20200313",
"vsce": "1.48.0",
"vscode-telemetry-extractor": "^1.5.4",
"xml2js": "^0.4.17"
+9 -9
View File
@@ -1780,10 +1780,10 @@ minimatch@3.0.4, minimatch@^3.0.3, minimatch@^3.0.4:
dependencies:
brace-expansion "^1.1.7"
minimist@^1.1.0, minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.2.tgz#b00a00230a1108c48c169e69a291aafda3aacd63"
integrity sha512-rIqbOrKb8GJmx/5bc2M0QchhUouMXSpd1RTclXsB41JdL+VtnojfaJR+h7F9k18/4kHUsBFgk80Uk+q569vjPA==
minimist@~0.0.1:
version "0.0.10"
@@ -2453,16 +2453,16 @@ typed-rest-client@^0.9.0:
tunnel "0.0.4"
underscore "1.8.3"
typescript@3.9.0-dev.20200304:
version "3.9.0-dev.20200304"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200304.tgz#3cc35357eff29dc5604b4fa56d6597e13daf86ed"
integrity sha512-eUip/GgJmjp4qtHiJDxVhE5SDDiPzBUg7KBAFUgb7HgL/tv10JAHej7fnS1i+7xrq1eDtbkJyPaYOVnhL9db7Q==
typescript@^3.0.1:
version "3.5.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
typescript@^3.9.0-dev.20200313:
version "3.9.0-dev.20200313"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200313.tgz#f66aeb2c08268f2b1fc6d1d96e15554c6e7ed29b"
integrity sha512-85/IJPm1nEUbQDxK3aN+svIy4X3kPcAipihB3704NY1HXncJ1daNLJW1OktOacb8tD/URpIGs9nMgbUrKvglGg==
typical@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
@@ -9,7 +9,7 @@
},
"main": "./out/cssServerMain",
"dependencies": {
"vscode-css-languageservice": "^4.1.0",
"vscode-css-languageservice": "^4.1.1",
"vscode-languageserver": "^6.1.1"
},
"devDependencies": {
@@ -689,10 +689,10 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
vscode-css-languageservice@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.1.0.tgz#144c8274e0bf1719fa6f773ca684bd1c7ffd634f"
integrity sha512-iTX3dTp0Y0RFWhIux5jasI8r9swdiWVB1Z3OrZ10iDHxzkETjVPxAQ5BEQU4ag0Awc8TTg1C7sJriHQY2LO14g==
vscode-css-languageservice@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.1.1.tgz#9131dd465e4b20f3ba78ab9734b2c7cdb9237443"
integrity sha512-2r2bYbhscivRu1zqh5kNe8aYpFnfksMYC7wTpKX2HqFsSzSJYXk0sCqPaWsP5ptqz0OFBTXnzx2JlE+Nb5Edgw==
dependencies:
vscode-languageserver-textdocument "^1.0.1"
vscode-languageserver-types "^3.15.1"
+2 -2
View File
@@ -27,8 +27,8 @@ export class PreviewManager implements vscode.CustomEditorProvider {
private readonly zoomStatusBarEntry: ZoomStatusBarEntry,
) { }
public async resolveCustomDocument(_document: vscode.CustomDocument): Promise<vscode.CustomEditorCapabilities> {
return {};
public async resolveCustomDocument(_document: vscode.CustomDocument): Promise<void> {
// noop
}
public async resolveCustomEditor(
@@ -188,6 +188,9 @@ export function activate(context: ExtensionContext) {
// handle content request
client.onRequest(VSCodeContentRequest.type, (uriPath: string) => {
const uri = Uri.parse(uriPath);
if (uri.scheme === 'untitled') {
return Promise.reject(new Error(localize('untitled.schema', 'Unable to load {0}', uri.toString())));
}
if (uri.scheme !== 'http' && uri.scheme !== 'https') {
return workspace.openTextDocument(uri).then(doc => {
schemaDocuments[uri.toString()] = true;
@@ -342,6 +345,9 @@ function getSchemaAssociations(_context: ExtensionContext): ISchemaAssociation[]
fileMatch = [fileMatch];
}
if (Array.isArray(fileMatch) && url) {
if (url[0] === '.' && url[1] === '/') {
url = Uri.file(path.join(extension.extensionPath, url)).toString();
}
fileMatch = fileMatch.map(fm => {
if (fm[0] === '%') {
fm = fm.replace(/%APP_SETTINGS_HOME%/, '/User');
@@ -148,8 +148,8 @@ export class MarkdownPreviewManager extends Disposable implements vscode.Webview
this.registerDynamicPreview(preview);
}
public async resolveCustomDocument(_document: vscode.CustomDocument): Promise<vscode.CustomEditorCapabilities> {
return {};
public async resolveCustomDocument(_document: vscode.CustomDocument): Promise<void> {
// noop
}
public async resolveCustomTextEditor(
@@ -191,9 +191,9 @@ abbrev@1:
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
acorn@^6.2.1:
version "6.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e"
integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==
version "6.4.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
ajv-errors@^1.0.0:
version "1.0.1"
@@ -434,5 +434,6 @@
"terminal.ansiBrightMagenta": "#d778ff",
"terminal.ansiBrightCyan": "#78ffff",
"terminal.ansiBrightWhite": "#ffffff"
}
},
"semanticHighlighting": true
}
@@ -18,5 +18,6 @@
"menu.foreground": "#CCCCCC",
"statusBarItem.remoteForeground": "#FFF",
"statusBarItem.remoteBackground": "#16825D"
}
}
},
"semanticHighlighting": true
}
@@ -337,5 +337,6 @@
"foreground": "#569cd6"
}
}
]
}
],
"semanticHighlighting": true
}
@@ -18,5 +18,6 @@
"settings.numberInputBorder": "#CECECE",
"statusBarItem.remoteForeground": "#FFF",
"statusBarItem.remoteBackground": "#16825D"
}
},
"semanticHighlighting": true
}
@@ -394,5 +394,6 @@
"foreground": "#dc3958"
}
}
]
],
"semanticHighlighting": true
}
@@ -572,5 +572,6 @@
"foreground": "#c7444a"
}
}
]
],
"semanticHighlighting": true
}
@@ -476,5 +476,6 @@
"foreground": "#FD971F"
}
}
]
],
"semanticHighlighting": true
}
@@ -494,5 +494,6 @@
"walkThrough.embeddedEditorBackground": "#00000014",
"editorIndentGuide.background": "#aaaaaa60",
"editorIndentGuide.activeBackground": "#777777b0"
}
},
"semanticHighlighting": true
}
@@ -385,5 +385,6 @@
"foreground": "#ec0d1e"
}
}
]
],
"semanticHighlighting": true
}
@@ -477,5 +477,6 @@
"terminal.ansiBrightMagenta": "#6c71c4",
"terminal.ansiBrightCyan": "#93a1a1",
"terminal.ansiBrightWhite": "#fdf6e3"
}
},
"semanticHighlighting": true
}
@@ -484,5 +484,6 @@
// Interactive Playground
"walkThrough.embeddedEditorBackground": "#00000014"
}
},
"semanticHighlighting": true
}
@@ -255,5 +255,6 @@
"foreground": "#b267e6"
}
}
]
],
"semanticHighlighting": true
}
@@ -19,7 +19,7 @@
"jsonc-parser": "^2.2.1",
"rimraf": "^2.6.3",
"semver": "5.5.1",
"typescript-vscode-sh-plugin": "^0.6.8",
"typescript-vscode-sh-plugin": "^0.6.10",
"vscode-extension-telemetry": "0.1.1",
"vscode-nls": "^4.1.1"
},
@@ -216,7 +216,7 @@ class MyCompletionItem extends vscode.CompletionItem {
case PConst.Kind.function:
case PConst.Kind.localFunction:
return vscode.CompletionItemKind.Function;
case PConst.Kind.memberFunction:
case PConst.Kind.method:
case PConst.Kind.constructSignature:
case PConst.Kind.callSignature:
case PConst.Kind.indexSignature:
@@ -272,7 +272,7 @@ class MyCompletionItem extends vscode.CompletionItem {
case PConst.Kind.memberVariable:
case PConst.Kind.class:
case PConst.Kind.function:
case PConst.Kind.memberFunction:
case PConst.Kind.method:
case PConst.Kind.keyword:
case PConst.Kind.parameter:
commitCharacters.push('.', ',', ';');
@@ -16,7 +16,7 @@ const getSymbolKind = (kind: string): vscode.SymbolKind => {
case PConst.Kind.class: return vscode.SymbolKind.Class;
case PConst.Kind.enum: return vscode.SymbolKind.Enum;
case PConst.Kind.interface: return vscode.SymbolKind.Interface;
case PConst.Kind.memberFunction: return vscode.SymbolKind.Method;
case PConst.Kind.method: return vscode.SymbolKind.Method;
case PConst.Kind.memberVariable: return vscode.SymbolKind.Property;
case PConst.Kind.memberGetAccessor: return vscode.SymbolKind.Property;
case PConst.Kind.memberSetAccessor: return vscode.SymbolKind.Property;
@@ -75,7 +75,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip
return getSymbolRange(document, item);
case PConst.Kind.class:
case PConst.Kind.memberFunction:
case PConst.Kind.method:
case PConst.Kind.memberVariable:
case PConst.Kind.memberGetAccessor:
case PConst.Kind.memberSetAccessor:
@@ -94,7 +94,7 @@ export class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLens
case PConst.Kind.enum:
return getSymbolRange(document, item);
case PConst.Kind.memberFunction:
case PConst.Kind.method:
case PConst.Kind.memberGetAccessor:
case PConst.Kind.memberSetAccessor:
case PConst.Kind.constructorImplementation:
@@ -9,15 +9,21 @@ import { ITypeScriptServiceClient } from '../typescriptService';
import * as fileSchemes from '../utils/fileSchemes';
import { doesResourceLookLikeAJavaScriptFile, doesResourceLookLikeATypeScriptFile } from '../utils/languageDescription';
import * as typeConverters from '../utils/typeConverters';
import * as PConst from '../protocol.const';
function getSymbolKind(item: Proto.NavtoItem): vscode.SymbolKind {
switch (item.kind) {
case 'method': return vscode.SymbolKind.Method;
case 'enum': return vscode.SymbolKind.Enum;
case 'function': return vscode.SymbolKind.Function;
case 'class': return vscode.SymbolKind.Class;
case 'interface': return vscode.SymbolKind.Interface;
case 'var': return vscode.SymbolKind.Variable;
case PConst.Kind.method: return vscode.SymbolKind.Method;
case PConst.Kind.enum: return vscode.SymbolKind.Enum;
case PConst.Kind.enumMember: return vscode.SymbolKind.EnumMember;
case PConst.Kind.function: return vscode.SymbolKind.Function;
case PConst.Kind.class: return vscode.SymbolKind.Class;
case PConst.Kind.interface: return vscode.SymbolKind.Interface;
case PConst.Kind.type: return vscode.SymbolKind.Class;
case PConst.Kind.memberVariable: return vscode.SymbolKind.Field;
case PConst.Kind.memberGetAccessor: return vscode.SymbolKind.Field;
case PConst.Kind.memberSetAccessor: return vscode.SymbolKind.Field;
case PConst.Kind.variable: return vscode.SymbolKind.Variable;
default: return vscode.SymbolKind.Variable;
}
}
@@ -25,7 +31,7 @@ function getSymbolKind(item: Proto.NavtoItem): vscode.SymbolKind {
class TypeScriptWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
public constructor(
private readonly client: ITypeScriptServiceClient,
private readonly modeIds: string[]
private readonly modeIds: readonly string[]
) { }
public async provideWorkspaceSymbols(
@@ -54,7 +60,7 @@ class TypeScriptWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvide
}
return response.body
.filter(item => item.containerName && item.kind !== 'alias')
.filter(item => item.containerName || item.kind !== 'alias')
.map(item => this.toSymbolInformation(item));
}
@@ -115,7 +121,8 @@ class TypeScriptWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvide
export function register(
client: ITypeScriptServiceClient,
modeIds: string[],
modeIds: readonly string[],
) {
return vscode.languages.registerWorkspaceSymbolProvider(new TypeScriptWorkspaceSymbolProvider(client, modeIds));
return vscode.languages.registerWorkspaceSymbolProvider(
new TypeScriptWorkspaceSymbolProvider(client, modeIds));
}
@@ -21,7 +21,7 @@ export class Kind {
public static readonly let = 'let';
public static readonly localFunction = 'local function';
public static readonly localVariable = 'local var';
public static readonly memberFunction = 'method';
public static readonly method = 'method';
public static readonly memberGetAccessor = 'getter';
public static readonly memberSetAccessor = 'setter';
public static readonly memberVariable = 'property';
@@ -107,7 +107,7 @@ export namespace SymbolKind {
case PConst.Kind.interface: return vscode.SymbolKind.Interface;
case PConst.Kind.indexSignature: return vscode.SymbolKind.Method;
case PConst.Kind.callSignature: return vscode.SymbolKind.Method;
case PConst.Kind.memberFunction: return vscode.SymbolKind.Method;
case PConst.Kind.method: return vscode.SymbolKind.Method;
case PConst.Kind.memberVariable: return vscode.SymbolKind.Property;
case PConst.Kind.memberGetAccessor: return vscode.SymbolKind.Property;
case PConst.Kind.memberSetAccessor: return vscode.SymbolKind.Property;
@@ -626,10 +626,10 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
typescript-vscode-sh-plugin@^0.6.8:
version "0.6.8"
resolved "https://registry.yarnpkg.com/typescript-vscode-sh-plugin/-/typescript-vscode-sh-plugin-0.6.8.tgz#60d5025f2ab814496824ee997b5e9fc12c5b7f1a"
integrity sha512-XEh/GwBRsZKWQjPTODqWWiW8o8DyF7Yzfp/xvq1vyK5Z9JykFKAkx95BEmALv9x9dpc2RcLZHgVsKFXrtDABCw==
typescript-vscode-sh-plugin@^0.6.10:
version "0.6.10"
resolved "https://registry.yarnpkg.com/typescript-vscode-sh-plugin/-/typescript-vscode-sh-plugin-0.6.10.tgz#f9fdac506a3adb698d52fd01723ec78e8a5fc09e"
integrity sha512-cYycpwLnYT2oS48tac+UvVRtIFHHTcHAz/g3N2HpYftuMEBvBcsGfe2SrlnrGCa1gMheTbo+twIHhsQu9ygdvg==
uri-js@^4.2.2:
version "4.2.2"
+1 -1
View File
@@ -10,7 +10,7 @@
"onFileSystem:memfs",
"onDebug"
],
"main": "./out/extension",
"main": "./out/web-playground/extension",
"engines": {
"vscode": "^1.25.0"
},
@@ -37,8 +37,7 @@ suite('Debug', function () {
disposeAll(toDispose);
});
this.retries(2);
test('start debugging', async function () {
test.skip('start debugging', async function () {
let stoppedEvents = 0;
let variablesReceived: () => void;
let initializedReceived: () => void;
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.44.0",
"distro": "07db0bb3dc2da82ce33f2871e0093df1b9085d06",
"distro": "de617fbc2d2b5e151b9e4f1713fcd5d29dda04ea",
"author": {
"name": "Microsoft Corporation"
},
@@ -150,7 +150,7 @@
"source-map": "^0.4.4",
"style-loader": "^1.0.0",
"ts-loader": "^4.4.2",
"typescript": "3.9.0-dev.20200304",
"typescript": "^3.9.0-dev.20200313",
"typescript-formatter": "7.1.0",
"underscore": "^1.8.2",
"vinyl": "^2.0.0",
@@ -46,7 +46,8 @@
}
.monaco-action-bar .action-item .codicon {
vertical-align: middle;
display: flex;
align-items: center;
}
.monaco-action-bar .action-label {
@@ -510,7 +510,7 @@ export class ActionBar extends Disposable implements IActionRunner {
} else if (event.equals(nextKey)) {
this.focusNext();
} else if (event.equals(KeyCode.Escape)) {
this.cancel();
this._onDidCancel.fire();
} else if (this.isTriggerKeyEvent(event)) {
// Staying out of the else branch even if not triggered
if (this.options.triggerKeys && this.options.triggerKeys.keyDown) {
@@ -813,14 +813,6 @@ export class ActionBar extends Disposable implements IActionRunner {
}
}
private cancel(): void {
if (document.activeElement instanceof HTMLElement) {
document.activeElement.blur(); // remove focus from focused action
}
this._onDidCancel.fire();
}
run(action: IAction, context?: unknown): Promise<void> {
return this._actionRunner.run(action, context);
}
@@ -5,7 +5,7 @@
@font-face {
font-family: "codicon";
src: url("./codicon.ttf?df9e07bbeddc0cf98f4d7a7c92bef3d8") format("truetype");
src: url("./codicon.ttf?5490083fcec741c6a0a08a366d2f9c98") format("truetype");
}
.codicon[class*='codicon-'] {
@@ -419,3 +419,4 @@
.codicon-bell-dot:before { content: "\f101" }
.codicon-debug-alt-2:before { content: "\f102" }
.codicon-debug-alt:before { content: "\f103" }
.codicon-run-all:before { content: "\f104" }
@@ -23,6 +23,7 @@ export interface IIconLabelValueOptions {
hideIcon?: boolean;
extraClasses?: string[];
italic?: boolean;
strikethrough?: boolean;
matches?: IMatch[];
labelEscapeNewLines?: boolean;
descriptionMatches?: IMatch[];
@@ -136,6 +137,10 @@ export class IconLabel extends Disposable {
if (options.italic) {
classes.push('italic');
}
if (options.strikethrough) {
classes.push('strikethrough');
}
}
this.domNode.className = classes.join(' ');
@@ -60,6 +60,11 @@
font-style: italic;
}
.monaco-icon-label.strikethrough > .monaco-icon-label-container > .monaco-icon-name-container > .label-name,
.monaco-icon-label.strikethrough > .monaco-icon-description-container > .label-description {
text-decoration: line-through;
}
.monaco-icon-label::after {
opacity: 0.75;
font-size: 90%;
+16 -12
View File
@@ -295,6 +295,10 @@ export class InputBox extends Widget {
}
}
public isSelectionAtEnd(): boolean {
return this.input.selectionEnd === this.input.value.length && this.input.selectionStart === this.input.selectionEnd;
}
public enable(): void {
this.input.removeAttribute('disabled');
}
@@ -373,18 +377,6 @@ export class InputBox extends Widget {
const styles = this.stylesForType(this.message.type);
this.element.style.border = styles.border ? `1px solid ${styles.border}` : '';
// ARIA Support
let alertText: string;
if (message.type === MessageType.ERROR) {
alertText = nls.localize('alertErrorMessage', "Error: {0}", message.content);
} else if (message.type === MessageType.WARNING) {
alertText = nls.localize('alertWarningMessage', "Warning: {0}", message.content);
} else {
alertText = nls.localize('alertInfoMessage', "Info: {0}", message.content);
}
aria.alert(alertText);
if (this.hasFocus() || force) {
this._showMessage();
}
@@ -485,6 +477,18 @@ export class InputBox extends Widget {
layout: layout
});
// ARIA Support
let alertText: string;
if (this.message.type === MessageType.ERROR) {
alertText = nls.localize('alertErrorMessage', "Error: {0}", this.message.content);
} else if (this.message.type === MessageType.WARNING) {
alertText = nls.localize('alertWarningMessage', "Warning: {0}", this.message.content);
} else {
alertText = nls.localize('alertInfoMessage', "Info: {0}", this.message.content);
}
aria.alert(alertText);
this.state = 'open';
}
+1 -1
View File
@@ -65,7 +65,7 @@ export interface IIdentityProvider<T> {
export enum ListAriaRootRole {
/** default list structure role */
LIST = 'list',
LIST = 'listbox',
/** default tree structure role */
TREE = 'tree',
+18 -8
View File
@@ -22,6 +22,7 @@ export interface IPaneOptions {
minimumBodySize?: number;
maximumBodySize?: number;
expanded?: boolean;
orientation?: Orientation;
title: string;
}
@@ -50,6 +51,7 @@ export abstract class Pane extends Disposable implements IView {
private body!: HTMLElement;
protected _expanded: boolean;
protected _orientation: Orientation;
protected _preventCollapse?: boolean;
private expandedSize: number | undefined = undefined;
@@ -117,11 +119,12 @@ export abstract class Pane extends Disposable implements IView {
return headerSize + maximumBodySize;
}
width: number = 0;
orthogonalSize: number = 0;
constructor(options: IPaneOptions) {
super();
this._expanded = typeof options.expanded === 'undefined' ? true : !!options.expanded;
this._orientation = typeof options.orientation === 'undefined' ? Orientation.VERTICAL : options.orientation;
this.ariaHeaderLabel = localize('viewSection', "{0} Section", options.title);
this._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : 120;
this._maximumBodySize = typeof options.maximumBodySize === 'number' ? options.maximumBodySize : Number.POSITIVE_INFINITY;
@@ -206,14 +209,21 @@ export abstract class Pane extends Disposable implements IView {
this.body = append(this.element, $('.pane-body'));
this.renderBody(this.body);
if (!this.isExpanded()) {
this.body.remove();
}
}
layout(height: number): void {
layout(size: number): void {
const headerSize = this.headerVisible ? Pane.HEADER_SIZE : 0;
const width = this._orientation === Orientation.VERTICAL ? this.orthogonalSize : size;
const height = this._orientation === Orientation.VERTICAL ? size - headerSize : this.orthogonalSize - headerSize;
if (this.isExpanded()) {
this.layoutBody(height - headerSize, this.width);
this.expandedSize = height;
this.layoutBody(height, width);
this.expandedSize = size;
}
}
@@ -391,7 +401,7 @@ export class PaneView extends Disposable {
private dndContext: IDndContext = { draggable: null };
private el: HTMLElement;
private paneItems: IPaneItem[] = [];
private width: number = 0;
private orthogonalSize: number = 0;
private splitview: SplitView;
private orientation: Orientation;
private animationTimer: number | undefined = undefined;
@@ -417,7 +427,7 @@ export class PaneView extends Disposable {
const paneItem = { pane: pane, disposable: disposables };
this.paneItems.splice(index, 0, paneItem);
pane.width = this.width;
pane.orthogonalSize = this.orthogonalSize;
this.splitview.addView(pane, size, index);
if (this.dnd) {
@@ -474,10 +484,10 @@ export class PaneView extends Disposable {
}
layout(height: number, width: number): void {
this.width = width;
this.orthogonalSize = this.orientation === Orientation.VERTICAL ? width : height;
for (const paneItem of this.paneItems) {
paneItem.pane.width = width;
paneItem.pane.orthogonalSize = this.orthogonalSize;
}
this.splitview.layout(this.orientation === Orientation.HORIZONTAL ? width : height);
+2 -2
View File
@@ -392,7 +392,7 @@ export function anyScore(pattern: string, lowPattern: string, _patternPos: numbe
//#region --- fuzzyScore ---
export function createMatches(score: undefined | FuzzyScore): IMatch[] {
export function createMatches(score: undefined | FuzzyScore, offset = 0): IMatch[] {
if (typeof score === 'undefined') {
return [];
}
@@ -407,7 +407,7 @@ export function createMatches(score: undefined | FuzzyScore): IMatch[] {
if (last && last.end === pos) {
last.end = pos + 1;
} else {
res.push({ start: pos, end: pos + 1 });
res.push({ start: pos + offset, end: pos + 1 + offset });
}
}
}
+234
View File
@@ -3,6 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as strings from 'vs/base/common/strings';
/**
* Return a hash value for an object.
*/
@@ -70,3 +72,235 @@ export class Hasher {
return this._value;
}
}
const enum SHA1Constant {
BLOCK_SIZE = 64, // 512 / 8
UNICODE_REPLACEMENT = 0xFFFD,
}
function leftRotate(value: number, bits: number, totalBits: number = 32): number {
// delta + bits = totalBits
const delta = totalBits - bits;
// All ones, expect `delta` zeros aligned to the right
const mask = ~((1 << delta) - 1);
// Join (value left-shifted `bits` bits) with (masked value right-shifted `delta` bits)
return ((value << bits) | ((mask & value) >>> delta)) >>> 0;
}
function fill(dest: Uint8Array, index: number = 0, count: number = dest.byteLength, value: number = 0): void {
for (let i = 0; i < count; i++) {
dest[index + i] = value;
}
}
function leftPad(value: string, length: number, char: string = '0'): string {
while (value.length < length) {
value = char + value;
}
return value;
}
function toHexString(value: number, bitsize: number = 32): string {
return leftPad((value >>> 0).toString(16), bitsize / 4);
}
/**
* A SHA1 implementation that works with strings and does not allocate.
*/
export class StringSHA1 {
private static _bigBlock32 = new DataView(new ArrayBuffer(320)); // 80 * 4 = 320
private _h0 = 0x67452301;
private _h1 = 0xEFCDAB89;
private _h2 = 0x98BADCFE;
private _h3 = 0x10325476;
private _h4 = 0xC3D2E1F0;
private readonly _buff: Uint8Array;
private readonly _buffDV: DataView;
private _buffLen: number;
private _totalLen: number;
private _leftoverHighSurrogate: number;
private _finished: boolean;
constructor() {
this._buff = new Uint8Array(SHA1Constant.BLOCK_SIZE + 3 /* to fit any utf-8 */);
this._buffDV = new DataView(this._buff.buffer);
this._buffLen = 0;
this._totalLen = 0;
this._leftoverHighSurrogate = 0;
this._finished = false;
}
public update(str: string): void {
const strLen = str.length;
if (strLen === 0) {
return;
}
const buff = this._buff;
let buffLen = this._buffLen;
let leftoverHighSurrogate = this._leftoverHighSurrogate;
let charCode: number;
let offset: number;
if (leftoverHighSurrogate !== 0) {
charCode = leftoverHighSurrogate;
offset = -1;
leftoverHighSurrogate = 0;
} else {
charCode = str.charCodeAt(0);
offset = 0;
}
while (true) {
let codePoint = charCode;
if (strings.isHighSurrogate(charCode)) {
if (offset + 1 < strLen) {
const nextCharCode = str.charCodeAt(offset + 1);
if (strings.isLowSurrogate(nextCharCode)) {
offset++;
codePoint = strings.computeCodePoint(charCode, nextCharCode);
} else {
// illegal => unicode replacement character
codePoint = SHA1Constant.UNICODE_REPLACEMENT;
}
} else {
// last character is a surrogate pair
leftoverHighSurrogate = charCode;
break;
}
} else if (strings.isLowSurrogate(charCode)) {
// illegal => unicode replacement character
codePoint = SHA1Constant.UNICODE_REPLACEMENT;
}
buffLen = this._push(buff, buffLen, codePoint);
offset++;
if (offset < strLen) {
charCode = str.charCodeAt(offset);
} else {
break;
}
}
this._buffLen = buffLen;
this._leftoverHighSurrogate = leftoverHighSurrogate;
}
private _push(buff: Uint8Array, buffLen: number, codePoint: number): number {
if (codePoint < 0x0080) {
buff[buffLen++] = codePoint;
} else if (codePoint < 0x0800) {
buff[buffLen++] = 0b11000000 | ((codePoint & 0b00000000000000000000011111000000) >>> 6);
buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);
} else if (codePoint < 0x10000) {
buff[buffLen++] = 0b11100000 | ((codePoint & 0b00000000000000001111000000000000) >>> 12);
buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);
buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);
} else {
buff[buffLen++] = 0b11110000 | ((codePoint & 0b00000000000111000000000000000000) >>> 18);
buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000111111000000000000) >>> 12);
buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);
buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);
}
if (buffLen >= SHA1Constant.BLOCK_SIZE) {
this._step();
buffLen -= SHA1Constant.BLOCK_SIZE;
this._totalLen += SHA1Constant.BLOCK_SIZE;
// take last 3 in case of UTF8 overflow
buff[0] = buff[SHA1Constant.BLOCK_SIZE + 0];
buff[1] = buff[SHA1Constant.BLOCK_SIZE + 1];
buff[2] = buff[SHA1Constant.BLOCK_SIZE + 2];
}
return buffLen;
}
public digest(): string {
if (!this._finished) {
this._finished = true;
if (this._leftoverHighSurrogate) {
// illegal => unicode replacement character
this._leftoverHighSurrogate = 0;
this._buffLen = this._push(this._buff, this._buffLen, SHA1Constant.UNICODE_REPLACEMENT);
}
this._totalLen += this._buffLen;
this._wrapUp();
}
return toHexString(this._h0) + toHexString(this._h1) + toHexString(this._h2) + toHexString(this._h3) + toHexString(this._h4);
}
private _wrapUp(): void {
this._buff[this._buffLen++] = 0x80;
fill(this._buff, this._buffLen);
if (this._buffLen > 56) {
this._step();
fill(this._buff);
}
// this will fit because the mantissa can cover up to 52 bits
const ml = 8 * this._totalLen;
this._buffDV.setUint32(56, Math.floor(ml / 4294967296), false);
this._buffDV.setUint32(60, ml % 4294967296, false);
this._step();
}
private _step(): void {
const bigBlock32 = StringSHA1._bigBlock32;
const data = this._buffDV;
for (let j = 0; j < 64 /* 16*4 */; j += 4) {
bigBlock32.setUint32(j, data.getUint32(j, false), false);
}
for (let j = 64; j < 320 /* 80*4 */; j += 4) {
bigBlock32.setUint32(j, leftRotate((bigBlock32.getUint32(j - 12, false) ^ bigBlock32.getUint32(j - 32, false) ^ bigBlock32.getUint32(j - 56, false) ^ bigBlock32.getUint32(j - 64, false)), 1), false);
}
let a = this._h0;
let b = this._h1;
let c = this._h2;
let d = this._h3;
let e = this._h4;
let f: number, k: number;
let temp: number;
for (let j = 0; j < 80; j++) {
if (j < 20) {
f = (b & c) | ((~b) & d);
k = 0x5A827999;
} else if (j < 40) {
f = b ^ c ^ d;
k = 0x6ED9EBA1;
} else if (j < 60) {
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
} else {
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = (leftRotate(a, 5) + f + e + k + bigBlock32.getUint32(j * 4, false)) & 0xffffffff;
e = d;
d = c;
c = leftRotate(b, 30);
b = a;
a = temp;
}
this._h0 = (this._h0 + a) & 0xffffffff;
this._h1 = (this._h1 + b) & 0xffffffff;
this._h2 = (this._h2 + c) & 0xffffffff;
this._h3 = (this._h3 + d) & 0xffffffff;
this._h4 = (this._h4 + e) & 0xffffffff;
}
}
+15 -17
View File
@@ -428,29 +428,27 @@ export function commonSuffixLength(a: string, b: string): number {
return len;
}
// --- unicode
// http://en.wikipedia.org/wiki/Surrogate_pair
// Returns the code point starting at a specified index in a string
// Code points U+0000 to U+D7FF and U+E000 to U+FFFF are represented on a single character
// Code points U+10000 to U+10FFFF are represented on two consecutive characters
//export function getUnicodePoint(str:string, index:number, len:number):number {
// const chrCode = str.charCodeAt(index);
// if (0xD800 <= chrCode && chrCode <= 0xDBFF && index + 1 < len) {
// const nextChrCode = str.charCodeAt(index + 1);
// if (0xDC00 <= nextChrCode && nextChrCode <= 0xDFFF) {
// return (chrCode - 0xD800) << 10 + (nextChrCode - 0xDC00) + 0x10000;
// }
// }
// return chrCode;
//}
/**
* See http://en.wikipedia.org/wiki/Surrogate_pair
*/
export function isHighSurrogate(charCode: number): boolean {
return (0xD800 <= charCode && charCode <= 0xDBFF);
}
/**
* See http://en.wikipedia.org/wiki/Surrogate_pair
*/
export function isLowSurrogate(charCode: number): boolean {
return (0xDC00 <= charCode && charCode <= 0xDFFF);
}
/**
* See http://en.wikipedia.org/wiki/Surrogate_pair
*/
export function computeCodePoint(highSurrogate: number, lowSurrogate: number): number {
return ((highSurrogate - 0xD800) << 10) + (lowSurrogate - 0xDC00) + 0x10000;
}
/**
* get the code point that begins at offset `offset`
*/
@@ -459,7 +457,7 @@ export function getNextCodePoint(str: string, len: number, offset: number): numb
if (isHighSurrogate(charCode) && offset + 1 < len) {
const nextCharCode = str.charCodeAt(offset + 1);
if (isLowSurrogate(nextCharCode)) {
return ((charCode - 0xD800) << 10) + (nextCharCode - 0xDC00) + 0x10000;
return computeCodePoint(charCode, nextCharCode);
}
}
return charCode;
@@ -473,7 +471,7 @@ function getPrevCodePoint(str: string, offset: number): number {
if (isLowSurrogate(charCode) && offset > 1) {
const prevCharCode = str.charCodeAt(offset - 2);
if (isHighSurrogate(prevCharCode)) {
return ((prevCharCode - 0xD800) << 10) + (charCode - 0xDC00) + 0x10000;
return computeCodePoint(prevCharCode, charCode);
}
}
return charCode;
+2
View File
@@ -85,6 +85,7 @@ const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
* (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation
* and encoding.
*
* ```txt
* foo://example.com:8042/over/there?name=ferret#nose
* \_/ \______________/\_________/ \_________/ \__/
* | | | | |
@@ -92,6 +93,7 @@ const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
* | _____________________|__
* / \ / \
* urn:example:animal:ferret:nose
* ```
*/
export class URI implements UriComponents {
@@ -186,6 +186,11 @@
align-items: center;
}
.quick-input-list .quick-input-list-rows > .quick-input-list-row .monaco-icon-label,
.quick-input-list .quick-input-list-rows > .quick-input-list-row .monaco-icon-label .monaco-icon-label-container > .monaco-icon-name-container {
flex: 1; /* make sure the icon label grows within the row */
}
.quick-input-list .quick-input-list-rows > .quick-input-list-row .codicon {
vertical-align: sub;
}
@@ -194,6 +199,10 @@
opacity: 1;
}
.quick-input-list .quick-input-list-entry .quick-input-list-entry-keybinding {
margin-right: 8px; /* separate from the separator label or scrollbar if any */
}
.quick-input-list .quick-input-list-label-meta {
opacity: 0.7;
line-height: normal;
@@ -205,17 +214,13 @@
font-weight: bold;
}
.quick-input-list .quick-input-list-separator {
margin-right: 18px;
}
.quick-input-list .quick-input-list-entry.has-actions:hover .quick-input-list-separator,
.quick-input-list .monaco-list-row.focused .quick-input-list-entry.has-actions .quick-input-list-separator {
margin-right: 0;
.quick-input-list .quick-input-list-entry .quick-input-list-separator {
margin-right: 8px; /* separate from keybindings or actions */
}
.quick-input-list .quick-input-list-entry-action-bar {
display: none;
display: flex;
visibility: hidden; /* not using display: none here to not flicker too much */
flex: 0;
overflow: visible;
}
@@ -231,15 +236,16 @@
margin-top: 1px;
}
.quick-input-list .quick-input-list-entry-action-bar ul:first-child .action-label.codicon {
margin-left: 2px;
.quick-input-list .quick-input-list-entry-action-bar {
margin-right: 4px; /* separate from scrollbar */
}
.quick-input-list .quick-input-list-entry-action-bar ul:last-child .action-label.codicon {
margin-right: 8px;
.quick-input-list .quick-input-list-entry-action-bar .action-label.codicon {
margin-right: 4px; /* separate actions */
}
.quick-input-list .quick-input-list-entry.always-visible-actions .quick-input-list-entry-action-bar,
.quick-input-list .quick-input-list-entry:hover .quick-input-list-entry-action-bar,
.quick-input-list .monaco-list-row.focused .quick-input-list-entry-action-bar {
display: flex;
visibility: visible;
}
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/quickInput';
import { IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IInputBox, IQuickPickItemButtonEvent, QuickPickInput, IQuickPickSeparator, IKeyMods } from 'vs/base/parts/quickinput/common/quickInput';
import { IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IInputBox, IQuickPickItemButtonEvent, QuickPickInput, IQuickPickSeparator, IKeyMods, IQuickPickAcceptEvent } from 'vs/base/parts/quickinput/common/quickInput';
import * as dom from 'vs/base/browser/dom';
import { CancellationToken } from 'vs/base/common/cancellation';
import { QuickInputList } from './quickInputList';
@@ -379,11 +379,12 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
private _ariaLabel = QuickPick.DEFAULT_ARIA_LABEL;
private _placeholder: string | undefined;
private readonly onDidChangeValueEmitter = this._register(new Emitter<string>());
private readonly onDidAcceptEmitter = this._register(new Emitter<void>());
private readonly onDidAcceptEmitter = this._register(new Emitter<IQuickPickAcceptEvent>());
private readonly onDidCustomEmitter = this._register(new Emitter<void>());
private _items: Array<T | IQuickPickSeparator> = [];
private itemsUpdated = false;
private _canSelectMany = false;
private _canAcceptInBackground = false;
private _matchOnDescription = false;
private _matchOnDetail = false;
private _matchOnLabel = true;
@@ -462,6 +463,14 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
this.update();
}
get canAcceptInBackground() {
return this._canAcceptInBackground;
}
set canAcceptInBackground(canAcceptInBackground: boolean) {
this._canAcceptInBackground = canAcceptInBackground;
}
get matchOnDescription() {
return this._matchOnDescription;
}
@@ -663,6 +672,22 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
this.ui.list.domFocus();
}
event.preventDefault();
break;
case KeyCode.RightArrow:
if (!this._canAcceptInBackground) {
return; // needs to be enabled
}
if (!this.ui.inputBox.isSelectionAtEnd()) {
return; // ensure input box selection at end
}
if (this.activeItems[0]) {
this._selectedItems = [this.activeItems[0]];
this.onDidChangeSelectionEmitter.fire(this.selectedItems);
this.onDidAcceptEmitter.fire({ inBackground: true });
}
break;
}
}));
@@ -671,7 +696,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
this._selectedItems = [this.activeItems[0]];
this.onDidChangeSelectionEmitter.fire(this.selectedItems);
}
this.onDidAcceptEmitter.fire(undefined);
this.onDidAcceptEmitter.fire({ inBackground: false });
}));
this.visibleDisposables.add(this.ui.onDidCustom(() => {
this.onDidCustomEmitter.fire(undefined);
@@ -686,7 +711,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
this._activeItems = focusedItems as T[];
this.onDidChangeActiveEmitter.fire(focusedItems as T[]);
}));
this.visibleDisposables.add(this.ui.list.onDidChangeSelection(selectedItems => {
this.visibleDisposables.add(this.ui.list.onDidChangeSelection(({ items: selectedItems, event }) => {
if (this.canSelectMany) {
if (selectedItems.length) {
this.ui.list.setSelectedElements([]);
@@ -699,7 +724,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
this._selectedItems = selectedItems as T[];
this.onDidChangeSelectionEmitter.fire(selectedItems as T[]);
if (selectedItems.length) {
this.onDidAcceptEmitter.fire(undefined);
this.onDidAcceptEmitter.fire({ inBackground: event instanceof MouseEvent && event.button === 1 /* mouse middle click */ });
}
}));
this.visibleDisposables.add(this.ui.list.onChangedCheckedElements(checkedItems => {
@@ -762,7 +787,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
if (wasTriggerKeyPressed && this.activeItems[0]) {
this._selectedItems = [this.activeItems[0]];
this.onDidChangeSelectionEmitter.fire(this.selectedItems);
this.onDidAcceptEmitter.fire(undefined);
this.onDidAcceptEmitter.fire({ inBackground: false });
}
});
}
@@ -54,7 +54,11 @@ export class QuickInputBox extends Disposable {
this.inputBox.select(range);
}
setPlaceholder(placeholder: string) {
isSelectionAtEnd(): boolean {
return this.inputBox.isSelectionAtEnd();
}
setPlaceholder(placeholder: string): void {
this.inputBox.setPlaceHolder(placeholder);
}
@@ -90,11 +94,11 @@ export class QuickInputBox extends Disposable {
return this.inputBox.hasFocus();
}
setAttribute(name: string, value: string) {
setAttribute(name: string, value: string): void {
this.inputBox.inputElement.setAttribute(name, value);
}
removeAttribute(name: string) {
removeAttribute(name: string): void {
this.inputBox.inputElement.removeAttribute(name);
}
@@ -118,7 +122,7 @@ export class QuickInputBox extends Disposable {
this.inputBox.layout();
}
style(styles: IInputBoxStyles) {
style(styles: IInputBoxStyles): void {
this.inputBox.style(styles);
}
}
@@ -25,7 +25,8 @@ import { Action } from 'vs/base/common/actions';
import { getIconClass } from 'vs/base/parts/quickinput/browser/quickInputUtils';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IQuickInputOptions } from 'vs/base/parts/quickinput/browser/quickInput';
import { IListOptions, List, IListStyles } from 'vs/base/browser/ui/list/listWidget';
import { IListOptions, List, IListStyles, IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
const $ = dom.$;
@@ -79,6 +80,7 @@ interface IListElementTemplateData {
entry: HTMLDivElement;
checkbox: HTMLInputElement;
label: IconLabel;
keybinding: KeybindingLabel;
detail: HighlightedLabel;
separator: HTMLDivElement;
actionBar: ActionBar;
@@ -118,6 +120,10 @@ class ListElementRenderer implements IListRenderer<ListElement, IListElementTemp
// Label
data.label = new IconLabel(row1, { supportHighlights: true, supportDescriptionHighlights: true, supportCodicons: true });
// Keybinding
const keybindingContainer = dom.append(row1, $('.quick-input-list-entry-keybinding'));
data.keybinding = new KeybindingLabel(keybindingContainer, platform.OS);
// Detail
const detailContainer = dom.append(row2, $('.quick-input-list-label-meta'));
data.detail = new HighlightedLabel(detailContainer, true);
@@ -148,14 +154,15 @@ class ListElementRenderer implements IListRenderer<ListElement, IListElementTemp
options.descriptionMatches = descriptionHighlights || [];
options.extraClasses = element.item.iconClasses;
options.italic = element.item.italic;
options.strikethrough = element.item.strikethrough;
data.label.setLabel(element.saneLabel, element.saneDescription, options);
// Keybinding
data.keybinding.set(element.item.keybinding);
// Meta
data.detail.set(element.saneDetail, detailHighlights);
// ARIA label
data.entry.setAttribute('aria-label', element.saneAriaLabel);
// Separator
if (element.separator && element.separator.label) {
data.separator.textContent = element.separator.label;
@@ -188,6 +195,12 @@ class ListElementRenderer implements IListRenderer<ListElement, IListElementTemp
} else {
dom.removeClass(data.entry, 'has-actions');
}
if (element.item.buttonsAlwaysVisible) {
dom.addClass(data.entry, 'always-visible-actions');
} else {
dom.removeClass(data.entry, 'always-visible-actions');
}
}
disposeElement(element: ListElement, index: number, data: IListElementTemplateData): void {
@@ -247,12 +260,14 @@ export class QuickInputList {
this.id = id;
this.container = dom.append(this.parent, $('.quick-input-list'));
const delegate = new ListElementDelegate();
const accessibilityProvider = new QuickInputAccessibilityProvider();
this.list = options.createList('QuickInput', this.container, delegate, [new ListElementRenderer()], {
identityProvider: { getId: element => element.saneLabel },
openController: { shouldOpen: () => false }, // Workaround #58124
setRowLineHeight: false,
multipleSelectionSupport: false,
horizontalScrolling: false,
accessibilityProvider
} as IListOptions<ListElement>);
this.list.getHTMLElement().id = id;
this.disposables.push(this.list);
@@ -303,7 +318,7 @@ export class QuickInputList {
@memoize
get onDidChangeSelection() {
return Event.map(this.list.onDidChangeSelection, e => e.elements.map(e => e.item));
return Event.map(this.list.onDidChangeSelection, e => ({ items: e.elements.map(e => e.item), event: e.browserEvent }));
}
getAllVisibleChecked() {
@@ -606,3 +621,9 @@ function compareEntries(elementA: ListElement, elementB: ListElement, lookFor: s
return compareAnything(elementA.saneLabel, elementB.saneLabel, lookFor);
}
class QuickInputAccessibilityProvider implements IAccessibilityProvider<ListElement> {
getAriaLabel(element: ListElement): string | null {
return element.saneAriaLabel;
}
}
@@ -24,10 +24,22 @@ export interface IQuickPickItem {
ariaLabel?: string;
description?: string;
detail?: string;
/**
* Allows to show a keybinding next to the item to indicate
* how the item can be triggered outside of the picker using
* keyboard shortcut.
*/
keybinding?: ResolvedKeybinding;
iconClasses?: string[];
italic?: boolean;
strikethrough?: boolean;
highlights?: IQuickPickItemHighlights;
buttons?: IQuickInputButton[];
/**
* Wether to always show the buttons. By default buttons
* are only visible when hovering over them with the mouse
*/
buttonsAlwaysVisible?: boolean;
picked?: boolean;
alwaysShow?: boolean;
}
@@ -164,6 +176,15 @@ export interface IQuickInput extends IDisposable {
hide(): void;
}
export interface IQuickPickAcceptEvent {
/**
* Signals if the picker item is to be accepted
* in the background while keeping the picker open.
*/
inBackground: boolean;
}
export interface IQuickPick<T extends IQuickPickItem> extends IQuickInput {
value: string;
@@ -180,7 +201,14 @@ export interface IQuickPick<T extends IQuickPickItem> extends IQuickInput {
readonly onDidChangeValue: Event<string>;
readonly onDidAccept: Event<void>;
readonly onDidAccept: Event<IQuickPickAcceptEvent>;
/**
* If enabled, will fire the `onDidAccept` event when
* pressing the arrow-right key with the idea of accepting
* the selected item without closing the picker.
*/
canAcceptInBackground: boolean;
ok: boolean | 'default';
@@ -45,8 +45,7 @@ export class HeightMap {
totalSize = viewItem.top + viewItem.height;
}
let boundSplice = this.heightMap.splice.bind(this.heightMap, i, 0);
const startingIndex = i;
let itemsToInsert: IViewItem[] = [];
while (item = iterator.next()) {
@@ -58,7 +57,7 @@ export class HeightMap {
sizeDiff += viewItem.height;
}
boundSplice.apply(this.heightMap, itemsToInsert);
this.heightMap.splice(startingIndex, 0, ...itemsToInsert);
for (j = i; j < this.heightMap.length; j++) {
viewItem = this.heightMap[j];
+25 -1
View File
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { hash } from 'vs/base/common/hash';
import { hash, StringSHA1 } from 'vs/base/common/hash';
suite('Hash', () => {
test('string', () => {
@@ -53,4 +53,28 @@ suite('Hash', () => {
assert.notEqual(a, b);
});
function checkSHA1(strings: string[], expected: string) {
const hash = new StringSHA1();
for (const str of strings) {
hash.update(str);
}
const actual = hash.digest();
assert.equal(actual, expected);
}
test('sha1-1', () => {
checkSHA1(['\udd56'], '9bdb77276c1852e1fb067820472812fcf6084024');
});
test('sha1-2', () => {
checkSHA1(['\udb52'], '9bdb77276c1852e1fb067820472812fcf6084024');
});
test('sha1-3', () => {
checkSHA1(['\uda02ꑍ'], '9b483a471f22fe7e09d83f221871a987244bbd3f');
});
test('sha1-4', () => {
checkSHA1(['hello'], 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d');
});
});
@@ -49,17 +49,16 @@ import { IFileService } from 'vs/platform/files/common/files';
import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider';
import { Schemas } from 'vs/base/common/network';
import { IProductService } from 'vs/platform/product/common/productService';
import { IUserDataSyncService, IUserDataSyncStoreService, registerConfiguration, IUserDataSyncLogService, IUserDataSyncUtilService, ISettingsSyncService, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { IUserDataSyncService, IUserDataSyncStoreService, registerConfiguration, IUserDataSyncLogService, IUserDataSyncUtilService, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService } from 'vs/platform/userDataSync/common/userDataSync';
import { UserDataSyncService } from 'vs/platform/userDataSync/common/userDataSyncService';
import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService';
import { UserDataSyncChannel, UserDataSyncUtilServiceClient, SettingsSyncChannel, UserDataAutoSyncChannel, UserDataSyncStoreServiceChannel, UserDataSyncBackupStoreServiceChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc';
import { UserDataSyncChannel, UserDataSyncUtilServiceClient, UserDataAutoSyncChannel, UserDataSyncStoreServiceChannel, UserDataSyncBackupStoreServiceChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc';
import { IElectronService } from 'vs/platform/electron/node/electron';
import { LoggerService } from 'vs/platform/log/node/loggerService';
import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog';
import { ICredentialsService } from 'vs/platform/credentials/common/credentials';
import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService';
import { UserDataAutoSyncService } from 'vs/platform/userDataSync/electron-browser/userDataAutoSyncService';
import { SettingsSynchroniser } from 'vs/platform/userDataSync/common/settingsSync';
import { NativeStorageService } from 'vs/platform/storage/node/storageService';
import { GlobalStorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc';
import { IStorageService } from 'vs/platform/storage/common/storage';
@@ -197,7 +196,6 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
services.set(IUserDataSyncStoreService, new SyncDescriptor(UserDataSyncStoreService));
services.set(IUserDataSyncBackupStoreService, new SyncDescriptor(UserDataSyncBackupStoreService));
services.set(IUserDataSyncEnablementService, new SyncDescriptor(UserDataSyncEnablementService));
services.set(ISettingsSyncService, new SyncDescriptor(SettingsSynchroniser));
services.set(IUserDataSyncService, new SyncDescriptor(UserDataSyncService));
registerConfiguration();
@@ -229,10 +227,6 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
const userDataSyncBackupStoreServiceChannel = new UserDataSyncBackupStoreServiceChannel(userDataSyncBackupStoreService);
server.registerChannel('userDataSyncBackupStoreService', userDataSyncBackupStoreServiceChannel);
const settingsSyncService = accessor.get(ISettingsSyncService);
const settingsSyncChannel = new SettingsSyncChannel(settingsSyncService);
server.registerChannel('settingsSync', settingsSyncChannel);
const userDataSyncService = accessor.get(IUserDataSyncService);
const userDataSyncChannel = new UserDataSyncChannel(userDataSyncService);
server.registerChannel('userDataSync', userDataSyncChannel);
+8 -2
View File
@@ -28,12 +28,13 @@ import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/commo
import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
import { endsWith } from 'vs/base/common/strings';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IFileService } from 'vs/platform/files/common/files';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
import { IStorageMainService } from 'vs/platform/storage/node/storageMainService';
import { IFileService } from 'vs/platform/files/common/files';
const RUN_TEXTMATE_IN_WORKER = false;
@@ -97,6 +98,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
@ILogService private readonly logService: ILogService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IFileService private readonly fileService: IFileService,
@IStorageMainService private readonly storageService: IStorageMainService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IThemeMainService private readonly themeMainService: IThemeMainService,
@IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService,
@@ -226,7 +228,11 @@ export class CodeWindow extends Disposable implements ICodeWindow {
this.createTouchBar();
// Request handling
this.marketplaceHeadersPromise = resolveMarketplaceHeaders(product.version, this.environmentService, this.fileService);
const that = this;
this.marketplaceHeadersPromise = resolveMarketplaceHeaders(product.version, this.environmentService, this.fileService, {
get(key) { return that.storageService.get(key); },
store(key, value) { that.storageService.store(key, value); }
});
// Eventing
this.registerListeners();
@@ -616,7 +616,15 @@ class RenderedViewLine implements IRenderedViewLine {
if (!r || r.length === 0) {
return -1;
}
return r[0].left;
const result = r[0].left;
if (this.input.isBasicASCII) {
const charOffset = this._characterMapping.getAbsoluteOffsets();
const expectedResult = Math.round(this.input.spaceWidth * charOffset[column - 1]);
if (Math.abs(expectedResult - result) <= 1) {
return expectedResult;
}
}
return result;
}
private _readRawVisibleRangesForRange(domNode: FastDomNode<HTMLElement>, startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null {
+4
View File
@@ -1759,6 +1759,7 @@ export class TextModel extends Disposable implements model.ITextModel {
if (ranges.length > 0) {
this._emitModelTokensChangedEvent({
tokenizationSupportChanged: false,
semanticTokensApplied: false,
ranges: ranges
});
}
@@ -1769,6 +1770,7 @@ export class TextModel extends Disposable implements model.ITextModel {
this._emitModelTokensChangedEvent({
tokenizationSupportChanged: false,
semanticTokensApplied: tokens !== null,
ranges: [{ fromLineNumber: 1, toLineNumber: this.getLineCount() }]
});
}
@@ -1783,6 +1785,7 @@ export class TextModel extends Disposable implements model.ITextModel {
this._tokens.flush();
this._emitModelTokensChangedEvent({
tokenizationSupportChanged: true,
semanticTokensApplied: false,
ranges: [{
fromLineNumber: 1,
toLineNumber: this._buffer.getLineCount()
@@ -1795,6 +1798,7 @@ export class TextModel extends Disposable implements model.ITextModel {
this._emitModelTokensChangedEvent({
tokenizationSupportChanged: false,
semanticTokensApplied: false,
ranges: [{ fromLineNumber: 1, toLineNumber: this.getLineCount() }]
});
}
@@ -87,6 +87,7 @@ export interface IModelDecorationsChangedEvent {
*/
export interface IModelTokensChangedEvent {
readonly tokenizationSupportChanged: boolean;
readonly semanticTokensApplied: boolean;
readonly ranges: {
/**
* The start of the range (inclusive)
@@ -466,15 +466,16 @@ class SemanticColoringFeature extends Disposable {
private _watchers: Record<string, ModelSemanticColoring>;
private _semanticStyling: SemanticStyling;
private _configurationService: IConfigurationService;
constructor(modelService: IModelService, themeService: IThemeService, configurationService: IConfigurationService, logService: ILogService) {
super();
this._configurationService = configurationService;
this._watchers = Object.create(null);
this._semanticStyling = this._register(new SemanticStyling(themeService, logService));
const isSemanticColoringEnabled = (model: ITextModel) => {
if (!themeService.getColorTheme().semanticHighlighting) {
return false;
}
const options = configurationService.getValue<IEditorSemanticHighlightingOptions>(SemanticColoringFeature.SETTING_ID, { overrideIdentifier: model.getLanguageIdentifier().language, resource: model.uri });
return options && options.enabled;
};
@@ -485,6 +486,20 @@ class SemanticColoringFeature extends Disposable {
modelSemanticColoring.dispose();
delete this._watchers[model.uri.toString()];
};
const handleSettingOrThemeChange = () => {
for (let model of modelService.getModels()) {
const curr = this._watchers[model.uri.toString()];
if (isSemanticColoringEnabled(model)) {
if (!curr) {
register(model);
}
} else {
if (curr) {
deregister(model, curr);
}
}
}
};
this._register(modelService.onModelAdded((model) => {
if (isSemanticColoringEnabled(model)) {
register(model);
@@ -496,22 +511,12 @@ class SemanticColoringFeature extends Disposable {
deregister(model, curr);
}
}));
this._configurationService.onDidChangeConfiguration(e => {
this._register(configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(SemanticColoringFeature.SETTING_ID)) {
for (let model of modelService.getModels()) {
const curr = this._watchers[model.uri.toString()];
if (isSemanticColoringEnabled(model)) {
if (!curr) {
register(model);
}
} else {
if (curr) {
deregister(model, curr);
}
}
}
handleSettingOrThemeChange();
}
});
}));
this._register(themeService.onDidColorThemeChange(handleSettingOrThemeChange));
}
}
@@ -525,12 +530,9 @@ class SemanticStyling extends Disposable {
) {
super();
this._caches = new WeakMap<DocumentSemanticTokensProvider, SemanticColoringProviderStyling>();
if (this._themeService) {
// workaround for tests which use undefined... :/
this._register(this._themeService.onDidColorThemeChange(() => {
this._caches = new WeakMap<DocumentSemanticTokensProvider, SemanticColoringProviderStyling>();
}));
}
this._register(this._themeService.onDidColorThemeChange(() => {
this._caches = new WeakMap<DocumentSemanticTokensProvider, SemanticColoringProviderStyling>();
}));
}
public get(provider: DocumentSemanticTokensProvider): SemanticColoringProviderStyling {
@@ -768,14 +770,12 @@ class ModelSemanticColoring extends Disposable {
this._fetchSemanticTokens.schedule();
}));
if (themeService) {
// workaround for tests which use undefined... :/
this._register(themeService.onDidColorThemeChange(_ => {
// clear out existing tokens
this._setSemanticTokens(null, null, null, []);
this._fetchSemanticTokens.schedule();
}));
}
this._register(themeService.onDidColorThemeChange(_ => {
// clear out existing tokens
this._setSemanticTokens(null, null, null, []);
this._fetchSemanticTokens.schedule();
}));
this._fetchSemanticTokens.schedule(0);
}
+2 -22
View File
@@ -36,12 +36,6 @@ export namespace InspectTokensNLS {
}
export namespace GoToLineNLS {
export const gotoLineLabelValidLineAndColumn = nls.localize('gotoLineLabelValidLineAndColumn', "Go to line {0} and character {1}");
export const gotoLineLabelValidLine = nls.localize('gotoLineLabelValidLine', "Go to line {0}");
export const gotoLineLabelEmptyWithLineLimit = nls.localize('gotoLineLabelEmptyWithLineLimit', "Type a line number between 1 and {0} to navigate to");
export const gotoLineLabelEmptyWithLineAndColumnLimit = nls.localize('gotoLineLabelEmptyWithLineAndColumnLimit', "Type a character between 1 and {0} to navigate to");
export const gotoLineAriaLabel = nls.localize('gotoLineAriaLabel', "Current Line: {0}. Go to line {1}.");
export const gotoLineActionInput = nls.localize('gotoLineActionInput', "Type a line number, followed by an optional colon and a character number to navigate to");
export const gotoLineActionLabel = nls.localize('gotoLineActionLabel', "Go to Line...");
}
@@ -50,27 +44,13 @@ export namespace QuickHelpNLS {
}
export namespace QuickCommandNLS {
export const ariaLabelEntryWithKey = nls.localize('ariaLabelEntryWithKey', "{0}, {1}, commands");
export const ariaLabelEntry = nls.localize('ariaLabelEntry', "{0}, commands");
export const quickCommandActionInput = nls.localize('quickCommandActionInput', "Type the name of an action you want to execute");
export const quickCommandActionLabel = nls.localize('quickCommandActionLabel', "Command Palette");
export const quickCommandHelp = nls.localize('quickCommandActionHelp', "Show And Run Commands");
}
export namespace QuickOutlineNLS {
export const entryAriaLabel = nls.localize('entryAriaLabel', "{0}, symbols");
export const quickOutlineActionInput = nls.localize('quickOutlineActionInput', "Type the name of an identifier you wish to navigate to");
export const quickOutlineActionLabel = nls.localize('quickOutlineActionLabel', "Go to Symbol...");
export const _symbols_ = nls.localize('symbols', "symbols ({0})");
export const _modules_ = nls.localize('modules', "modules ({0})");
export const _class_ = nls.localize('class', "classes ({0})");
export const _interface_ = nls.localize('interface', "interfaces ({0})");
export const _method_ = nls.localize('method', "methods ({0})");
export const _function_ = nls.localize('function', "functions ({0})");
export const _property_ = nls.localize('property', "properties ({0})");
export const _variable_ = nls.localize('variable', "variables ({0})");
export const _variable2_ = nls.localize('variable2', "variables ({0})");
export const _constructor_ = nls.localize('_constructor', "constructors ({0})");
export const _call_ = nls.localize('call', "calls ({0})");
export const quickOutlineByCategoryActionLabel = nls.localize('quickOutlineByCategoryActionLabel', "Go to Symbol by Category...");
}
export namespace StandaloneCodeEditorNLS {
@@ -42,8 +42,8 @@ class MoveCaretLeftAction extends MoveCaretAction {
constructor() {
super(true, {
id: 'editor.action.moveCarretLeftAction',
label: nls.localize('caret.moveLeft', "Move Caret Left"),
alias: 'Move Caret Left',
label: nls.localize('caret.moveLeft', "Move Selected Text Left"),
alias: 'Move Selected Text Left',
precondition: EditorContextKeys.writable
});
}
@@ -53,8 +53,8 @@ class MoveCaretRightAction extends MoveCaretAction {
constructor() {
super(false, {
id: 'editor.action.moveCarretRightAction',
label: nls.localize('caret.moveRight', "Move Caret Right"),
alias: 'Move Caret Right',
label: nls.localize('caret.moveRight', "Move Selected Text Right"),
alias: 'Move Selected Text Right',
precondition: EditorContextKeys.writable
});
}
@@ -419,7 +419,7 @@ registerEditorAction(class ShowLensesInCurrentLine extends EditorAction {
super({
id: 'codelens.showLensesInCurrentLine',
precondition: EditorContextKeys.hasCodeLensProvider,
label: localize('showLensOnLine', "Show Code Lens Command For Current Line"),
label: localize('showLensOnLine', "Show Code Lens Commands For Current Line"),
alias: 'Show Code Lens Commands For Current Line',
});
}
@@ -0,0 +1,49 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AbstractCommandsQuickAccessProvider, ICommandQuickPick, ICommandsQuickAccessOptions } from 'vs/platform/quickinput/browser/commandsQuickAccess';
import { IEditor } from 'vs/editor/common/editorCommon';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ICommandService } from 'vs/platform/commands/common/commands';
export abstract class AbstractEditorCommandsQuickAccessProvider extends AbstractCommandsQuickAccessProvider {
constructor(
options: ICommandsQuickAccessOptions,
instantiationService: IInstantiationService,
keybindingService: IKeybindingService,
commandService: ICommandService,
telemetryService: ITelemetryService,
notificationService: INotificationService
) {
super(options, instantiationService, keybindingService, commandService, telemetryService, notificationService);
}
/**
* Subclasses to provide the current active editor control.
*/
protected abstract activeTextEditorControl: IEditor | undefined;
protected getCodeEditorCommandPicks(): ICommandQuickPick[] {
const activeTextEditorControl = this.activeTextEditorControl;
if (!activeTextEditorControl) {
return [];
}
const editorCommandPicks: ICommandQuickPick[] = [];
for (const editorAction of activeTextEditorControl.getSupportedActions()) {
editorCommandPicks.push({
commandId: editorAction.id,
commandAlias: editorAction.alias,
label: editorAction.label || editorAction.id,
});
}
return editorCommandPicks;
}
}
@@ -0,0 +1,192 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IQuickAccessProvider } from 'vs/platform/quickinput/common/quickAccess';
import { IEditor, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon';
import { IModelDeltaDecoration, OverviewRulerLane, ITextModel } from 'vs/editor/common/model';
import { IRange } from 'vs/editor/common/core/range';
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
import { overviewRulerRangeHighlight } from 'vs/editor/common/view/editorColorRegistry';
import { IQuickPick, IQuickPickItem, IKeyMods } from 'vs/platform/quickinput/common/quickInput';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IDisposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event';
import { isDiffEditor } from 'vs/editor/browser/editorBrowser';
import { withNullAsUndefined } from 'vs/base/common/types';
import { once } from 'vs/base/common/functional';
interface IEditorLineDecoration {
rangeHighlightId: string;
overviewRulerDecorationId: string;
}
/**
* A reusable quick access provider for the editor with support
* for adding decorations for navigating in the currently active file
* (for example "Go to line", "Go to symbol").
*/
export abstract class AbstractEditorNavigationQuickAccessProvider implements IQuickAccessProvider {
//#region Provider methods
provide(picker: IQuickPick<IQuickPickItem>, token: CancellationToken): IDisposable {
const disposables = new DisposableStore();
// Disable filtering & sorting, we control the results
picker.matchOnLabel = picker.matchOnDescription = picker.matchOnDetail = picker.sortByLabel = false;
// Provide based on current active editor
let pickerDisposable = this.doProvide(picker, token);
disposables.add(toDisposable(() => pickerDisposable.dispose()));
// Re-create whenever the active editor changes
disposables.add(this.onDidActiveTextEditorControlChange(() => {
pickerDisposable.dispose();
pickerDisposable = this.doProvide(picker, token);
}));
return disposables;
}
private doProvide(picker: IQuickPick<IQuickPickItem>, token: CancellationToken): IDisposable {
const disposables = new DisposableStore();
// With text control
const editor = this.activeTextEditorControl;
if (editor && this.canProvideWithTextEditor(editor)) {
// Restore any view state if this picker was closed
// without actually going to a line
const lastKnownEditorViewState = withNullAsUndefined(editor.saveViewState());
once(token.onCancellationRequested)(() => {
if (lastKnownEditorViewState) {
editor.restoreViewState(lastKnownEditorViewState);
}
});
// Clean up decorations on dispose
disposables.add(toDisposable(() => this.clearDecorations(editor)));
// Ask subclass for entries
disposables.add(this.provideWithTextEditor(editor, picker, token));
}
// Without text control
else {
disposables.add(this.provideWithoutTextEditor(picker, token));
}
return disposables;
}
/**
* Subclasses to implement if they can operate on the text editor.
*/
protected canProvideWithTextEditor(editor: IEditor): boolean {
return true;
}
/**
* Subclasses to implement to provide picks for the picker when an editor is active.
*/
protected abstract provideWithTextEditor(editor: IEditor, picker: IQuickPick<IQuickPickItem>, token: CancellationToken): IDisposable;
/**
* Subclasses to implement to provide picks for the picker when no editor is active.
*/
protected abstract provideWithoutTextEditor(picker: IQuickPick<IQuickPickItem>, token: CancellationToken): IDisposable;
protected gotoLocation(editor: IEditor, range: IRange, keyMods: IKeyMods, forceSideBySide?: boolean): void {
editor.setSelection(range);
editor.revealRangeInCenter(range, ScrollType.Smooth);
editor.focus();
}
protected getModel(editor: IEditor | IDiffEditor): ITextModel | undefined {
return isDiffEditor(editor) ?
editor.getModel()?.modified :
editor.getModel() as ITextModel;
}
//#endregion
//#region Editor access
/**
* Subclasses to provide an event when the active editor control changes.
*/
protected abstract readonly onDidActiveTextEditorControlChange: Event<void>;
/**
* Subclasses to provide the current active editor control.
*/
protected abstract activeTextEditorControl: IEditor | undefined;
//#endregion
//#region Decorations Utils
private rangeHighlightDecorationId: IEditorLineDecoration | undefined = undefined;
protected addDecorations(editor: IEditor, range: IRange): void {
editor.changeDecorations(changeAccessor => {
// Reset old decorations if any
const deleteDecorations: string[] = [];
if (this.rangeHighlightDecorationId) {
deleteDecorations.push(this.rangeHighlightDecorationId.overviewRulerDecorationId);
deleteDecorations.push(this.rangeHighlightDecorationId.rangeHighlightId);
this.rangeHighlightDecorationId = undefined;
}
// Add new decorations for the range
const newDecorations: IModelDeltaDecoration[] = [
// highlight the entire line on the range
{
range,
options: {
className: 'rangeHighlight',
isWholeLine: true
}
},
// also add overview ruler highlight
{
range,
options: {
overviewRuler: {
color: themeColorFromId(overviewRulerRangeHighlight),
position: OverviewRulerLane.Full
}
}
}
];
const [rangeHighlightId, overviewRulerDecorationId] = changeAccessor.deltaDecorations(deleteDecorations, newDecorations);
this.rangeHighlightDecorationId = { rangeHighlightId, overviewRulerDecorationId };
});
}
protected clearDecorations(editor: IEditor): void {
const rangeHighlightDecorationId = this.rangeHighlightDecorationId;
if (rangeHighlightDecorationId) {
editor.changeDecorations(changeAccessor => {
changeAccessor.deltaDecorations([
rangeHighlightDecorationId.overviewRulerDecorationId,
rangeHighlightDecorationId.rangeHighlightId
], []);
});
this.rangeHighlightDecorationId = undefined;
}
}
//#endregion
}
@@ -4,74 +4,32 @@
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { IQuickPick, IQuickPickItem, IKeyMods } from 'vs/platform/quickinput/common/quickInput';
import { IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { CancellationToken } from 'vs/base/common/cancellation';
import { DisposableStore, toDisposable, IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { once } from 'vs/base/common/functional';
import { IEditor, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
import { isDiffEditor } from 'vs/editor/browser/editorBrowser';
import { DisposableStore, IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { IEditor, ScrollType } from 'vs/editor/common/editorCommon';
import { IRange } from 'vs/editor/common/core/range';
import { withNullAsUndefined } from 'vs/base/common/types';
import { AbstractEditorQuickAccessProvider } from 'vs/editor/contrib/quickAccess/quickAccess';
import { AbstractEditorNavigationQuickAccessProvider } from 'vs/editor/contrib/quickAccess/editorNavigationQuickAccess';
import { IPosition } from 'vs/editor/common/core/position';
export const GOTO_LINE_PREFIX = ':';
interface IGotoLineQuickPickItem extends IQuickPickItem, Partial<IPosition> { }
export abstract class AbstractGotoLineQuickAccessProvider extends AbstractEditorQuickAccessProvider {
export abstract class AbstractGotoLineQuickAccessProvider extends AbstractEditorNavigationQuickAccessProvider {
provide(picker: IQuickPick<IGotoLineQuickPickItem>, token: CancellationToken): IDisposable {
const disposables = new DisposableStore();
static PREFIX = ':';
// Disable filtering & sorting, we control the results
picker.matchOnLabel = picker.matchOnDescription = picker.matchOnDetail = picker.sortByLabel = false;
protected provideWithoutTextEditor(picker: IQuickPick<IGotoLineQuickPickItem>): IDisposable {
const label = localize('cannotRunGotoLine', "Open a text editor first to go to a line.");
// Provide based on current active editor
let pickerDisposable = this.doProvide(picker, token);
disposables.add(toDisposable(() => pickerDisposable.dispose()));
// Re-create whenever the active editor changes
disposables.add(this.onDidActiveTextEditorControlChange(() => {
pickerDisposable.dispose();
pickerDisposable = this.doProvide(picker, token);
}));
return disposables;
}
private doProvide(picker: IQuickPick<IGotoLineQuickPickItem>, token: CancellationToken): IDisposable {
// With text control
if (this.activeTextEditorControl) {
return this.doProvideWithTextEditor(this.activeTextEditorControl, picker, token);
}
// Without text control
return this.doProvideWithoutTextEditor(picker);
}
private doProvideWithoutTextEditor(picker: IQuickPick<IGotoLineQuickPickItem>): IDisposable {
const label = localize('cannotRunGotoLine', "Open a text file first to go to a line.");
picker.items = [{ label }];
picker.ariaLabel = label;
return Disposable.None;
}
private doProvideWithTextEditor(editor: IEditor, picker: IQuickPick<IGotoLineQuickPickItem>, token: CancellationToken): IDisposable {
protected provideWithTextEditor(editor: IEditor, picker: IQuickPick<IGotoLineQuickPickItem>, token: CancellationToken): IDisposable {
const disposables = new DisposableStore();
// Restore any view state if this picker was closed
// without actually going to a line
const lastKnownEditorViewState = withNullAsUndefined(editor.saveViewState());
once(token.onCancellationRequested)(() => {
if (lastKnownEditorViewState) {
editor.restoreViewState(lastKnownEditorViewState);
}
});
// Goto line once picked
disposables.add(picker.onDidAccept(() => {
const [item] = picker.selectedItems;
@@ -80,7 +38,7 @@ export abstract class AbstractGotoLineQuickAccessProvider extends AbstractEditor
return;
}
this.gotoLine(editor, this.toRange(item.lineNumber, item.column), picker.keyMods);
this.gotoLocation(editor, this.toRange(item.lineNumber, item.column), picker.keyMods);
picker.hide();
}
@@ -88,7 +46,7 @@ export abstract class AbstractGotoLineQuickAccessProvider extends AbstractEditor
// React to picker changes
const updatePickerAndEditor = () => {
const position = this.parsePosition(editor, picker.value.trim().substr(GOTO_LINE_PREFIX.length));
const position = this.parsePosition(editor, picker.value.trim().substr(AbstractGotoLineQuickAccessProvider.PREFIX.length));
const label = this.getPickLabel(editor, position.lineNumber, position.column);
// Picker
@@ -117,9 +75,6 @@ export abstract class AbstractGotoLineQuickAccessProvider extends AbstractEditor
updatePickerAndEditor();
disposables.add(picker.onDidChangeValue(() => updatePickerAndEditor()));
// Clean up decorations on dispose
disposables.add(toDisposable(() => this.clearDecorations(editor)));
return disposables;
}
@@ -191,16 +146,4 @@ export abstract class AbstractGotoLineQuickAccessProvider extends AbstractEditor
private lineCount(editor: IEditor): number {
return this.getModel(editor)?.getLineCount() ?? 0;
}
private getModel(editor: IEditor | IDiffEditor): ITextModel | undefined {
return isDiffEditor(editor) ?
editor.getModel()?.modified :
editor.getModel() as ITextModel;
}
protected gotoLine(editor: IEditor, range: IRange, keyMods: IKeyMods): void {
editor.setSelection(range);
editor.revealRangeInCenter(range, ScrollType.Smooth);
editor.focus();
}
}
@@ -0,0 +1,420 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { IQuickPick, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { DisposableStore, IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { IEditor, ScrollType } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
import { IRange, Range } from 'vs/editor/common/core/range';
import { AbstractEditorNavigationQuickAccessProvider } from 'vs/editor/contrib/quickAccess/editorNavigationQuickAccess';
import { DocumentSymbol, SymbolKinds, SymbolTag, DocumentSymbolProviderRegistry, SymbolKind } from 'vs/editor/common/modes';
import { OutlineModel, OutlineElement } from 'vs/editor/contrib/documentSymbols/outlineModel';
import { values } from 'vs/base/common/collections';
import { trim, format } from 'vs/base/common/strings';
import { fuzzyScore, FuzzyScore, createMatches } from 'vs/base/common/filters';
interface IGotoSymbolQuickPickItem extends IQuickPickItem {
kind: SymbolKind,
index: number,
score?: FuzzyScore;
range?: { decoration: IRange, selection: IRange },
}
export interface IGotoSymbolQuickAccessProviderOptions {
openSideBySideDirection: () => undefined | 'right' | 'down'
}
export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEditorNavigationQuickAccessProvider {
static PREFIX = '@';
static SCOPE_PREFIX = ':';
static PREFIX_BY_CATEGORY = `${AbstractGotoSymbolQuickAccessProvider.PREFIX}${AbstractGotoSymbolQuickAccessProvider.SCOPE_PREFIX}`;
constructor(private options?: IGotoSymbolQuickAccessProviderOptions) {
super();
}
protected provideWithoutTextEditor(picker: IQuickPick<IGotoSymbolQuickPickItem>): IDisposable {
const label = localize('cannotRunGotoSymbolWithoutEditor', "Open a text editor first to go to a symbol.");
picker.items = [{ label, index: 0, kind: SymbolKind.String }];
picker.ariaLabel = label;
return Disposable.None;
}
protected provideWithTextEditor(editor: IEditor, picker: IQuickPick<IGotoSymbolQuickPickItem>, token: CancellationToken): IDisposable {
const model = this.getModel(editor);
if (!model) {
return Disposable.None;
}
// Provide symbols from model if available in registry
if (DocumentSymbolProviderRegistry.has(model)) {
return this.doProvideWithEditorSymbols(editor, model, picker, token);
}
// Otherwise show an entry for a model without registry
// But give a chance to resolve the symbols at a later
// point if possible
return this.doProvideWithoutEditorSymbols(editor, model, picker, token);
}
private doProvideWithoutEditorSymbols(editor: IEditor, model: ITextModel, picker: IQuickPick<IGotoSymbolQuickPickItem>, token: CancellationToken): IDisposable {
const disposables = new DisposableStore();
// Generic pick for not having any symbol information
const label = localize('cannotRunGotoSymbolWithoutSymbolProvider', "Open a text editor with symbol information first to go to a symbol.");
picker.items = [{ label, index: 0, kind: SymbolKind.String }];
picker.ariaLabel = label;
// Listen to changes to the registry and see if eventually
// we do get symbols. This can happen if the picker is opened
// very early after the model has loaded but before the
// language registry is ready.
// https://github.com/microsoft/vscode/issues/70607
const symbolProviderListener = disposables.add(DocumentSymbolProviderRegistry.onDidChange(() => {
if (DocumentSymbolProviderRegistry.has(model)) {
symbolProviderListener.dispose();
disposables.add(this.doProvideWithEditorSymbols(editor, model, picker, token));
}
}));
return disposables;
}
private doProvideWithEditorSymbols(editor: IEditor, model: ITextModel, picker: IQuickPick<IGotoSymbolQuickPickItem>, token: CancellationToken): IDisposable {
const disposables = new DisposableStore();
// Goto symbol once picked
disposables.add(picker.onDidAccept(() => {
const [item] = picker.selectedItems;
if (item && item.range) {
this.gotoLocation(editor, item.range.selection, picker.keyMods);
picker.hide();
}
}));
// Goto symbol side by side if enabled
disposables.add(picker.onDidTriggerItemButton(({ item }) => {
if (item && item.range) {
this.gotoLocation(editor, item.range.selection, picker.keyMods, true);
picker.hide();
}
}));
// Resolve symbols from document once and reuse this
// request for all filtering and typing then on
const symbolsPromise = this.getDocumentSymbols(model, true, token);
// Set initial picks and update on type
let picksCts: CancellationTokenSource | undefined = undefined;
const updatePickerItems = async () => {
// Cancel any previous ask for picks and busy
picksCts?.dispose(true);
picker.busy = false;
// Create new cancellation source for this run
picksCts = new CancellationTokenSource(token);
// Collect symbol picks
picker.busy = true;
try {
const items = await this.getSymbolPicks(symbolsPromise, picker.value.substr(AbstractGotoSymbolQuickAccessProvider.PREFIX.length).trim(), picksCts.token);
if (token.isCancellationRequested) {
return;
}
picker.items = items;
} finally {
if (!token.isCancellationRequested) {
picker.busy = false;
}
}
};
disposables.add(picker.onDidChangeValue(() => updatePickerItems()));
updatePickerItems();
// Reveal and decorate when active item changes
// However, ignore the very first event so that
// opening the picker is not immediately revealing
// and decorating the first entry.
let ignoreFirstActiveEvent = true;
disposables.add(picker.onDidChangeActive(() => {
const [item] = picker.activeItems;
if (item && item.range) {
if (ignoreFirstActiveEvent) {
ignoreFirstActiveEvent = false;
return;
}
// Reveal
editor.revealRangeInCenter(item.range.selection, ScrollType.Smooth);
// Decorate
this.addDecorations(editor, item.range.decoration);
}
}));
return disposables;
}
private async getSymbolPicks(symbolsPromise: Promise<DocumentSymbol[]>, filter: string, token: CancellationToken): Promise<Array<IGotoSymbolQuickPickItem | IQuickPickSeparator>> {
const symbols = await symbolsPromise;
if (token.isCancellationRequested) {
return [];
}
// Normalize filter
const filterBySymbolKind = filter.indexOf(AbstractGotoSymbolQuickAccessProvider.SCOPE_PREFIX) === 0;
const filterPos = filterBySymbolKind ? 1 : 0;
const [symbolFilter, containerFilter] = filter.split(' ') as [string, string | undefined];
const symbolFilterLow = symbolFilter.toLowerCase();
const containerFilterLow = containerFilter?.toLowerCase();
// Convert to symbol picks and apply filtering
const filteredSymbolPicks: IGotoSymbolQuickPickItem[] = [];
for (let index = 0; index < symbols.length; index++) {
const symbol = symbols[index];
const symbolLabel = trim(symbol.name);
const containerLabel = symbol.containerName;
let symbolScore: FuzzyScore | undefined = undefined;
let containerScore: FuzzyScore | undefined = undefined;
let includeSymbol = true;
if (filter.length > filterPos) {
// Score by symbol
symbolScore = fuzzyScore(symbolFilter, symbolFilterLow, filterPos, symbolLabel, symbolLabel.toLowerCase(), 0, true);
includeSymbol = !!symbolScore;
// Score by container if specified
if (includeSymbol && containerFilter && containerFilterLow) {
if (containerLabel) {
containerScore = fuzzyScore(containerFilter, containerFilterLow, filterPos, containerLabel, containerLabel.toLowerCase(), 0, true);
}
includeSymbol = !!containerScore;
}
}
if (includeSymbol) {
const symbolLabelWithIcon = `$(symbol-${SymbolKinds.toString(symbol.kind) || 'property'}) ${symbolLabel}`;
const deprecated = symbol.tags && symbol.tags.indexOf(SymbolTag.Deprecated) >= 0;
filteredSymbolPicks.push({
index,
kind: symbol.kind,
score: symbolScore,
label: symbolLabelWithIcon,
ariaLabel: localize('symbolsAriaLabel', "{0}, symbols picker", symbolLabel),
description: containerLabel,
highlights: deprecated ? undefined : {
label: createMatches(symbolScore, symbolLabelWithIcon.length - symbolLabel.length /* Readjust matches to account for codicons in label */),
description: createMatches(containerScore)
},
range: {
selection: Range.collapseToStart(symbol.selectionRange),
decoration: symbol.range
},
strikethrough: deprecated,
buttons: (() => {
const openSideBySideDirection = this.options?.openSideBySideDirection();
if (!openSideBySideDirection) {
return undefined;
}
return [
{
iconClass: openSideBySideDirection === 'right' ? 'codicon-split-horizontal' : 'codicon-split-vertical',
tooltip: openSideBySideDirection === 'right' ? localize('openToSide', "Open to the Side") : localize('openToBottom', "Open to the Bottom")
}
];
})()
});
}
}
// Sort by score
const sortedFilteredSymbolPicks = filteredSymbolPicks.sort((symbolA, symbolB) => filterBySymbolKind ?
this.compareByKindAndScore(symbolA, symbolB) :
this.compareByScore(symbolA, symbolB)
);
// Add separator for types
// - @ only total number of symbols
// - @: grouped by symbol kind
let symbolPicks: Array<IGotoSymbolQuickPickItem | IQuickPickSeparator> = [];
if (filterBySymbolKind) {
let lastSymbolKind: SymbolKind | undefined = undefined;
let lastSeparator: IQuickPickSeparator | undefined = undefined;
let lastSymbolKindCounter = 0;
function updateLastSeparatorLabel(): void {
if (lastSeparator && typeof lastSymbolKind === 'number' && lastSymbolKindCounter > 0) {
lastSeparator.label = format(NLS_SYMBOL_KIND_CACHE[lastSymbolKind] || FALLBACK_NLS_SYMBOL_KIND, lastSymbolKindCounter);
}
}
for (const symbolPick of sortedFilteredSymbolPicks) {
// Found new kind
if (lastSymbolKind !== symbolPick.kind) {
// Update last separator with number of symbols we found for kind
updateLastSeparatorLabel();
lastSymbolKind = symbolPick.kind;
lastSymbolKindCounter = 1;
// Add new separator for new kind
lastSeparator = { type: 'separator' };
symbolPicks.push(lastSeparator);
}
// Existing kind, keep counting
else {
lastSymbolKindCounter++;
}
// Add to final result
symbolPicks.push(symbolPick);
}
// Update last separator with number of symbols we found for kind
updateLastSeparatorLabel();
} else {
symbolPicks = [
{ label: localize('symbols', "symbols ({0})", filteredSymbolPicks.length), type: 'separator' },
...sortedFilteredSymbolPicks
];
}
return symbolPicks;
}
private compareByScore(symbolA: IGotoSymbolQuickPickItem, symbolB: IGotoSymbolQuickPickItem): number {
if (!symbolA.score && symbolB.score) {
return 1;
} else if (symbolA.score && !symbolB.score) {
return -1;
}
if (symbolA.score && symbolB.score) {
if (symbolA.score[0] > symbolB.score[0]) {
return -1;
} else if (symbolA.score[0] < symbolB.score[0]) {
return 1;
}
}
if (symbolA.index < symbolB.index) {
return -1;
} else if (symbolA.index > symbolB.index) {
return 1;
}
return 0;
}
private compareByKindAndScore(symbolA: IGotoSymbolQuickPickItem, symbolB: IGotoSymbolQuickPickItem): number {
const kindA = NLS_SYMBOL_KIND_CACHE[symbolA.kind] || FALLBACK_NLS_SYMBOL_KIND;
const kindB = NLS_SYMBOL_KIND_CACHE[symbolB.kind] || FALLBACK_NLS_SYMBOL_KIND;
// Sort by type first if scoped search
const result = kindA.localeCompare(kindB);
if (result === 0) {
return this.compareByScore(symbolA, symbolB);
}
return result;
}
private async getDocumentSymbols(document: ITextModel, flatten: boolean, token: CancellationToken): Promise<DocumentSymbol[]> {
const model = await OutlineModel.create(document, token);
if (token.isCancellationRequested) {
return [];
}
const roots: DocumentSymbol[] = [];
for (const child of values(model.children)) {
if (child instanceof OutlineElement) {
roots.push(child.symbol);
} else {
roots.push(...values(child.children).map(child => child.symbol));
}
}
let flatEntries: DocumentSymbol[] = [];
if (flatten) {
this.flattenDocumentSymbols(flatEntries, roots, '');
} else {
flatEntries = roots;
}
return flatEntries.sort((symbolA, symbolB) => Range.compareRangesUsingStarts(symbolA.range, symbolB.range));
}
private flattenDocumentSymbols(bucket: DocumentSymbol[], entries: DocumentSymbol[], overrideContainerLabel: string): void {
for (const entry of entries) {
bucket.push({
kind: entry.kind,
tags: entry.tags,
name: entry.name,
detail: entry.detail,
containerName: entry.containerName || overrideContainerLabel,
range: entry.range,
selectionRange: entry.selectionRange,
children: undefined, // we flatten it...
});
// Recurse over children
if (entry.children) {
this.flattenDocumentSymbols(bucket, entry.children, entry.name);
}
}
}
}
// #region NLS Helpers
const FALLBACK_NLS_SYMBOL_KIND = localize('property', "properties ({0})");
const NLS_SYMBOL_KIND_CACHE: { [type: number]: string } = {
[SymbolKind.Method]: localize('method', "methods ({0})"),
[SymbolKind.Function]: localize('function', "functions ({0})"),
[SymbolKind.Constructor]: localize('_constructor', "constructors ({0})"),
[SymbolKind.Variable]: localize('variable', "variables ({0})"),
[SymbolKind.Class]: localize('class', "classes ({0})"),
[SymbolKind.Struct]: localize('struct', "structs ({0})"),
[SymbolKind.Event]: localize('event', "events ({0})"),
[SymbolKind.Operator]: localize('operator', "operators ({0})"),
[SymbolKind.Interface]: localize('interface', "interfaces ({0})"),
[SymbolKind.Namespace]: localize('namespace', "namespaces ({0})"),
[SymbolKind.Package]: localize('package', "packages ({0})"),
[SymbolKind.TypeParameter]: localize('typeParameter', "type parameters ({0})"),
[SymbolKind.Module]: localize('modules', "modules ({0})"),
[SymbolKind.Property]: localize('property', "properties ({0})"),
[SymbolKind.Enum]: localize('enum', "enumerations ({0})"),
[SymbolKind.EnumMember]: localize('enumMember', "enumeration members ({0})"),
[SymbolKind.String]: localize('string', "strings ({0})"),
[SymbolKind.File]: localize('file', "files ({0})"),
[SymbolKind.Array]: localize('array', "arrays ({0})"),
[SymbolKind.Number]: localize('number', "numbers ({0})"),
[SymbolKind.Boolean]: localize('boolean', "booleans ({0})"),
[SymbolKind.Object]: localize('object', "objects ({0})"),
[SymbolKind.Key]: localize('key', "keys ({0})"),
[SymbolKind.Field]: localize('field', "fields ({0})"),
[SymbolKind.Constant]: localize('constant', "constants ({0})")
};
//#endregion
@@ -1,104 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IQuickAccessProvider } from 'vs/platform/quickinput/common/quickAccess';
import { IEditor } from 'vs/editor/common/editorCommon';
import { IModelDeltaDecoration, OverviewRulerLane } from 'vs/editor/common/model';
import { IRange } from 'vs/editor/common/core/range';
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
import { overviewRulerRangeHighlight } from 'vs/editor/common/view/editorColorRegistry';
import { IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Event } from 'vs/base/common/event';
interface IEditorLineDecoration {
rangeHighlightId: string;
overviewRulerDecorationId: string;
}
/**
* A reusable quick access provider for the editor with support for adding decorations.
*/
export abstract class AbstractEditorQuickAccessProvider implements IQuickAccessProvider {
/**
* Subclasses to provide an event when the active editor control changes.
*/
abstract readonly onDidActiveTextEditorControlChange: Event<void>;
/**
* Subclasses to provide the current active editor control.
*/
abstract activeTextEditorControl: IEditor | undefined;
/**
* Subclasses to implement the quick access picker.
*/
abstract provide(picker: IQuickPick<IQuickPickItem>, token: CancellationToken): IDisposable;
//#region Decorations Utils
private rangeHighlightDecorationId: IEditorLineDecoration | undefined = undefined;
protected addDecorations(editor: IEditor, range: IRange): void {
editor.changeDecorations(changeAccessor => {
// Reset old decorations if any
const deleteDecorations: string[] = [];
if (this.rangeHighlightDecorationId) {
deleteDecorations.push(this.rangeHighlightDecorationId.overviewRulerDecorationId);
deleteDecorations.push(this.rangeHighlightDecorationId.rangeHighlightId);
this.rangeHighlightDecorationId = undefined;
}
// Add new decorations for the range
const newDecorations: IModelDeltaDecoration[] = [
// highlight the entire line on the range
{
range,
options: {
className: 'rangeHighlight',
isWholeLine: true
}
},
// also add overview ruler highlight
{
range,
options: {
overviewRuler: {
color: themeColorFromId(overviewRulerRangeHighlight),
position: OverviewRulerLane.Full
}
}
}
];
const [rangeHighlightId, overviewRulerDecorationId] = changeAccessor.deltaDecorations(deleteDecorations, newDecorations);
this.rangeHighlightDecorationId = { rangeHighlightId, overviewRulerDecorationId };
});
}
protected clearDecorations(editor: IEditor): void {
const rangeHighlightDecorationId = this.rangeHighlightDecorationId;
if (rangeHighlightDecorationId) {
editor.changeDecorations(changeAccessor => {
changeAccessor.deltaDecorations([
rangeHighlightDecorationId.overviewRulerDecorationId,
rangeHighlightDecorationId.rangeHighlightId
], []);
});
this.rangeHighlightDecorationId = undefined;
}
}
//#endregion
}
+2 -3
View File
@@ -7,11 +7,10 @@ import 'vs/editor/editor.all';
import 'vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp';
import 'vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard';
import 'vs/editor/standalone/browser/inspectTokens/inspectTokens';
import 'vs/editor/standalone/browser/quickOpen/gotoLine';
import 'vs/editor/standalone/browser/quickOpen/quickCommand';
import 'vs/editor/standalone/browser/quickOpen/quickOutline';
import 'vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess';
import 'vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess';
import 'vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess';
import 'vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess';
import 'vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch';
import 'vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast';
@@ -330,7 +330,11 @@ class ShowAccessibilityHelpAction extends EditorAction {
kbOpts: {
kbExpr: EditorContextKeys.focus,
primary: KeyMod.Alt | KeyCode.F1,
weight: KeybindingWeight.EditorContrib
weight: KeybindingWeight.EditorContrib,
linux: {
primary: KeyMod.Alt | KeyMod.Shift | KeyCode.F1,
secondary: [KeyMod.Alt | KeyCode.F1]
}
}
});
}
@@ -0,0 +1,76 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Registry } from 'vs/platform/registry/common/platform';
import { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';
import { QuickCommandNLS } from 'vs/editor/common/standaloneStrings';
import { ICommandQuickPick } from 'vs/platform/quickinput/browser/commandsQuickAccess';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { AbstractEditorCommandsQuickAccessProvider } from 'vs/editor/contrib/quickAccess/commandsQuickAccess';
import { IEditor } from 'vs/editor/common/editorCommon';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { EditorAction, registerEditorAction } from 'vs/editor/browser/editorExtensions';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { KeyCode } from 'vs/base/common/keyCodes';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
export class StandaloneCommandsQuickAccessProvider extends AbstractEditorCommandsQuickAccessProvider {
protected get activeTextEditorControl(): IEditor | undefined { return withNullAsUndefined(this.codeEditorService.getFocusedCodeEditor()); }
constructor(
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService private readonly codeEditorService: ICodeEditorService,
@IKeybindingService keybindingService: IKeybindingService,
@ICommandService commandService: ICommandService,
@ITelemetryService telemetryService: ITelemetryService,
@INotificationService notificationService: INotificationService
) {
super({ showAlias: false }, instantiationService, keybindingService, commandService, telemetryService, notificationService);
}
protected async getCommandPicks(): Promise<Array<ICommandQuickPick>> {
return this.getCodeEditorCommandPicks();
}
}
Registry.as<IQuickAccessRegistry>(Extensions.Quickaccess).registerQuickAccessProvider({
ctor: StandaloneCommandsQuickAccessProvider,
prefix: StandaloneCommandsQuickAccessProvider.PREFIX,
helpEntries: [{ description: QuickCommandNLS.quickCommandHelp, needsEditor: true }]
});
export class GotoLineAction extends EditorAction {
constructor() {
super({
id: 'editor.action.quickCommand',
label: QuickCommandNLS.quickCommandActionLabel,
alias: 'Command Palette',
precondition: undefined,
kbOpts: {
kbExpr: EditorContextKeys.focus,
primary: KeyCode.F1,
weight: KeybindingWeight.EditorContrib
},
contextMenuOpts: {
group: 'z_commands',
order: 1
}
});
}
run(accessor: ServicesAccessor): void {
accessor.get(IQuickInputService).quickAccess.show(StandaloneCommandsQuickAccessProvider.PREFIX);
}
}
registerEditorAction(GotoLineAction);
@@ -3,29 +3,58 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AbstractGotoLineQuickAccessProvider, GOTO_LINE_PREFIX } from 'vs/editor/contrib/quickAccess/gotoLine';
import { AbstractGotoLineQuickAccessProvider } from 'vs/editor/contrib/quickAccess/gotoLineQuickAccess';
import { Registry } from 'vs/platform/registry/common/platform';
import { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { withNullAsUndefined } from 'vs/base/common/types';
import { GoToLineNLS } from 'vs/editor/common/standaloneStrings';
import { Event } from 'vs/base/common/event';
import { EditorAction, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
export class StandaloneGotoLineQuickAccessProvider extends AbstractGotoLineQuickAccessProvider {
readonly onDidActiveTextEditorControlChange = Event.None;
protected readonly onDidActiveTextEditorControlChange = Event.None;
constructor(@ICodeEditorService private readonly editorService: ICodeEditorService) {
super();
}
get activeTextEditorControl() {
protected get activeTextEditorControl() {
return withNullAsUndefined(this.editorService.getFocusedCodeEditor());
}
}
Registry.as<IQuickAccessRegistry>(Extensions.Quickaccess).registerQuickAccessProvider({
ctor: StandaloneGotoLineQuickAccessProvider,
prefix: GOTO_LINE_PREFIX,
prefix: StandaloneGotoLineQuickAccessProvider.PREFIX,
helpEntries: [{ description: GoToLineNLS.gotoLineActionLabel, needsEditor: true }]
});
export class GotoLineAction extends EditorAction {
constructor() {
super({
id: 'editor.action.gotoLine',
label: GoToLineNLS.gotoLineActionLabel,
alias: 'Go to Line...',
precondition: undefined,
kbOpts: {
kbExpr: EditorContextKeys.focus,
primary: KeyMod.CtrlCmd | KeyCode.KEY_G,
mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_G },
weight: KeybindingWeight.EditorContrib
}
});
}
run(accessor: ServicesAccessor): void {
accessor.get(IQuickInputService).quickAccess.show(StandaloneGotoLineQuickAccessProvider.PREFIX);
}
}
registerEditorAction(GotoLineAction);
@@ -0,0 +1,67 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { AbstractGotoSymbolQuickAccessProvider } from 'vs/editor/contrib/quickAccess/gotoSymbolQuickAccess';
import { Registry } from 'vs/platform/registry/common/platform';
import { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { withNullAsUndefined } from 'vs/base/common/types';
import { QuickOutlineNLS } from 'vs/editor/common/standaloneStrings';
import { Event } from 'vs/base/common/event';
import { EditorAction, registerEditorAction } from 'vs/editor/browser/editorExtensions';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
export class StandaloneGotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccessProvider {
protected readonly onDidActiveTextEditorControlChange = Event.None;
constructor(@ICodeEditorService private readonly editorService: ICodeEditorService) {
super();
}
protected get activeTextEditorControl() {
return withNullAsUndefined(this.editorService.getFocusedCodeEditor());
}
}
Registry.as<IQuickAccessRegistry>(Extensions.Quickaccess).registerQuickAccessProvider({
ctor: StandaloneGotoSymbolQuickAccessProvider,
prefix: AbstractGotoSymbolQuickAccessProvider.PREFIX,
helpEntries: [
{ description: QuickOutlineNLS.quickOutlineActionLabel, prefix: AbstractGotoSymbolQuickAccessProvider.PREFIX, needsEditor: true },
{ description: QuickOutlineNLS.quickOutlineByCategoryActionLabel, prefix: AbstractGotoSymbolQuickAccessProvider.PREFIX_BY_CATEGORY, needsEditor: true }
]
});
export class GotoLineAction extends EditorAction {
constructor() {
super({
id: 'editor.action.quickOutline',
label: QuickOutlineNLS.quickOutlineActionLabel,
alias: 'Go to Symbol...',
precondition: EditorContextKeys.hasDocumentSymbolProvider,
kbOpts: {
kbExpr: EditorContextKeys.focus,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_O,
weight: KeybindingWeight.EditorContrib
},
contextMenuOpts: {
group: 'navigation',
order: 3
}
});
}
run(accessor: ServicesAccessor): void {
accessor.get(IQuickInputService).quickAccess.show(AbstractGotoSymbolQuickAccessProvider.PREFIX);
}
}
registerEditorAction(GotoLineAction);
@@ -8,8 +8,8 @@ import { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/
import { QuickHelpNLS } from 'vs/editor/common/standaloneStrings';
import { HelpQuickAccessProvider } from 'vs/platform/quickinput/browser/helpQuickAccess';
Registry.as<IQuickAccessRegistry>(Extensions.Quickaccess).defaultProvider = {
Registry.as<IQuickAccessRegistry>(Extensions.Quickaccess).registerQuickAccessProvider({
ctor: HelpQuickAccessProvider,
prefix: '',
helpEntries: [{ description: QuickHelpNLS.helpQuickAccessActionLabel, needsEditor: true }]
};
});
@@ -1,19 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-quick-open-widget .monaco-tree .monaco-tree-row .monaco-highlighted-label .highlight,
.monaco-quick-open-widget .monaco-list .monaco-list-row .monaco-highlighted-label .highlight {
color: #0066BF;
}
.vs-dark .monaco-quick-open-widget .monaco-tree .monaco-tree-row .monaco-highlighted-label .highlight,
.vs-dark .monaco-quick-open-widget .monaco-list .monaco-list-row .monaco-highlighted-label .highlight {
color: #0097fb;
}
.hc-black .monaco-quick-open-widget .monaco-tree .monaco-tree-row .monaco-highlighted-label .highlight,
.hc-black .monaco-quick-open-widget .monaco-list .monaco-list-row .monaco-highlighted-label .highlight {
color: #F38518;
}
@@ -1,172 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./editorQuickOpen';
import { QuickOpenModel } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { IAutoFocus } from 'vs/base/parts/quickopen/common/quickOpen';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorAction, IActionOptions, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { IEditorContribution, ScrollType, IEditor } from 'vs/editor/common/editorCommon';
import { IModelDeltaDecoration } from 'vs/editor/common/model';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { QuickOpenEditorWidget } from 'vs/editor/standalone/browser/quickOpen/quickOpenEditorWidget';
import { IThemeService } from 'vs/platform/theme/common/themeService';
export interface IQuickOpenControllerOpts {
inputAriaLabel: string;
getModel(value: string): QuickOpenModel;
getAutoFocus(searchValue: string): IAutoFocus;
}
export class QuickOpenController implements IEditorContribution, IDecorator {
public static readonly ID = 'editor.controller.quickOpenController';
public static get(editor: ICodeEditor): QuickOpenController {
return editor.getContribution<QuickOpenController>(QuickOpenController.ID);
}
private readonly editor: ICodeEditor;
private widget: QuickOpenEditorWidget | null = null;
private rangeHighlightDecorationId: string | null = null;
private lastKnownEditorSelection: Selection | null = null;
constructor(editor: ICodeEditor, @IThemeService private readonly themeService: IThemeService) {
this.editor = editor;
}
public dispose(): void {
// Dispose widget
if (this.widget) {
this.widget.destroy();
this.widget = null;
}
}
public run(opts: IQuickOpenControllerOpts): void {
if (this.widget) {
this.widget.destroy();
this.widget = null;
}
// Create goto line widget
let onClose = (canceled: boolean) => {
// Clear Highlight Decorations if present
this.clearDecorations();
// Restore selection if canceled
if (canceled && this.lastKnownEditorSelection) {
this.editor.setSelection(this.lastKnownEditorSelection);
this.editor.revealRangeInCenterIfOutsideViewport(this.lastKnownEditorSelection, ScrollType.Smooth);
}
this.lastKnownEditorSelection = null;
// Return focus to the editor if
// - focus is back on the <body> element because no other focusable element was clicked
// - a command was picked from the picker which indicates the editor should get focused
if (document.activeElement === document.body || !canceled) {
this.editor.focus();
}
};
this.widget = new QuickOpenEditorWidget(
this.editor,
() => onClose(false),
() => onClose(true),
(value: string) => {
this.widget!.setInput(opts.getModel(value), opts.getAutoFocus(value));
},
{
inputAriaLabel: opts.inputAriaLabel
},
this.themeService
);
// Remember selection to be able to restore on cancel
if (!this.lastKnownEditorSelection) {
this.lastKnownEditorSelection = this.editor.getSelection();
}
// Show
this.widget.show('');
}
private static readonly _RANGE_HIGHLIGHT_DECORATION = ModelDecorationOptions.register({
className: 'rangeHighlight',
isWholeLine: true
});
public decorateLine(range: Range, editor: ICodeEditor): void {
const oldDecorations: string[] = [];
if (this.rangeHighlightDecorationId) {
oldDecorations.push(this.rangeHighlightDecorationId);
this.rangeHighlightDecorationId = null;
}
const newDecorations: IModelDeltaDecoration[] = [
{
range: range,
options: QuickOpenController._RANGE_HIGHLIGHT_DECORATION
}
];
const decorations = editor.deltaDecorations(oldDecorations, newDecorations);
this.rangeHighlightDecorationId = decorations[0];
}
public clearDecorations(): void {
if (this.rangeHighlightDecorationId) {
this.editor.deltaDecorations([this.rangeHighlightDecorationId], []);
this.rangeHighlightDecorationId = null;
}
}
}
export interface IQuickOpenOpts {
/**
* provide the quick open model for the given search value.
*/
getModel(value: string): QuickOpenModel;
/**
* provide the quick open auto focus mode for the given search value.
*/
getAutoFocus(searchValue: string): IAutoFocus;
}
/**
* Base class for providing quick open in the editor.
*/
export abstract class BaseEditorQuickOpenAction extends EditorAction {
private readonly _inputAriaLabel: string;
constructor(inputAriaLabel: string, opts: IActionOptions) {
super(opts);
this._inputAriaLabel = inputAriaLabel;
}
protected getController(editor: ICodeEditor): QuickOpenController {
return QuickOpenController.get(editor);
}
protected _show(controller: QuickOpenController, opts: IQuickOpenOpts): void {
controller.run({
inputAriaLabel: this._inputAriaLabel,
getModel: (value: string): QuickOpenModel => opts.getModel(value),
getAutoFocus: (searchValue: string): IAutoFocus => opts.getAutoFocus(searchValue)
});
}
}
export interface IDecorator {
decorateLine(range: Range, editor: IEditor): void;
clearDecorations(): void;
}
registerEditorContribution(QuickOpenController.ID, QuickOpenController);
@@ -1,8 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-quick-open-widget {
font-size: 13px;
}
@@ -1,177 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./gotoLine';
import * as strings from 'vs/base/common/strings';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { QuickOpenEntry, QuickOpenModel } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { IAutoFocus, Mode, IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
import { ICodeEditor, IDiffEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { IEditor, ScrollType } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ITextModel } from 'vs/editor/common/model';
import { BaseEditorQuickOpenAction, IDecorator } from 'vs/editor/standalone/browser/quickOpen/editorQuickOpen';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { GoToLineNLS } from 'vs/editor/common/standaloneStrings';
interface ParseResult {
position: Position;
isValid: boolean;
label: string;
}
export class GotoLineEntry extends QuickOpenEntry {
private readonly parseResult: ParseResult;
private readonly decorator: IDecorator;
private readonly editor: IEditor;
constructor(line: string, editor: IEditor, decorator: IDecorator) {
super();
this.editor = editor;
this.decorator = decorator;
this.parseResult = this.parseInput(line);
}
private parseInput(line: string): ParseResult {
const numbers = line.split(',').map(part => parseInt(part, 10)).filter(part => !isNaN(part));
let position: Position;
if (numbers.length === 0) {
position = new Position(-1, -1);
} else if (numbers.length === 1) {
position = new Position(numbers[0], 1);
} else {
position = new Position(numbers[0], numbers[1]);
}
let model: ITextModel | null;
if (isCodeEditor(this.editor)) {
model = this.editor.getModel();
} else {
const diffModel = (<IDiffEditor>this.editor).getModel();
model = diffModel ? diffModel.modified : null;
}
const isValid = model ? model.validatePosition(position).equals(position) : false;
let label: string;
if (isValid) {
if (position.column && position.column > 1) {
label = strings.format(GoToLineNLS.gotoLineLabelValidLineAndColumn, position.lineNumber, position.column);
} else {
label = strings.format(GoToLineNLS.gotoLineLabelValidLine, position.lineNumber);
}
} else if (position.lineNumber < 1 || position.lineNumber > (model ? model.getLineCount() : 0)) {
label = strings.format(GoToLineNLS.gotoLineLabelEmptyWithLineLimit, model ? model.getLineCount() : 0);
} else {
label = strings.format(GoToLineNLS.gotoLineLabelEmptyWithLineAndColumnLimit, model ? model.getLineMaxColumn(position.lineNumber) : 0);
}
return {
position: position,
isValid: isValid,
label: label
};
}
getLabel(): string {
return this.parseResult.label;
}
getAriaLabel(): string {
const position = this.editor.getPosition();
const currentLine = position ? position.lineNumber : 0;
return strings.format(GoToLineNLS.gotoLineAriaLabel, currentLine, this.parseResult.label);
}
run(mode: Mode, _context: IEntryRunContext): boolean {
if (mode === Mode.OPEN) {
return this.runOpen();
}
return this.runPreview();
}
runOpen(): boolean {
// No-op if range is not valid
if (!this.parseResult.isValid) {
return false;
}
// Apply selection and focus
const range = this.toSelection();
(<ICodeEditor>this.editor).setSelection(range);
(<ICodeEditor>this.editor).revealRangeInCenter(range, ScrollType.Smooth);
this.editor.focus();
return true;
}
runPreview(): boolean {
// No-op if range is not valid
if (!this.parseResult.isValid) {
this.decorator.clearDecorations();
return false;
}
// Select Line Position
const range = this.toSelection();
this.editor.revealRangeInCenter(range, ScrollType.Smooth);
// Decorate if possible
this.decorator.decorateLine(range, this.editor);
return false;
}
private toSelection(): Range {
return new Range(
this.parseResult.position.lineNumber,
this.parseResult.position.column,
this.parseResult.position.lineNumber,
this.parseResult.position.column
);
}
}
export class GotoLineAction extends BaseEditorQuickOpenAction {
constructor() {
super(GoToLineNLS.gotoLineActionInput, {
id: 'editor.action.gotoLine',
label: GoToLineNLS.gotoLineActionLabel,
alias: 'Go to Line...',
precondition: undefined,
kbOpts: {
kbExpr: EditorContextKeys.focus,
primary: KeyMod.CtrlCmd | KeyCode.KEY_G,
mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_G },
weight: KeybindingWeight.EditorContrib
}
});
}
run(accessor: ServicesAccessor, editor: ICodeEditor): void {
this._show(this.getController(editor), {
getModel: (value: string): QuickOpenModel => {
return new QuickOpenModel([new GotoLineEntry(value, editor, this.getController(editor))]);
},
getAutoFocus: (searchValue: string): IAutoFocus => {
return {
autoFocusFirstEntry: searchValue.length > 0
};
}
});
}
}
registerEditorAction(GotoLineAction);
@@ -1,144 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as strings from 'vs/base/common/strings';
import { onUnexpectedError } from 'vs/base/common/errors';
import { matchesFuzzy } from 'vs/base/common/filters';
import { KeyCode } from 'vs/base/common/keyCodes';
import { IHighlight, QuickOpenEntryGroup, QuickOpenModel } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { IAutoFocus, Mode, IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';
import { IEditor, IEditorAction } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { BaseEditorQuickOpenAction } from 'vs/editor/standalone/browser/quickOpen/editorQuickOpen';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { QuickCommandNLS } from 'vs/editor/common/standaloneStrings';
export class EditorActionCommandEntry extends QuickOpenEntryGroup {
private readonly key: string;
private readonly action: IEditorAction;
private readonly editor: IEditor;
private readonly keyAriaLabel: string;
constructor(key: string, keyAriaLabel: string, highlights: IHighlight[], action: IEditorAction, editor: IEditor) {
super();
this.key = key;
this.keyAriaLabel = keyAriaLabel;
this.setHighlights(highlights);
this.action = action;
this.editor = editor;
}
public getLabel(): string {
return this.action.label;
}
public getAriaLabel(): string {
if (this.keyAriaLabel) {
return strings.format(QuickCommandNLS.ariaLabelEntryWithKey, this.getLabel(), this.keyAriaLabel);
}
return strings.format(QuickCommandNLS.ariaLabelEntry, this.getLabel());
}
public getGroupLabel(): string {
return this.key;
}
public run(mode: Mode, context: IEntryRunContext): boolean {
if (mode === Mode.OPEN) {
// Use a timeout to give the quick open widget a chance to close itself first
setTimeout(() => {
// Some actions are enabled only when editor has focus
this.editor.focus();
try {
let promise = this.action.run() || Promise.resolve();
promise.then(undefined, onUnexpectedError);
} catch (error) {
onUnexpectedError(error);
}
}, 50);
return true;
}
return false;
}
}
export class QuickCommandAction extends BaseEditorQuickOpenAction {
constructor() {
super(QuickCommandNLS.quickCommandActionInput, {
id: 'editor.action.quickCommand',
label: QuickCommandNLS.quickCommandActionLabel,
alias: 'Command Palette',
precondition: undefined,
kbOpts: {
kbExpr: EditorContextKeys.focus,
primary: KeyCode.F1,
weight: KeybindingWeight.EditorContrib
},
contextMenuOpts: {
group: 'z_commands',
order: 1
}
});
}
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
const keybindingService = accessor.get(IKeybindingService);
this._show(this.getController(editor), {
getModel: (value: string): QuickOpenModel => {
return new QuickOpenModel(this._editorActionsToEntries(keybindingService, editor, value));
},
getAutoFocus: (searchValue: string): IAutoFocus => {
return {
autoFocusFirstEntry: true,
autoFocusPrefixMatch: searchValue
};
}
});
}
private _sort(elementA: QuickOpenEntryGroup, elementB: QuickOpenEntryGroup): number {
let elementAName = (elementA.getLabel() || '').toLowerCase();
let elementBName = (elementB.getLabel() || '').toLowerCase();
return elementAName.localeCompare(elementBName);
}
private _editorActionsToEntries(keybindingService: IKeybindingService, editor: ICodeEditor, searchValue: string): EditorActionCommandEntry[] {
let actions: IEditorAction[] = editor.getSupportedActions();
let entries: EditorActionCommandEntry[] = [];
for (const action of actions) {
let keybinding = keybindingService.lookupKeybinding(action.id);
if (action.label) {
let highlights = matchesFuzzy(searchValue, action.label);
if (highlights) {
entries.push(new EditorActionCommandEntry(keybinding ? keybinding.getLabel() || '' : '', keybinding ? keybinding.getAriaLabel() || '' : '', highlights, action, editor));
}
}
}
// Sort by name
entries = entries.sort(this._sort);
return entries;
}
}
registerEditorAction(QuickCommandAction);
@@ -1,107 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Dimension } from 'vs/base/browser/dom';
import { IDisposable } from 'vs/base/common/lifecycle';
import { QuickOpenModel } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { QuickOpenWidget } from 'vs/base/parts/quickopen/browser/quickOpenWidget';
import { IAutoFocus } from 'vs/base/parts/quickopen/common/quickOpen';
import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
import { foreground } from 'vs/platform/theme/common/colorRegistry';
import { attachQuickOpenStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
export interface IQuickOpenEditorWidgetOptions {
inputAriaLabel: string;
}
export class QuickOpenEditorWidget implements IOverlayWidget {
private static readonly ID = 'editor.contrib.quickOpenEditorWidget';
private readonly codeEditor: ICodeEditor;
private readonly themeService: IThemeService;
private visible: boolean | undefined;
private quickOpenWidget: QuickOpenWidget;
private domNode: HTMLElement;
private styler: IDisposable;
constructor(codeEditor: ICodeEditor, onOk: () => void, onCancel: () => void, onType: (value: string) => void, configuration: IQuickOpenEditorWidgetOptions, themeService: IThemeService) {
this.codeEditor = codeEditor;
this.themeService = themeService;
this.visible = false;
this.domNode = document.createElement('div');
this.quickOpenWidget = new QuickOpenWidget(
this.domNode,
{
onOk: onOk,
onCancel: onCancel,
onType: onType
}, {
inputPlaceHolder: undefined,
inputAriaLabel: configuration.inputAriaLabel,
keyboardSupport: true
}
);
this.styler = attachQuickOpenStyler(this.quickOpenWidget, this.themeService, {
pickerGroupForeground: foreground
});
this.quickOpenWidget.create();
this.codeEditor.addOverlayWidget(this);
}
setInput(model: QuickOpenModel, focus: IAutoFocus): void {
this.quickOpenWidget.setInput(model, focus);
}
getId(): string {
return QuickOpenEditorWidget.ID;
}
getDomNode(): HTMLElement {
return this.domNode;
}
destroy(): void {
this.codeEditor.removeOverlayWidget(this);
this.quickOpenWidget.dispose();
this.styler.dispose();
}
isVisible(): boolean {
return !!this.visible;
}
show(value: string): void {
this.visible = true;
const editorLayout = this.codeEditor.getLayoutInfo();
if (editorLayout) {
this.quickOpenWidget.layout(new Dimension(editorLayout.width, editorLayout.height));
}
this.quickOpenWidget.show(value);
this.codeEditor.layoutOverlayWidget(this);
}
hide(): void {
this.visible = false;
this.quickOpenWidget.hide();
this.codeEditor.layoutOverlayWidget(this);
}
getPosition(): IOverlayWidgetPosition | null {
if (this.visible) {
return {
preference: OverlayWidgetPositionPreference.TOP_CENTER
};
}
return null;
}
}
@@ -1,8 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-quick-open-widget {
font-size: 13px;
}
@@ -1,325 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./quickOutline';
import 'vs/base/browser/ui/codiconLabel/codiconLabel'; // The codicon symbol styles are defined here and must be loaded
import 'vs/editor/contrib/documentSymbols/outlineTree'; // The codicon symbol colors are defined here and must be loaded
import { CancellationToken } from 'vs/base/common/cancellation';
import { matchesFuzzy } from 'vs/base/common/filters';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import * as strings from 'vs/base/common/strings';
import { IHighlight, QuickOpenEntryGroup, QuickOpenModel } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { IAutoFocus, Mode, IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions';
import { IRange, Range } from 'vs/editor/common/core/range';
import { ScrollType } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { DocumentSymbol, DocumentSymbolProviderRegistry, SymbolKinds } from 'vs/editor/common/modes';
import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/quickOpen';
import { BaseEditorQuickOpenAction, IDecorator } from 'vs/editor/standalone/browser/quickOpen/editorQuickOpen';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { QuickOutlineNLS } from 'vs/editor/common/standaloneStrings';
let SCOPE_PREFIX = ':';
export class SymbolEntry extends QuickOpenEntryGroup {
private readonly name: string;
private readonly type: string;
private readonly description: string | undefined;
private readonly range: Range;
private readonly editor: ICodeEditor;
private readonly decorator: IDecorator;
constructor(name: string, type: string, description: string | undefined, range: Range, highlights: IHighlight[], editor: ICodeEditor, decorator: IDecorator) {
super();
this.name = name;
this.type = type;
this.description = description;
this.range = range;
this.setHighlights(highlights);
this.editor = editor;
this.decorator = decorator;
}
public getLabel(): string {
return this.name;
}
public getAriaLabel(): string {
return strings.format(QuickOutlineNLS.entryAriaLabel, this.name);
}
public getIcon(): string {
return this.type;
}
public getDescription(): string | undefined {
return this.description;
}
public getType(): string {
return this.type;
}
public getRange(): Range {
return this.range;
}
public run(mode: Mode, context: IEntryRunContext): boolean {
if (mode === Mode.OPEN) {
return this.runOpen(context);
}
return this.runPreview();
}
private runOpen(_context: IEntryRunContext): boolean {
// Apply selection and focus
let range = this.toSelection();
this.editor.setSelection(range);
this.editor.revealRangeInCenter(range, ScrollType.Smooth);
this.editor.focus();
return true;
}
private runPreview(): boolean {
// Select Outline Position
let range = this.toSelection();
this.editor.revealRangeInCenter(range, ScrollType.Smooth);
// Decorate if possible
this.decorator.decorateLine(this.range, this.editor);
return false;
}
private toSelection(): Range {
return new Range(
this.range.startLineNumber,
this.range.startColumn || 1,
this.range.startLineNumber,
this.range.startColumn || 1
);
}
}
export class QuickOutlineAction extends BaseEditorQuickOpenAction {
constructor() {
super(QuickOutlineNLS.quickOutlineActionInput, {
id: 'editor.action.quickOutline',
label: QuickOutlineNLS.quickOutlineActionLabel,
alias: 'Go to Symbol...',
precondition: EditorContextKeys.hasDocumentSymbolProvider,
kbOpts: {
kbExpr: EditorContextKeys.focus,
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_O,
weight: KeybindingWeight.EditorContrib
},
contextMenuOpts: {
group: 'navigation',
order: 3
}
});
}
public run(accessor: ServicesAccessor, editor: ICodeEditor) {
if (!editor.hasModel()) {
return undefined;
}
const model = editor.getModel();
if (!DocumentSymbolProviderRegistry.has(model)) {
return undefined;
}
// Resolve outline
return getDocumentSymbols(model, true, CancellationToken.None).then((result: DocumentSymbol[]) => {
if (result.length === 0) {
return;
}
this._run(editor, result);
});
}
private _run(editor: ICodeEditor, result: DocumentSymbol[]): void {
this._show(this.getController(editor), {
getModel: (value: string): QuickOpenModel => {
return new QuickOpenModel(this.toQuickOpenEntries(editor, result, value));
},
getAutoFocus: (searchValue: string): IAutoFocus => {
// Remove any type pattern (:) from search value as needed
if (searchValue.indexOf(SCOPE_PREFIX) === 0) {
searchValue = searchValue.substr(SCOPE_PREFIX.length);
}
return {
autoFocusPrefixMatch: searchValue,
autoFocusFirstEntry: !!searchValue
};
}
});
}
private symbolEntry(name: string, type: string, description: string | undefined, range: IRange, highlights: IHighlight[], editor: ICodeEditor, decorator: IDecorator): SymbolEntry {
return new SymbolEntry(name, type, description, Range.lift(range), highlights, editor, decorator);
}
private toQuickOpenEntries(editor: ICodeEditor, flattened: DocumentSymbol[], searchValue: string): SymbolEntry[] {
const controller = this.getController(editor);
let results: SymbolEntry[] = [];
// Convert to Entries
let normalizedSearchValue = searchValue;
if (searchValue.indexOf(SCOPE_PREFIX) === 0) {
normalizedSearchValue = normalizedSearchValue.substr(SCOPE_PREFIX.length);
}
for (const element of flattened) {
let label = strings.trim(element.name);
// Check for meatch
let highlights = matchesFuzzy(normalizedSearchValue, label);
if (highlights) {
// Show parent scope as description
let description: string | undefined = undefined;
if (element.containerName) {
description = element.containerName;
}
// Add
results.push(this.symbolEntry(label, SymbolKinds.toCssClassName(element.kind), description, element.range, highlights, editor, controller));
}
}
// Sort properly if actually searching
if (searchValue) {
if (searchValue.indexOf(SCOPE_PREFIX) === 0) {
results = results.sort(this.sortScoped.bind(this, searchValue.toLowerCase()));
} else {
results = results.sort(this.sortNormal.bind(this, searchValue.toLowerCase()));
}
}
// Mark all type groups
if (results.length > 0 && searchValue.indexOf(SCOPE_PREFIX) === 0) {
let currentType: string | null = null;
let currentResult: SymbolEntry | null = null;
let typeCounter = 0;
for (let i = 0; i < results.length; i++) {
let result = results[i];
// Found new type
if (currentType !== result.getType()) {
// Update previous result with count
if (currentResult) {
currentResult.setGroupLabel(this.typeToLabel(currentType || '', typeCounter));
}
currentType = result.getType();
currentResult = result;
typeCounter = 1;
result.setShowBorder(i > 0);
}
// Existing type, keep counting
else {
typeCounter++;
}
}
// Update previous result with count
if (currentResult) {
currentResult.setGroupLabel(this.typeToLabel(currentType || '', typeCounter));
}
}
// Mark first entry as outline
else if (results.length > 0) {
results[0].setGroupLabel(strings.format(QuickOutlineNLS._symbols_, results.length));
}
return results;
}
private typeToLabel(type: string, count: number): string {
switch (type) {
case 'module': return strings.format(QuickOutlineNLS._modules_, count);
case 'class': return strings.format(QuickOutlineNLS._class_, count);
case 'interface': return strings.format(QuickOutlineNLS._interface_, count);
case 'method': return strings.format(QuickOutlineNLS._method_, count);
case 'function': return strings.format(QuickOutlineNLS._function_, count);
case 'property': return strings.format(QuickOutlineNLS._property_, count);
case 'variable': return strings.format(QuickOutlineNLS._variable_, count);
case 'var': return strings.format(QuickOutlineNLS._variable2_, count);
case 'constructor': return strings.format(QuickOutlineNLS._constructor_, count);
case 'call': return strings.format(QuickOutlineNLS._call_, count);
}
return type;
}
private sortNormal(searchValue: string, elementA: SymbolEntry, elementB: SymbolEntry): number {
let elementAName = elementA.getLabel().toLowerCase();
let elementBName = elementB.getLabel().toLowerCase();
// Compare by name
let r = elementAName.localeCompare(elementBName);
if (r !== 0) {
return r;
}
// If name identical sort by range instead
let elementARange = elementA.getRange();
let elementBRange = elementB.getRange();
return elementARange.startLineNumber - elementBRange.startLineNumber;
}
private sortScoped(searchValue: string, elementA: SymbolEntry, elementB: SymbolEntry): number {
// Remove scope char
searchValue = searchValue.substr(SCOPE_PREFIX.length);
// Sort by type first if scoped search
let elementAType = elementA.getType();
let elementBType = elementB.getType();
let r = elementAType.localeCompare(elementBType);
if (r !== 0) {
return r;
}
// Special sort when searching in scoped mode
if (searchValue) {
let elementAName = elementA.getLabel().toLowerCase();
let elementBName = elementB.getLabel().toLowerCase();
// Compare by name
let r = elementAName.localeCompare(elementBName);
if (r !== 0) {
return r;
}
}
// Default to sort by range
let elementARange = elementA.getRange();
let elementBRange = elementB.getRange();
return elementARange.startLineNumber - elementBRange.startLineNumber;
}
}
registerEditorAction(QuickOutlineAction);
@@ -138,6 +138,8 @@ class StandaloneTheme implements IStandaloneTheme {
public get tokenColorMap(): string[] {
return [];
}
public readonly semanticHighlighting = false;
}
function isBuiltinTheme(themeName: string): themeName is BuiltinTheme {
@@ -60,6 +60,8 @@ suite('TokenizationSupport2Adapter', () => {
return undefined;
},
semanticHighlighting: false,
tokenColorMap: []
};
}
+2
View File
@@ -74,6 +74,7 @@ declare namespace monaco {
* (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation
* and encoding.
*
* ```txt
* foo://example.com:8042/over/there?name=ferret#nose
* \_/ \______________/\_________/ \_________/ \__/
* | | | | |
@@ -81,6 +82,7 @@ declare namespace monaco {
* | _____________________|__
* / \ / \
* urn:example:animal:ferret:nose
* ```
*/
export class Uri implements UriComponents {
static isUri(thing: any): thing is Uri;
@@ -12,7 +12,7 @@ import { IdGenerator } from 'vs/base/common/idGenerator';
import { IDisposable, toDisposable, MutableDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { isLinux, isWindows } from 'vs/base/common/platform';
import { localize } from 'vs/nls';
import { ICommandAction, IMenu, IMenuActionOptions, MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { ICommandAction, IMenu, IMenuActionOptions, MenuItemAction, SubmenuItemAction, Icon } from 'vs/platform/actions/common/actions';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -216,9 +216,10 @@ export class MenuEntryActionViewItem extends ActionViewItem {
const keybinding = this._keybindingService.lookupKeybinding(this._commandAction.id);
const keybindingLabel = keybinding && keybinding.getLabel();
const tooltip = this._commandAction.tooltip || this._commandAction.label;
this.label.title = keybindingLabel
? localize('titleAndKb', "{0} ({1})", this._commandAction.label, keybindingLabel)
: this._commandAction.label;
? localize('titleAndKb', "{0} ({1})", tooltip, keybindingLabel)
: tooltip;
}
}
@@ -237,9 +238,11 @@ export class MenuEntryActionViewItem extends ActionViewItem {
_updateItemClass(item: ICommandAction): void {
this._itemClassDispose.value = undefined;
if (ThemeIcon.isThemeIcon(item.icon)) {
const icon = this._commandAction.checked && (item.toggled as { icon?: Icon })?.icon ? (item.toggled as { icon: Icon }).icon : item.icon;
if (ThemeIcon.isThemeIcon(icon)) {
// theme icons
const iconClass = ThemeIcon.asClassName(item.icon);
const iconClass = ThemeIcon.asClassName(icon);
if (this.label && iconClass) {
addClasses(this.label, iconClass);
this._itemClassDispose.value = toDisposable(() => {
@@ -249,20 +252,20 @@ export class MenuEntryActionViewItem extends ActionViewItem {
});
}
} else if (item.icon) {
} else if (icon) {
// icon path
let iconClass: string;
if (item.icon?.dark?.scheme) {
if (icon?.dark?.scheme) {
const iconPathMapKey = item.icon.dark.toString();
const iconPathMapKey = icon.dark.toString();
if (MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.has(iconPathMapKey)) {
iconClass = MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.get(iconPathMapKey)!;
} else {
iconClass = ids.nextId();
createCSSRule(`.icon.${iconClass}`, `background-image: ${asCSSUrl(item.icon.light || item.icon.dark)}`);
createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: ${asCSSUrl(item.icon.dark)}`);
createCSSRule(`.icon.${iconClass}`, `background-image: ${asCSSUrl(icon.light || icon.dark)}`);
createCSSRule(`.vs-dark .icon.${iconClass}, .hc-black .icon.${iconClass}`, `background-image: ${asCSSUrl(icon.dark)}`);
MenuEntryActionViewItem.ICON_PATH_TO_CSS_RULES.set(iconPathMapKey, iconClass);
}
+24 -12
View File
@@ -20,13 +20,16 @@ export interface ILocalizedString {
original: string;
}
export type Icon = { dark?: URI; light?: URI; } | ThemeIcon;
export interface ICommandAction {
id: string;
title: string | ILocalizedString;
category?: string | ILocalizedString;
icon?: { dark?: URI; light?: URI; } | ThemeIcon;
tooltip?: string | ILocalizedString;
icon?: Icon;
precondition?: ContextKeyExpression;
toggled?: ContextKeyExpression;
toggled?: ContextKeyExpression | { condition: ContextKeyExpression, icon?: Icon, tooltip?: string | ILocalizedString };
}
export type ISerializableCommandAction = UriDto<ICommandAction>;
@@ -275,9 +278,20 @@ export class MenuItemAction extends ExecuteCommandAction {
@ICommandService commandService: ICommandService
) {
typeof item.title === 'string' ? super(item.id, item.title, commandService) : super(item.id, item.title.value, commandService);
this._cssClass = undefined;
this._enabled = !item.precondition || contextKeyService.contextMatchesRules(item.precondition);
this._checked = Boolean(item.toggled && contextKeyService.contextMatchesRules(item.toggled));
this._tooltip = item.tooltip ? typeof item.tooltip === 'string' ? item.tooltip : item.tooltip.value : undefined;
if (item.toggled) {
const toggled = ((item.toggled as { condition: ContextKeyExpression }).condition ? item.toggled : { condition: item.toggled }) as {
condition: ContextKeyExpression, icon?: Icon, tooltip?: string | ILocalizedString
};
this._checked = contextKeyService.contextMatchesRules(toggled.condition);
if (this._checked && toggled.tooltip) {
this._tooltip = typeof toggled.tooltip === 'string' ? toggled.tooltip : toggled.tooltip.value;
}
}
this._options = options || {};
@@ -373,7 +387,7 @@ export interface IAction2Options extends ICommandAction {
/**
* One or many menu items.
*/
menu?: OneOrN<{ id: MenuId } & Omit<IMenuItem, 'command'> & { command?: Partial<Omit<ICommandAction, 'id'>> }>;
menu?: OneOrN<{ id: MenuId } & Omit<IMenuItem, 'command'>>;
/**
* One keybinding.
@@ -396,7 +410,7 @@ export function registerAction2(ctor: { new(): Action2 }): IDisposable {
const disposables = new DisposableStore();
const action = new ctor();
const { f1, menu: menus, keybinding, description, ...command } = action.desc;
const { f1, menu, keybinding, description, ...command } = action.desc;
// command
disposables.add(CommandsRegistry.registerCommand({
@@ -406,14 +420,12 @@ export function registerAction2(ctor: { new(): Action2 }): IDisposable {
}));
// menu
if (Array.isArray(menus)) {
for (let item of menus) {
const { command: commandOverrides, ...menu } = item;
disposables.add(MenuRegistry.appendMenuItem(item.id, { command: { ...command, ...commandOverrides }, ...menu }));
if (Array.isArray(menu)) {
for (let item of menu) {
disposables.add(MenuRegistry.appendMenuItem(item.id, { command: { ...command }, ...item }));
}
} else if (menus) {
const { command: commandOverrides, ...menu } = menus;
disposables.add(MenuRegistry.appendMenuItem(menu.id, { command: { ...command, ...commandOverrides }, ...menu }));
} else if (menu) {
disposables.add(MenuRegistry.appendMenuItem(menu.id, { command: { ...command }, ...menu }));
}
if (f1) {
disposables.add(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command: command }));
@@ -94,7 +94,8 @@ class Menu implements IMenu {
// keep toggled keys for event if applicable
if (isIMenuItem(item) && item.command.toggled) {
Menu._fillInKbExprKeys(item.command.toggled, this._contextKeys);
const toggledExpression: ContextKeyExpression = (item.command.toggled as { condition: ContextKeyExpression }).condition || item.command.toggled;
Menu._fillInKbExprKeys(toggledExpression, this._contextKeys);
}
}
this._onDidChange.fire(this);
@@ -39,7 +39,6 @@ export interface ParsedArgs {
'builtin-extensions-dir'?: string;
extensionDevelopmentPath?: string[]; // // undefined or array of 1 or more local paths or URIs
extensionTestsPath?: string; // either a local path or a URI
'extension-development-confirm-save'?: boolean;
'inspect-extensions'?: string;
'inspect-brk-extensions'?: string;
debugId?: string;
@@ -74,6 +73,7 @@ export interface ParsedArgs {
'disable-user-env-probe'?: boolean;
'force'?: boolean;
'force-user-env'?: boolean;
'sync'?: 'on' | 'off';
// chromium command line args: https://electronjs.org/docs/all#supported-chrome-command-line-switches
'no-proxy-server'?: boolean;
@@ -167,5 +167,5 @@ export interface IEnvironmentService extends IUserHomeProvider {
driverHandle?: string;
driverVerbose: boolean;
galleryMachineIdResource?: URI;
serviceMachineIdResource?: URI;
}

Some files were not shown because too many files have changed in this diff Show More