This commit is contained in:
ADS Merger 2020-04-04 04:30:52 +00:00
Родитель 00cc0074f7
Коммит 35f1a014d5
184 изменённых файлов: 3043 добавлений и 2285 удалений

34
.github/feature-requests.yml поставляемый
Просмотреть файл

@ -1,34 +0,0 @@
{
typeLabel: {
name: 'feature-request'
},
candidateMilestone: {
number: 107,
name: 'Backlog Candidates'
},
approvedMilestone: {
number: 8,
name: 'Backlog'
},
onLabeled: {
delay: 60,
perform: true
},
onCandidateMilestoned: {
candidatesComment: "This feature request is now a candidate for our backlog. The community has 60 days to upvote the issue. If it receives 20 upvotes we will move it to our backlog. If not, we will close it. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!",
perform: true
},
onMonitorUpvotes: {
upvoteThreshold: 20,
acceptanceComment: ":slightly_smiling_face: This feature request received a sufficient number of community upvotes and we moved it to our backlog. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!",
perform: true
},
onMonitorDaysOnCandidateMilestone: {
daysOnMilestone: 60,
warningPeriod: 10,
numberOfCommentsToPreventAutomaticRejection: 20,
rejectionComment: ":slightly_frowning_face: In the last 60 days, this feature request has received less than 20 community upvotes and we closed it. Still a big Thank You to you for taking the time to create this issue! To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!",
warningComment: "This feature request has not yet received the 20 community upvotes it takes to make to our backlog. 10 days to go. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding",
perform: true
}
}

36
.github/workflows/feature-request.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,36 @@
name: Feature Request Manager
on:
repository_dispatch:
issues:
types: [labeled, milestoned]
schedule:
- cron: 20 2 * * * # 4:20am Zurich
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Checkout Actions
if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'feature-request')
uses: actions/checkout@v2
with:
repository: 'JacksonKearl/vscode-triage-github-actions'
ref: v20
- name: Run Feature Request Manager
if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'feature-request')
uses: ./feature-request
with:
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
candidateMilestoneID: 107
candidateMilestoneName: Backlog Candidates
backlogMilestoneID: 8
featureRequestLabel: feature-request
upvotesRequired: 20
numCommentsOverride: 20
initComment: "This feature request is now a candidate for our backlog. The community has 60 days to upvote the issue. If it receives 20 upvotes we will move it to our backlog. If not, we will close it. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!"
warnComment: "This feature request has not yet received the 20 community upvotes it takes to make to our backlog. 10 days to go. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding"
acceptComment: ":slightly_smiling_face: This feature request received a sufficient number of community upvotes and we moved it to our backlog. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!"
rejectComment: ":slightly_frowning_face: In the last 60 days, this feature request has received less than 20 community upvotes and we closed it. Still a big Thank You to you for taking the time to create this issue! To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!"
warnDays: 10
closeDays: 60
milestoneDelaySeconds: 60

67
.vscode/searches/es6.code-search поставляемый
Просмотреть файл

@ -2,7 +2,7 @@
# Flags: CaseSensitive WordMatch
# ContextLines: 2
11 results - 3 files
9 results - 4 files
src/vs/base/common/arrays.ts:
401
@ -17,20 +17,14 @@ src/vs/base/common/arrays.ts:
420 */
421 export function first<T>(array: ReadonlyArray<T>, fn: (item: T) => boolean, notFoundValue: T): T;
474
475 /**
476: * @deprecated ES6: use `Array.fill`
477 */
478 export function fill<T>(num: number, value: T, arr: T[] = []): T[] {
571
572 /**
573: * @deprecated ES6: use `Array.find`
574 */
575 export function find<T>(arr: ArrayLike<T>, predicate: (value: T, index: number, arr: ArrayLike<T>) => any): T | undefined {
560
561 /**
562: * @deprecated ES6: use `Array.find`
563 */
564 export function find<T>(arr: ArrayLike<T>, predicate: (value: T, index: number, arr: ArrayLike<T>) => any): T | undefined {
src/vs/base/common/map.ts:
9
9
10 /**
11: * @deprecated ES6: use `[...SetOrMap.values()]`
12 */
@ -42,33 +36,28 @@ src/vs/base/common/map.ts:
23 */
24 export function keys<K, V>(map: Map<K, V>): K[] {
58
59 /**
60: * @deprecated ES6: use `...Map.entries()`
61 */
62 export function mapToSerializable(map: Map<string, string>): [string, string][] {
71
72 /**
73: * @deprecated ES6: use `new Map([[key1, value1],[key2, value2]])`
74 */
75 export function serializableToMap(serializable: [string, string][]): Map<string, string> {
src/vs/base/common/objects.ts:
115
116 /**
117: * @deprecated ES6
118 */
119 export function assign<T>(destination: T): T;
src/vs/base/common/strings.ts:
16
17 /**
18: * @deprecated ES6: use `String.padStart`
19 */
20 export function pad(n: number, l: number, char: string = '0'): string {
15
16 /**
17: * @deprecated ES6: use `String.padStart`
18 */
19 export function pad(n: number, l: number, char: string = '0'): string {
147
148 /**
149: * @deprecated ES6: use `String.startsWith`
150 */
151 export function startsWith(haystack: string, needle: string): boolean {
146
147 /**
148: * @deprecated ES6: use `String.startsWith`
149 */
150 export function startsWith(haystack: string, needle: string): boolean {
168
169 /**
170: * @deprecated ES6: use `String.endsWith`
171 */
172 export function endsWith(haystack: string, needle: string): boolean {
167
168 /**
169: * @deprecated ES6: use `String.endsWith`
170 */
171 export function endsWith(haystack: string, needle: string): boolean {

Просмотреть файл

@ -230,9 +230,9 @@ for-own@^0.1.4:
for-in "^1.0.1"
fsevents@~2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.1.tgz#74c64e21df71721845d0c44fe54b7f56b82995a9"
integrity sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw==
version "2.1.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805"
integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==
glob-base@^0.3.0:
version "0.3.0"
@ -258,9 +258,9 @@ glob-parent@^3.0.1:
path-dirname "^1.0.0"
glob-parent@~5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
version "5.1.1"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
dependencies:
is-glob "^4.0.1"
@ -405,9 +405,9 @@ kind-of@^3.0.2:
is-buffer "^1.1.5"
kind-of@^6.0.0:
version "6.0.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
version "6.0.3"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
math-random@^1.0.1:
version "1.0.4"
@ -479,9 +479,9 @@ path-is-absolute@^1.0.1:
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
picomatch@^2.0.4:
version "2.1.0"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.1.0.tgz#0fd042f568d08b1ad9ff2d3ec0f0bfb3cb80e177"
integrity sha512-uhnEDzAbrcJ8R3g2fANnSuXZMBtkpSjxTTgn2LeSiQlfmq72enQJWdQllXW24MBLYnA1SBD2vfvx2o0Zw3Ielw==
version "2.2.2"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
pify@^2.3.0:
version "2.3.0"
@ -530,9 +530,9 @@ randomatic@^3.0.0:
math-random "^1.0.1"
readable-stream@^2.0.2, readable-stream@^2.2.2, readable-stream@^2.3.5:
version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"

Просмотреть файл

@ -1235,11 +1235,6 @@
}
],
"timeline/item/context": [
{
"command": "git.timeline.openDiff",
"group": "inline",
"when": "config.git.enabled && !git.missing && timelineItem =~ /git:file\\b/"
},
{
"command": "git.timeline.openDiff",
"group": "1_timeline",

Просмотреть файл

@ -74,7 +74,7 @@ export class GitTimelineProvider implements TimelineProvider {
constructor(private readonly _model: Model) {
this.disposable = Disposable.from(
_model.onDidOpenRepository(this.onRepositoriesChanged, this),
workspace.registerTimelineProvider(['file', 'git', 'gitlens-git'], this),
workspace.registerTimelineProvider(['file', 'git', 'vscode-remote', 'gitlens-git'], this),
);
}

Просмотреть файл

@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as uuid from 'uuid';
import { keychain } from './common/keychain';
import { GitHubServer } from './githubServer';
import Logger from './common/logger';
@ -122,7 +123,7 @@ export class GitHubAuthenticationProvider {
private async tokenToSession(token: string, scopes: string[]): Promise<vscode.AuthenticationSession> {
const userInfo = await this._githubServer.getUserInfo(token);
return {
id: userInfo.id,
id: uuid(),
getAccessToken: () => Promise.resolve(token),
accountName: userInfo.accountName,
scopes: scopes

Просмотреть файл

@ -23,7 +23,7 @@ export function activate(context: vscode.ExtensionContext) {
const previewManager = new PreviewManager(extensionRoot, sizeStatusBarEntry, binarySizeStatusBarEntry, zoomStatusBarEntry);
context.subscriptions.push(vscode.window.registerCustomEditorProvider(PreviewManager.viewType, previewManager));
context.subscriptions.push(vscode.window.registerCustomEditorProvider2(PreviewManager.viewType, previewManager));
context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomIn', () => {
previewManager.activePreview?.zoomIn();

Просмотреть файл

@ -14,7 +14,7 @@
"dependencies": {
"jsonc-parser": "^2.2.1",
"request-light": "^0.2.5",
"vscode-json-languageservice": "^3.5.1",
"vscode-json-languageservice": "^3.5.2",
"vscode-languageserver": "^6.1.1",
"vscode-uri": "^2.1.1"
},

Просмотреть файл

@ -80,10 +80,10 @@ request-light@^0.2.5:
https-proxy-agent "^2.2.3"
vscode-nls "^4.1.1"
vscode-json-languageservice@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.5.1.tgz#75779d466107cbc8c4cc9828df100df71c1870f8"
integrity sha512-F8jPqcAC1mbQOMKvGYS4dGEw9JCZxVEi7tc5ASZLfcfwKq2URZKB4fOtdy1GEsTLsrW11tVrBjEPntpXzqp/NA==
vscode-json-languageservice@^3.5.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.5.2.tgz#4b898140a8e581359c10660845a4cae15dcbb4f9"
integrity sha512-9cUvBq00O08lpWVVOx6tQ1yLxCHss79nsUdEAVYGomRyMbnPBmc0AkYPcXI9WK1EM6HBo0R9Zo3NjFhcICpy4A==
dependencies:
jsonc-parser "^2.2.1"
vscode-languageserver-textdocument "^1.0.1"

Просмотреть файл

@ -51,9 +51,11 @@
"typescript": "^3.7.4",
"tslint": "^5.12.1",
"@types/node": "^10.12.21",
"@types/keytar": "^4.0.1"
"@types/keytar": "^4.0.1",
"@types/uuid": "^3.4.6"
},
"dependencies": {
"uuid": "^3.3.3",
"vscode-nls": "^4.1.1"
}
}

Просмотреть файл

@ -7,6 +7,7 @@ import * as crypto from 'crypto';
import * as https from 'https';
import * as querystring from 'querystring';
import * as vscode from 'vscode';
import * as uuid from 'uuid';
import { createServer, startServer } from './authServer';
import { keychain } from './keychain';
import Logger from './logger';
@ -81,7 +82,7 @@ export class AzureActiveDirectoryService {
const sessions = this.parseStoredData(storedData);
const refreshes = sessions.map(async session => {
try {
await this.refreshToken(session.refreshToken, session.scope);
await this.refreshToken(session.refreshToken, session.scope, session.id);
} catch (e) {
if (e.message === REFRESH_NETWORK_FAILURE) {
const didSucceedOnRetry = await this.handleRefreshNetworkError(session.id, session.refreshToken, session.scope);
@ -140,7 +141,7 @@ export class AzureActiveDirectoryService {
const matchesExisting = this._tokens.some(token => token.scope === session.scope && token.sessionId === session.id);
if (!matchesExisting) {
try {
await this.refreshToken(session.refreshToken, session.scope);
await this.refreshToken(session.refreshToken, session.scope, session.id);
addedIds.push(session.id);
} catch (e) {
if (e.message === REFRESH_NETWORK_FAILURE) {
@ -169,10 +170,17 @@ export class AzureActiveDirectoryService {
}
} else {
if (this._tokens.length) {
// Log out all
// Log out all, remove all local data
removedIds = this._tokens.map(token => token.sessionId);
Logger.info('No tokens in memory, clearing keychain data');
await this.clearSessions();
Logger.info('No stored keychain data, clearing local data');
this._tokens = [];
this._refreshTimeouts.forEach(timeout => {
clearTimeout(timeout);
});
this._refreshTimeouts.clear();
}
}
@ -203,7 +211,7 @@ export class AzureActiveDirectoryService {
try {
Logger.info('Token expired or unavailable, trying refresh');
const refreshedToken = await this.refreshToken(token.refreshToken, token.scope);
const refreshedToken = await this.refreshToken(token.refreshToken, token.scope, token.sessionId);
if (refreshedToken.accessToken) {
return refreshedToken.accessToken;
} else {
@ -379,7 +387,7 @@ export class AzureActiveDirectoryService {
if (token.expiresIn) {
this._refreshTimeouts.set(token.sessionId, setTimeout(async () => {
try {
await this.refreshToken(token.refreshToken, scope);
await this.refreshToken(token.refreshToken, scope, token.sessionId);
onDidChangeSessions.fire({ added: [], removed: [], changed: [token.sessionId] });
} catch (e) {
if (e.message === REFRESH_NETWORK_FAILURE) {
@ -398,7 +406,7 @@ export class AzureActiveDirectoryService {
this.storeTokenData();
}
private getTokenFromResponse(buffer: Buffer[], scope: string): IToken {
private getTokenFromResponse(buffer: Buffer[], scope: string, existingId?: string): IToken {
const json = JSON.parse(Buffer.concat(buffer).toString());
const claims = this.getTokenClaims(json.access_token);
return {
@ -407,7 +415,7 @@ export class AzureActiveDirectoryService {
accessToken: json.access_token,
refreshToken: json.refresh_token,
scope,
sessionId: `${claims.tid}/${(claims.oid || (claims.altsecid || '' + claims.ipd || ''))}/${scope}`,
sessionId: existingId || `${claims.tid}/${(claims.oid || (claims.altsecid || '' + claims.ipd || ''))}/${uuid()}`,
accountName: claims.email || claims.unique_name || 'user@example.com'
};
}
@ -465,7 +473,7 @@ export class AzureActiveDirectoryService {
});
}
private async refreshToken(refreshToken: string, scope: string): Promise<IToken> {
private async refreshToken(refreshToken: string, scope: string, sessionId: string): Promise<IToken> {
return new Promise((resolve: (value: IToken) => void, reject) => {
Logger.info('Refreshing token...');
const postData = querystring.stringify({
@ -490,7 +498,7 @@ export class AzureActiveDirectoryService {
});
result.on('end', async () => {
if (result.statusCode === 200) {
const token = this.getTokenFromResponse(buffer, scope);
const token = this.getTokenFromResponse(buffer, scope, sessionId);
this.setToken(token, scope);
Logger.info('Token refresh success');
resolve(token);
@ -533,7 +541,7 @@ export class AzureActiveDirectoryService {
this._refreshTimeouts.set(sessionId, setTimeout(async () => {
try {
await this.refreshToken(refreshToken, scope);
await this.refreshToken(refreshToken, scope, sessionId);
} catch (e) {
this.pollForReconnect(sessionId, refreshToken, scope);
}
@ -561,7 +569,7 @@ export class AzureActiveDirectoryService {
this._refreshTimeouts.set(sessionId, setTimeout(async () => {
try {
await this.refreshToken(refreshToken, scope);
await this.refreshToken(refreshToken, scope, sessionId);
return resolve(true);
} catch (e) {
return resolve(await this.handleRefreshNetworkError(sessionId, refreshToken, scope, attempts + 1));

Просмотреть файл

@ -30,6 +30,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.13.tgz#ccebcdb990bd6139cd16e84c39dc2fb1023ca90c"
integrity sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg==
"@types/uuid@^3.4.6":
version "3.4.8"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.8.tgz#4ba887fcef88bd9a7515ca2de336d691e3e18318"
integrity sha512-zHWce3allXWSmRx6/AGXKCtSOA7JjeWd2L3t4aHfysNk8mouQnWCocveaT7a4IEIlPVHp81jzlnknqTgCjCLXA==
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
@ -635,6 +640,11 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
uuid@^3.3.3:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
vscode-nls@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c"

Просмотреть файл

@ -56,7 +56,7 @@
"iconv-lite": "0.5.0",
"jquery": "3.4.0",
"jschardet": "2.1.1",
"keytar": "^4.11.0",
"keytar": "github:rmacfarlane/node-keytar#334424bd26414923782f144110f4beda19168d24",
"minimist": "^1.2.5",
"native-is-elevated": "0.4.1",
"native-keymap": "2.1.1",
@ -185,7 +185,7 @@
"vinyl": "^2.0.0",
"vinyl-fs": "^3.0.0",
"vsce": "1.48.0",
"vscode-debugprotocol": "1.40.0-pre.1",
"vscode-debugprotocol": "^1.40.0",
"vscode-nls-dev": "^3.3.1",
"webpack": "^4.16.5",
"webpack-cli": "^3.3.8",

Просмотреть файл

@ -8,26 +8,29 @@ import { QUERY_HISTORY_PANEL_ID } from 'sql/workbench/contrib/queryHistory/commo
import { RunQueryOnConnectionMode } from 'sql/platform/connection/common/connectionManagement';
import { Action } from 'vs/base/common/actions';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
import { localize } from 'vs/nls';
import { IQueryHistoryService } from 'sql/workbench/services/queryHistory/common/queryHistoryService';
import { QueryHistoryNode } from 'sql/workbench/contrib/queryHistory/browser/queryHistoryNode';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { openNewQuery } from 'sql/workbench/contrib/query/browser/queryActions';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IViewsService, IViewDescriptorService } from 'vs/workbench/common/views';
import { ToggleViewAction } from 'vs/workbench/browser/actions/layoutActions';
export class ToggleQueryHistoryAction extends TogglePanelAction {
export class ToggleQueryHistoryAction extends ToggleViewAction {
public static readonly ID = 'workbench.action.tasks.toggleQueryHistory';
public static readonly LABEL = localize('toggleQueryHistory', "Toggle Query History");
constructor(
id: string, label: string,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@IPanelService panelService: IPanelService,
@IViewsService viewsService: IViewsService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IContextKeyService contextKeyService: IContextKeyService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService
) {
super(id, label, QUERY_HISTORY_PANEL_ID, panelService, layoutService);
super(id, label, QUERY_HISTORY_PANEL_ID, viewsService, viewDescriptorService, contextKeyService, layoutService);
}
}

Просмотреть файл

@ -5,20 +5,23 @@
import { localize } from 'vs/nls';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
import { ToggleViewAction } from 'vs/workbench/browser/actions/layoutActions';
import { IViewsService, IViewDescriptorService } from 'vs/workbench/common/views';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { TASKS_PANEL_ID } from 'sql/workbench/contrib/tasks/common/tasks';
export class ToggleTasksAction extends TogglePanelAction {
export class ToggleTasksAction extends ToggleViewAction {
public static readonly ID = 'workbench.action.tasks.toggleTasks';
public static readonly LABEL = localize('toggleTasks', "Toggle Tasks");
constructor(
id: string, label: string,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@IPanelService panelService: IPanelService,
@IViewsService viewsService: IViewsService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IContextKeyService contextKeyService: IContextKeyService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService
) {
super(id, label, TASKS_PANEL_ID, panelService, layoutService);
super(id, label, TASKS_PANEL_ID, viewsService, viewDescriptorService, contextKeyService, layoutService);
}
}

Просмотреть файл

@ -159,6 +159,11 @@ export let addStandardDisposableGenericMouseDownListner = function addStandardDi
return addDisposableGenericMouseDownListner(node, wrapHandler, useCapture);
};
export let addStandardDisposableGenericMouseUpListner = function addStandardDisposableListener(node: HTMLElement, handler: (event: any) => void, useCapture?: boolean): IDisposable {
let wrapHandler = _wrapAsStandardMouseEvent(handler);
return addDisposableGenericMouseUpListner(node, wrapHandler, useCapture);
};
export function addDisposableGenericMouseDownListner(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable {
return addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_DOWN : EventType.MOUSE_DOWN, handler, useCapture);
}

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0719 7.99999L5.7146 12.3573L6.33332 12.976L11 8.30935V7.69064L6.33332 3.02397L5.7146 3.64269L10.0719 7.99999Z" fill="#C5C5C5"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 284 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0719 7.99999L5.7146 12.3573L6.33332 12.976L11 8.30935V7.69063L6.33332 3.02396L5.7146 3.64268L10.0719 7.99999Z" fill="white"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 282 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0719 7.99999L5.7146 12.3573L6.33332 12.976L11 8.30935V7.69063L6.33332 3.02396L5.7146 3.64268L10.0719 7.99999Z" fill="#424242"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 284 B

Просмотреть файл

@ -36,7 +36,7 @@ export class HorizontalScrollbar extends AbstractScrollbar {
let scrollbarDelta = (options.horizontalScrollbarSize - ARROW_IMG_SIZE) / 2;
this._createArrow({
className: 'left-arrow',
className: 'scra codicon codicon-triangle-left',
top: scrollbarDelta,
left: arrowDelta,
bottom: undefined,
@ -47,7 +47,7 @@ export class HorizontalScrollbar extends AbstractScrollbar {
});
this._createArrow({
className: 'right-arrow',
className: 'scra codicon codicon-triangle-right',
top: scrollbarDelta,
left: undefined,
bottom: undefined,

Просмотреть файл

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 11"><path transform="rotate(-180 5.49045991897583,5.811500072479248)" fill="#E8E8E8" d="m9.48046,8.9615l1.26,-1.26l-5.04,-5.04l-5.46,5.04l1.26,1.26l4.2,-3.78l3.78,3.78z"/></svg>

До

Ширина:  |  Высота:  |  Размер: 233 B

Просмотреть файл

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 11"><path transform="rotate(-180 5.49045991897583,5.811500072479248)" fill="#424242" d="m9.48046,8.9615l1.26,-1.26l-5.04,-5.04l-5.46,5.04l1.26,1.26l4.2,-3.78l3.78,3.78z"/></svg>

До

Ширина:  |  Высота:  |  Размер: 233 B

Просмотреть файл

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 11"><path transform="rotate(-90 5.490459918975831,5.431382179260254)" fill="#E8E8E8" d="m9.48046,8.58138l1.26,-1.26l-5.04,-5.04l-5.46,5.04l1.26,1.26l4.2,-3.78l3.78,3.78z"/></svg>

До

Ширина:  |  Высота:  |  Размер: 234 B

Просмотреть файл

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 11"><path transform="rotate(-90 5.490459918975831,5.431382179260254)" fill="#424242" d="m9.48046,8.58138l1.26,-1.26l-5.04,-5.04l-5.46,5.04l1.26,1.26l4.2,-3.78l3.78,3.78z"/></svg>

До

Ширина:  |  Высота:  |  Размер: 234 B

Просмотреть файл

@ -1 +0,0 @@
<svg viewBox="0 0 11 11" xmlns="http://www.w3.org/2000/svg"><path transform="rotate(90 5.6171650886535645,5.55808973312378) " fill="#E8E8E8" d="m9.60717,8.70809l1.26,-1.26l-5.04,-5.04l-5.46,5.04l1.26,1.26l4.2,-3.78l3.78,3.78z"/></svg>

До

Ширина:  |  Высота:  |  Размер: 234 B

Просмотреть файл

@ -1 +0,0 @@
<svg viewBox="0 0 11 11" xmlns="http://www.w3.org/2000/svg"><path transform="rotate(90 5.6171650886535645,5.55808973312378) " fill="#424242" d="m9.60717,8.70809l1.26,-1.26l-5.04,-5.04l-5.46,5.04l1.26,1.26l4.2,-3.78l3.78,3.78z"/></svg>

До

Ширина:  |  Высота:  |  Размер: 234 B

Просмотреть файл

@ -1 +0,0 @@
<svg viewBox="0 0 11 11" xmlns="http://www.w3.org/2000/svg"><path d="m9.48046,8.9615l1.26,-1.26l-5.04,-5.04l-5.46,5.04l1.26,1.26l4.2,-3.78l3.78,3.78z" fill="#E8E8E8"/></svg>

До

Ширина:  |  Высота:  |  Размер: 173 B

Просмотреть файл

@ -1 +0,0 @@
<svg viewBox="0 0 11 11" xmlns="http://www.w3.org/2000/svg"><path d="m9.48046,8.9615l1.26,-1.26l-5.04,-5.04l-5.46,5.04l1.26,1.26l4.2,-3.78l3.78,3.78z" fill="#424242"/></svg>

До

Ширина:  |  Высота:  |  Размер: 173 B

Просмотреть файл

@ -4,38 +4,9 @@
*--------------------------------------------------------------------------------------------*/
/* Arrows */
.monaco-scrollable-element > .scrollbar > .up-arrow {
background: url('arrow-up.svg');
.monaco-scrollable-element > .scrollbar > .scra {
cursor: pointer;
}
.monaco-scrollable-element > .scrollbar > .down-arrow {
background: url('arrow-down.svg');
cursor: pointer;
}
.monaco-scrollable-element > .scrollbar > .left-arrow {
background: url('arrow-left.svg');
cursor: pointer;
}
.monaco-scrollable-element > .scrollbar > .right-arrow {
background: url('arrow-right.svg');
cursor: pointer;
}
.hc-black .monaco-scrollable-element > .scrollbar > .up-arrow,
.vs-dark .monaco-scrollable-element > .scrollbar > .up-arrow {
background: url('arrow-up-dark.svg');
}
.hc-black .monaco-scrollable-element > .scrollbar > .down-arrow,
.vs-dark .monaco-scrollable-element > .scrollbar > .down-arrow {
background: url('arrow-down-dark.svg');
}
.hc-black .monaco-scrollable-element > .scrollbar > .left-arrow,
.vs-dark .monaco-scrollable-element > .scrollbar > .left-arrow {
background: url('arrow-left-dark.svg');
}
.hc-black .monaco-scrollable-element > .scrollbar > .right-arrow,
.vs-dark .monaco-scrollable-element > .scrollbar > .right-arrow {
background: url('arrow-right-dark.svg');
font-size: 11px !important;
}
.monaco-scrollable-element > .visible {
@ -137,4 +108,4 @@
.hc-black .monaco-scrollable-element .shadow.top.left {
box-shadow: none;
}
}

Просмотреть файл

@ -37,7 +37,7 @@ export class VerticalScrollbar extends AbstractScrollbar {
let scrollbarDelta = (options.verticalScrollbarSize - ARROW_IMG_SIZE) / 2;
this._createArrow({
className: 'up-arrow',
className: 'scra codicon codicon-triangle-up',
top: arrowDelta,
left: scrollbarDelta,
bottom: undefined,
@ -48,7 +48,7 @@ export class VerticalScrollbar extends AbstractScrollbar {
});
this._createArrow({
className: 'down-arrow',
className: 'scra codicon codicon-triangle-down',
top: undefined,
left: scrollbarDelta,
bottom: arrowDelta,

Просмотреть файл

@ -52,6 +52,10 @@ export class SelectBoxNative extends Disposable implements ISelectBoxDelegate {
}));
});
this._register(dom.addStandardDisposableListener(this.selectElement, 'click', (e) => {
dom.EventHelper.stop(e, true);
}));
this._register(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => {
this.selectElement.title = e.target.value;
this._onDidSelect.fire({

Просмотреть файл

@ -68,6 +68,24 @@
color: inherit;
}
.monaco-pane-view .pane > .pane-header .monaco-action-bar .action-item.select-container {
cursor: default;
}
.monaco-pane-view .pane > .pane-header .action-item .monaco-select-box {
cursor: pointer;
min-width: 110px;
min-height: 18px;
padding: 2px 23px 2px 8px;
background-color: inherit !important;
color: inherit !important;
}
.linux .monaco-pane-view .pane > .pane-header .action-item .monaco-select-box,
.windows .monaco-pane-view .pane > .pane-header .action-item .monaco-select-box {
padding: 0px 23px 2px 8px;
}
/* Bold font style does not go well with CJK fonts */
.monaco-pane-view:lang(zh-Hans) .pane > .pane-header,
.monaco-pane-view:lang(zh-Hant) .pane > .pane-header,

Просмотреть файл

@ -31,6 +31,7 @@ export interface IPaneStyles {
headerForeground?: Color;
headerBackground?: Color;
headerBorder?: Color;
leftBorder?: Color;
}
/**
@ -243,6 +244,8 @@ export abstract class Pane extends Disposable implements IView {
style(styles: IPaneStyles): void {
this.styles = styles;
this.element.style.borderLeft = this.styles.leftBorder && this.orientation === Orientation.HORIZONTAL ? `1px solid ${this.styles.leftBorder}` : '';
if (!this.header) {
return;
}
@ -261,7 +264,7 @@ export abstract class Pane extends Disposable implements IView {
this.header.style.color = this.styles.headerForeground ? this.styles.headerForeground.toString() : '';
this.header.style.backgroundColor = this.styles.headerBackground ? this.styles.headerBackground.toString() : '';
this.header.style.borderTop = this.styles.headerBorder ? `1px solid ${this.styles.headerBorder}` : '';
this.header.style.borderTop = this.styles.headerBorder && this.orientation === Orientation.VERTICAL ? `1px solid ${this.styles.headerBorder}` : '';
this._dropBackground = this.styles.dropBackground;
}

Просмотреть файл

@ -1,31 +0,0 @@
<?xml version='1.0' standalone='no' ?>
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
<style>
circle {
animation: ball 0.6s linear infinite;
}
circle:nth-child(2) { animation-delay: 0.075s; }
circle:nth-child(3) { animation-delay: 0.15s; }
circle:nth-child(4) { animation-delay: 0.225s; }
circle:nth-child(5) { animation-delay: 0.3s; }
circle:nth-child(6) { animation-delay: 0.375s; }
circle:nth-child(7) { animation-delay: 0.45s; }
circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball {
from { opacity: 1; }
to { opacity: 0.3; }
}
</style>
<g style="fill:grey;">
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
</g>
</svg>

До

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -1,31 +0,0 @@
<?xml version='1.0' standalone='no' ?>
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
<style>
circle {
animation: ball 0.6s linear infinite;
}
circle:nth-child(2) { animation-delay: 0.075s; }
circle:nth-child(3) { animation-delay: 0.15s; }
circle:nth-child(4) { animation-delay: 0.225s; }
circle:nth-child(5) { animation-delay: 0.3s; }
circle:nth-child(6) { animation-delay: 0.375s; }
circle:nth-child(7) { animation-delay: 0.45s; }
circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball {
from { opacity: 1; }
to { opacity: 0.3; }
}
</style>
<g style="fill:white;">
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
</g>
</svg>

До

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -1,31 +0,0 @@
<?xml version='1.0' standalone='no' ?>
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
<style>
circle {
animation: ball 0.6s linear infinite;
}
circle:nth-child(2) { animation-delay: 0.075s; }
circle:nth-child(3) { animation-delay: 0.15s; }
circle:nth-child(4) { animation-delay: 0.225s; }
circle:nth-child(5) { animation-delay: 0.3s; }
circle:nth-child(6) { animation-delay: 0.375s; }
circle:nth-child(7) { animation-delay: 0.45s; }
circle:nth-child(8) { animation-delay: 0.525s; }
@keyframes ball {
from { opacity: 1; }
to { opacity: 0.3; }
}
</style>
<g>
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
</g>
</svg>

До

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0719 7.99999L5.71461 12.3573L6.33333 12.976L11 8.30935V7.69064L6.33333 3.02397L5.71461 3.64269L10.0719 7.99999Z" fill="#C5C5C5"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 286 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0719 7.99999L5.71461 12.3573L6.33333 12.976L11 8.30935V7.69063L6.33333 3.02396L5.71461 3.64268L10.0719 7.99999Z" fill="white"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 284 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0719 7.99999L5.71461 12.3573L6.33333 12.976L11 8.30935V7.69063L6.33333 3.02396L5.71461 3.64268L10.0719 7.99999Z" fill="#424242"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 286 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.97603 10.0719L12.3333 5.71461L12.9521 6.33333L8.28539 11L7.66667 11L3 6.33333L3.61872 5.71461L7.97603 10.0719Z" fill="#C5C5C5"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 284 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.97603 10.0719L12.3333 5.71461L12.9521 6.33333L8.28539 11L7.66667 11L3 6.33333L3.61872 5.71461L7.97603 10.0719Z" fill="white"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 282 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.97603 10.0719L12.3333 5.71461L12.9521 6.33333L8.28539 11L7.66667 11L3 6.33333L3.61872 5.71461L7.97603 10.0719Z" fill="#424242"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 284 B

Просмотреть файл

@ -4,56 +4,24 @@
*--------------------------------------------------------------------------------------------*/
import { compareAnything } from 'vs/base/common/comparers';
import { matchesPrefix, IMatch, matchesCamelCase, isUpper } from 'vs/base/common/filters';
import { matchesPrefix, IMatch, matchesCamelCase, isUpper, fuzzyScore, createMatches as createFuzzyMatches } from 'vs/base/common/filters';
import { sep } from 'vs/base/common/path';
import { isWindows, isLinux } from 'vs/base/common/platform';
import { stripWildcards, equalsIgnoreCase } from 'vs/base/common/strings';
import { CharCode } from 'vs/base/common/charCode';
import { distinctES6 } from 'vs/base/common/arrays';
export type Score = [number /* score */, number[] /* match positions */];
export type ScorerCache = { [key: string]: IItemScore };
//#region Fuzzy scorer
export type FuzzyScore = [number /* score */, number[] /* match positions */];
export type FuzzyScorerCache = { [key: string]: IItemScore };
const NO_MATCH = 0;
const NO_SCORE: Score = [NO_MATCH, []];
const NO_SCORE: FuzzyScore = [NO_MATCH, []];
// const DEBUG = false;
// const DEBUG_MATRIX = false;
export function score(target: string, query: IPreparedQuery, fuzzy: boolean): Score {
if (query.values && query.values.length > 1) {
return scoreMultiple(target, query.values, fuzzy);
}
return scoreSingle(target, query.normalized, query.normalizedLowercase, fuzzy);
}
function scoreMultiple(target: string, query: IPreparedQueryPiece[], fuzzy: boolean): Score {
let totalScore = NO_MATCH;
const totalPositions: number[] = [];
for (const { normalized, normalizedLowercase } of query) {
const [scoreValue, positions] = scoreSingle(target, normalized, normalizedLowercase, fuzzy);
if (scoreValue === NO_MATCH) {
// if a single query value does not match, return with
// no score entirely, we require all queries to match
return NO_SCORE;
}
totalScore += scoreValue;
totalPositions.push(...positions);
}
if (totalScore === NO_MATCH) {
return NO_SCORE;
}
// if we have a score, ensure that the positions are
// sorted in ascending order and distinct
return [totalScore, distinctES6(totalPositions).sort((a, b) => a - b)];
}
function scoreSingle(target: string, query: string, queryLower: string, fuzzy: boolean): Score {
export function scoreFuzzy(target: string, query: string, queryLower: string, fuzzy: boolean): FuzzyScore {
if (!target || !query) {
return NO_SCORE; // return early if target or query are undefined
}
@ -84,7 +52,7 @@ function scoreSingle(target: string, query: string, queryLower: string, fuzzy: b
}
}
const res = doScore(query, queryLower, queryLength, target, targetLower, targetLength);
const res = doScoreFuzzy(query, queryLower, queryLength, target, targetLower, targetLength);
// if (DEBUG) {
// console.log(`%cFinal Score: ${res[0]}`, 'font-weight: bold');
@ -94,7 +62,7 @@ function scoreSingle(target: string, query: string, queryLower: string, fuzzy: b
return res;
}
function doScore(query: string, queryLower: string, queryLength: number, target: string, targetLower: string, targetLength: number): Score {
function doScoreFuzzy(query: string, queryLower: string, queryLength: number, target: string, targetLower: string, targetLength: number): FuzzyScore {
const scores: number[] = [];
const matches: number[] = [];
@ -291,6 +259,61 @@ function scoreSeparatorAtPos(charCode: number): number {
// }
// }
//#endregion
//#region Alternate fuzzy scorer implementation that is e.g. used for symbols
export type FuzzyScore2 = [number /* score*/, IMatch[]];
const NO_SCORE2: FuzzyScore2 = [NO_MATCH, []];
export function scoreFuzzy2(target: string, query: IPreparedQuery, patternStart = 0, matchOffset = 0): FuzzyScore2 {
// Score: multiple inputs
if (query.values && query.values.length > 1) {
return doScoreFuzzy2Multiple(target, query.values, patternStart, matchOffset);
}
// Score: single input
return doScoreFuzzy2Single(target, query, patternStart, matchOffset);
}
function doScoreFuzzy2Multiple(target: string, query: IPreparedQueryPiece[], patternStart: number, matchOffset: number): FuzzyScore2 {
let totalScore = 0;
const totalMatches: IMatch[] = [];
for (const queryPiece of query) {
const [score, matches] = doScoreFuzzy2Single(target, queryPiece, patternStart, matchOffset);
if (!score) {
// if a single query value does not match, return with
// no score entirely, we require all queries to match
return NO_SCORE2;
}
totalScore += score;
totalMatches.push(...matches);
}
// if we have a score, ensure that the positions are
// sorted in ascending order and distinct
return [totalScore, normalizeMatches(totalMatches)];
}
function doScoreFuzzy2Single(target: string, query: IPreparedQueryPiece, patternStart: number, matchOffset: number): FuzzyScore2 {
const score = fuzzyScore(query.original, query.originalLowercase, patternStart, target, target.toLowerCase(), 0, true);
if (!score) {
return NO_SCORE2;
}
return [score[0], createFuzzyMatches(score, matchOffset)];
}
//#endregion
//#region Item (label, description, path) scorer
/**
* Scoring on structural items that have a label and optional description.
*/
@ -337,99 +360,7 @@ const LABEL_PREFIX_SCORE = 1 << 17;
const LABEL_CAMELCASE_SCORE = 1 << 16;
const LABEL_SCORE_THRESHOLD = 1 << 15;
export interface IPreparedQueryPiece {
/**
* The original query as provided as input.
*/
original: string;
originalLowercase: string;
/**
* Original normalized to platform separators:
* - Windows: \
* - Posix: /
*/
pathNormalized: string;
/**
* In addition to the normalized path, will have
* whitespace and wildcards removed.
*/
normalized: string;
normalizedLowercase: string;
}
export interface IPreparedQuery extends IPreparedQueryPiece {
// Split by spaces
values: IPreparedQueryPiece[] | undefined;
containsPathSeparator: boolean;
}
/**
* Helper function to prepare a search value for scoring by removing unwanted characters
* and allowing to score on multiple pieces separated by whitespace character.
*/
const MULTIPL_QUERY_VALUES_SEPARATOR = ' ';
export function prepareQuery(original: string): IPreparedQuery {
if (typeof original !== 'string') {
original = '';
}
const originalLowercase = original.toLowerCase();
const { pathNormalized, normalized, normalizedLowercase } = normalizeQuery(original);
const containsPathSeparator = pathNormalized.indexOf(sep) >= 0;
let values: IPreparedQueryPiece[] | undefined = undefined;
const originalSplit = original.split(MULTIPL_QUERY_VALUES_SEPARATOR);
if (originalSplit.length > 1) {
for (const originalPiece of originalSplit) {
const {
pathNormalized: pathNormalizedPiece,
normalized: normalizedPiece,
normalizedLowercase: normalizedLowercasePiece
} = normalizeQuery(originalPiece);
if (normalizedPiece) {
if (!values) {
values = [];
}
values.push({
original: originalPiece,
originalLowercase: originalPiece.toLowerCase(),
pathNormalized: pathNormalizedPiece,
normalized: normalizedPiece,
normalizedLowercase: normalizedLowercasePiece
});
}
}
}
return { original, originalLowercase, pathNormalized, normalized, normalizedLowercase, values, containsPathSeparator };
}
function normalizeQuery(original: string): { pathNormalized: string, normalized: string, normalizedLowercase: string } {
let pathNormalized: string;
if (isWindows) {
pathNormalized = original.replace(/\//g, sep); // Help Windows users to search for paths when using slash
} else {
pathNormalized = original.replace(/\\/g, sep); // Help macOS/Linux users to search for paths when using backslash
}
const normalized = stripWildcards(pathNormalized).replace(/\s/g, '');
return {
pathNormalized,
normalized,
normalizedLowercase: normalized.toLowerCase()
};
}
export function scoreItem<T>(item: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, cache: ScorerCache): IItemScore {
export function scoreItemFuzzy<T>(item: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, cache: FuzzyScorerCache): IItemScore {
if (!item || !query.normalized) {
return NO_ITEM_SCORE; // we need an item and query to score on at least
}
@ -453,62 +384,86 @@ export function scoreItem<T>(item: T, query: IPreparedQuery, fuzzy: boolean, acc
return cached;
}
const itemScore = doScoreItem(label, description, accessor.getItemPath(item), query, fuzzy);
const itemScore = doScoreItemFuzzy(label, description, accessor.getItemPath(item), query, fuzzy);
cache[cacheHash] = itemScore;
return itemScore;
}
function createMatches(offsets: undefined | number[]): IMatch[] {
let ret: IMatch[] = [];
if (!offsets) {
return ret;
}
function doScoreItemFuzzy(label: string, description: string | undefined, path: string | undefined, query: IPreparedQuery, fuzzy: boolean): IItemScore {
const preferLabelMatches = !path || !query.containsPathSeparator;
let last: IMatch | undefined;
for (const pos of offsets) {
if (last && last.end === pos) {
last.end += 1;
} else {
last = { start: pos, end: pos + 1 };
ret.push(last);
}
}
return ret;
}
function doScoreItem(label: string, description: string | undefined, path: string | undefined, query: IPreparedQuery, fuzzy: boolean): IItemScore {
// 1.) treat identity matches on full path highest
// Treat identity matches on full path highest
if (path && (isLinux ? query.pathNormalized === path : equalsIgnoreCase(query.pathNormalized, path))) {
return { score: PATH_IDENTITY_SCORE, labelMatch: [{ start: 0, end: label.length }], descriptionMatch: description ? [{ start: 0, end: description.length }] : undefined };
}
// We only consider label matches if the query is not including file path separators
const preferLabelMatches = !path || !query.containsPathSeparator;
// Score: multiple inputs
if (query.values && query.values.length > 1) {
return doScoreItemFuzzyMultiple(label, description, path, query.values, preferLabelMatches, fuzzy);
}
// Score: single input
return doScoreItemFuzzySingle(label, description, path, query, preferLabelMatches, fuzzy);
}
function doScoreItemFuzzyMultiple(label: string, description: string | undefined, path: string | undefined, query: IPreparedQueryPiece[], preferLabelMatches: boolean, fuzzy: boolean): IItemScore {
let totalScore = 0;
const totalLabelMatches: IMatch[] = [];
const totalDescriptionMatches: IMatch[] = [];
for (const queryPiece of query) {
const { score, labelMatch, descriptionMatch } = doScoreItemFuzzySingle(label, description, path, queryPiece, preferLabelMatches, fuzzy);
if (score === NO_MATCH) {
// if a single query value does not match, return with
// no score entirely, we require all queries to match
return NO_ITEM_SCORE;
}
totalScore += score;
if (labelMatch) {
totalLabelMatches.push(...labelMatch);
}
if (descriptionMatch) {
totalDescriptionMatches.push(...descriptionMatch);
}
}
// if we have a score, ensure that the positions are
// sorted in ascending order and distinct
return {
score: totalScore,
labelMatch: normalizeMatches(totalLabelMatches),
descriptionMatch: normalizeMatches(totalDescriptionMatches)
};
}
function doScoreItemFuzzySingle(label: string, description: string | undefined, path: string | undefined, query: IPreparedQueryPiece, preferLabelMatches: boolean, fuzzy: boolean): IItemScore {
// Prefer label matches if told so
if (preferLabelMatches) {
// 2.) treat prefix matches on the label second highest
// Treat prefix matches on the label second highest
const prefixLabelMatch = matchesPrefix(query.normalized, label);
if (prefixLabelMatch) {
return { score: LABEL_PREFIX_SCORE, labelMatch: prefixLabelMatch };
}
// 3.) treat camelcase matches on the label third highest
// Treat camelcase matches on the label third highest
const camelcaseLabelMatch = matchesCamelCase(query.normalized, label);
if (camelcaseLabelMatch) {
return { score: LABEL_CAMELCASE_SCORE, labelMatch: camelcaseLabelMatch };
}
// 4.) prefer scores on the label if any
const [labelScore, labelPositions] = score(label, query, fuzzy);
// Prefer scores on the label if any
const [labelScore, labelPositions] = scoreFuzzy(label, query.normalized, query.normalizedLowercase, fuzzy);
if (labelScore) {
return { score: labelScore + LABEL_SCORE_THRESHOLD, labelMatch: createMatches(labelPositions) };
}
}
// 5.) finally compute description + label scores if we have a description
// Finally compute description + label scores if we have a description
if (description) {
let descriptionPrefix = description;
if (!!path) {
@ -518,7 +473,7 @@ function doScoreItem(label: string, description: string | undefined, path: strin
const descriptionPrefixLength = descriptionPrefix.length;
const descriptionAndLabel = `${descriptionPrefix}${label}`;
const [labelDescriptionScore, labelDescriptionPositions] = score(descriptionAndLabel, query, fuzzy);
const [labelDescriptionScore, labelDescriptionPositions] = scoreFuzzy(descriptionAndLabel, query.normalized, query.normalizedLowercase, fuzzy);
if (labelDescriptionScore) {
const labelDescriptionMatches = createMatches(labelDescriptionPositions);
const labelMatch: IMatch[] = [];
@ -551,9 +506,45 @@ function doScoreItem(label: string, description: string | undefined, path: strin
return NO_ITEM_SCORE;
}
export function compareItemsByScore<T>(itemA: T, itemB: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, cache: ScorerCache): number {
const itemScoreA = scoreItem(itemA, query, fuzzy, accessor, cache);
const itemScoreB = scoreItem(itemB, query, fuzzy, accessor, cache);
function createMatches(offsets: number[] | undefined): IMatch[] {
const ret: IMatch[] = [];
if (!offsets) {
return ret;
}
let last: IMatch | undefined;
for (const pos of offsets) {
if (last && last.end === pos) {
last.end += 1;
} else {
last = { start: pos, end: pos + 1 };
ret.push(last);
}
}
return ret;
}
function normalizeMatches(matches: IMatch[]): IMatch[] {
const positions = new Set<number>();
for (const match of matches) {
for (let i = match.start; i < match.end; i++) {
positions.add(i);
}
}
return createMatches(Array.from(positions.values()).sort((a, b) => a - b));
}
//#endregion
//#region Comparers
export function compareItemsByFuzzyScore<T>(itemA: T, itemB: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, cache: FuzzyScorerCache): number {
const itemScoreA = scoreItemFuzzy(itemA, query, fuzzy, accessor, cache);
const itemScoreB = scoreItemFuzzy(itemB, query, fuzzy, accessor, cache);
const scoreA = itemScoreA.score;
const scoreB = itemScoreB.score;
@ -744,3 +735,112 @@ function fallbackCompare<T>(itemA: T, itemB: T, query: IPreparedQuery, accessor:
// equal
return 0;
}
//#endregion
//#region Query Normalizer
export interface IPreparedQueryPiece {
/**
* The original query as provided as input.
*/
original: string;
originalLowercase: string;
/**
* Original normalized to platform separators:
* - Windows: \
* - Posix: /
*/
pathNormalized: string;
/**
* In addition to the normalized path, will have
* whitespace and wildcards removed.
*/
normalized: string;
normalizedLowercase: string;
}
export interface IPreparedQuery extends IPreparedQueryPiece {
// Split by spaces
values: IPreparedQueryPiece[] | undefined;
containsPathSeparator: boolean;
}
/**
* Helper function to prepare a search value for scoring by removing unwanted characters
* and allowing to score on multiple pieces separated by whitespace character.
*/
const MULTIPLE_QUERY_VALUES_SEPARATOR = ' ';
export function prepareQuery(original: string): IPreparedQuery {
if (typeof original !== 'string') {
original = '';
}
const originalLowercase = original.toLowerCase();
const { pathNormalized, normalized, normalizedLowercase } = normalizeQuery(original);
const containsPathSeparator = pathNormalized.indexOf(sep) >= 0;
let values: IPreparedQueryPiece[] | undefined = undefined;
const originalSplit = original.split(MULTIPLE_QUERY_VALUES_SEPARATOR);
if (originalSplit.length > 1) {
for (const originalPiece of originalSplit) {
const {
pathNormalized: pathNormalizedPiece,
normalized: normalizedPiece,
normalizedLowercase: normalizedLowercasePiece
} = normalizeQuery(originalPiece);
if (normalizedPiece) {
if (!values) {
values = [];
}
values.push({
original: originalPiece,
originalLowercase: originalPiece.toLowerCase(),
pathNormalized: pathNormalizedPiece,
normalized: normalizedPiece,
normalizedLowercase: normalizedLowercasePiece
});
}
}
}
return { original, originalLowercase, pathNormalized, normalized, normalizedLowercase, values, containsPathSeparator };
}
function normalizeQuery(original: string): { pathNormalized: string, normalized: string, normalizedLowercase: string } {
let pathNormalized: string;
if (isWindows) {
pathNormalized = original.replace(/\//g, sep); // Help Windows users to search for paths when using slash
} else {
pathNormalized = original.replace(/\\/g, sep); // Help macOS/Linux users to search for paths when using backslash
}
const normalized = stripWildcards(pathNormalized).replace(/\s/g, '');
return {
pathNormalized,
normalized,
normalizedLowercase: normalized.toLowerCase()
};
}
export function pieceToQuery(piece: IPreparedQueryPiece): IPreparedQuery;
export function pieceToQuery(pieces: IPreparedQueryPiece[]): IPreparedQuery;
export function pieceToQuery(arg1: IPreparedQueryPiece | IPreparedQueryPiece[]): IPreparedQuery {
if (Array.isArray(arg1)) {
return prepareQuery(arg1.map(piece => piece.original).join(MULTIPLE_QUERY_VALUES_SEPARATOR));
}
return prepareQuery(arg1.original);
}
//#endregion

Просмотреть файл

@ -113,6 +113,9 @@ export function mixin(destination: any, source: any, overwrite: boolean = true):
return destination;
}
/**
* @deprecated ES6
*/
export function assign<T>(destination: T): T;
export function assign<T, U>(destination: T, u: U): T & U;
export function assign<T, U, V>(destination: T, u: U, v: V): T & U & V;

Просмотреть файл

@ -33,6 +33,9 @@ export interface ScrollEvent {
export class ScrollState implements IScrollDimensions, IScrollPosition {
_scrollStateBrand: void;
public readonly rawScrollLeft: number;
public readonly rawScrollTop: number;
public readonly width: number;
public readonly scrollWidth: number;
public readonly scrollLeft: number;
@ -55,6 +58,9 @@ export class ScrollState implements IScrollDimensions, IScrollPosition {
scrollHeight = scrollHeight | 0;
scrollTop = scrollTop | 0;
this.rawScrollLeft = scrollLeft; // before validation
this.rawScrollTop = scrollTop; // before validation
if (width < 0) {
width = 0;
}
@ -85,7 +91,9 @@ export class ScrollState implements IScrollDimensions, IScrollPosition {
public equals(other: ScrollState): boolean {
return (
this.width === other.width
this.rawScrollLeft === other.rawScrollLeft
&& this.rawScrollTop === other.rawScrollTop
&& this.width === other.width
&& this.scrollWidth === other.scrollWidth
&& this.scrollLeft === other.scrollLeft
&& this.height === other.height
@ -98,10 +106,10 @@ export class ScrollState implements IScrollDimensions, IScrollPosition {
return new ScrollState(
(typeof update.width !== 'undefined' ? update.width : this.width),
(typeof update.scrollWidth !== 'undefined' ? update.scrollWidth : this.scrollWidth),
this.scrollLeft,
this.rawScrollLeft,
(typeof update.height !== 'undefined' ? update.height : this.height),
(typeof update.scrollHeight !== 'undefined' ? update.scrollHeight : this.scrollHeight),
this.scrollTop
this.rawScrollTop
);
}
@ -109,10 +117,10 @@ export class ScrollState implements IScrollDimensions, IScrollPosition {
return new ScrollState(
this.width,
this.scrollWidth,
(typeof update.scrollLeft !== 'undefined' ? update.scrollLeft : this.scrollLeft),
(typeof update.scrollLeft !== 'undefined' ? update.scrollLeft : this.rawScrollLeft),
this.height,
this.scrollHeight,
(typeof update.scrollTop !== 'undefined' ? update.scrollTop : this.scrollTop)
(typeof update.scrollTop !== 'undefined' ? update.scrollTop : this.rawScrollTop)
);
}

Просмотреть файл

@ -5,45 +5,25 @@
import { URI, UriComponents } from 'vs/base/common/uri';
const _typeof = {
number: 'number',
string: 'string',
undefined: 'undefined',
object: 'object',
function: 'function'
};
/**
* @returns whether the provided parameter is a JavaScript Array or not.
*/
export function isArray(array: any): array is any[] {
if (Array.isArray) {
return Array.isArray(array);
}
if (array && typeof (array.length) === _typeof.number && array.constructor === Array) {
return true;
}
return false;
return Array.isArray(array);
}
/**
* @returns whether the provided parameter is a JavaScript String or not.
*/
export function isString(str: any): str is string {
if (typeof (str) === _typeof.string || str instanceof String) {
return true;
}
return false;
return (typeof str === 'string');
}
/**
* @returns whether the provided parameter is a JavaScript Array and each element in the array is a string.
*/
export function isStringArray(value: any): value is string[] {
return isArray(value) && (<any[]>value).every(elem => isString(elem));
return Array.isArray(value) && (<any[]>value).every(elem => isString(elem));
}
/**
@ -55,7 +35,7 @@ export function isObject(obj: any): obj is Object {
// The method can't do a type cast since there are type (like strings) which
// are subclasses of any put not positvely matched by the function. Hence type
// narrowing results in wrong results.
return typeof obj === _typeof.object
return typeof obj === 'object'
&& obj !== null
&& !Array.isArray(obj)
&& !(obj instanceof RegExp)
@ -67,32 +47,28 @@ export function isObject(obj: any): obj is Object {
* @returns whether the provided parameter is a JavaScript Number or not.
*/
export function isNumber(obj: any): obj is number {
if ((typeof (obj) === _typeof.number || obj instanceof Number) && !isNaN(obj)) {
return true;
}
return false;
return (typeof obj === 'number' && !isNaN(obj));
}
/**
* @returns whether the provided parameter is a JavaScript Boolean or not.
*/
export function isBoolean(obj: any): obj is boolean {
return obj === true || obj === false;
return (obj === true || obj === false);
}
/**
* @returns whether the provided parameter is undefined.
*/
export function isUndefined(obj: any): obj is undefined {
return typeof (obj) === _typeof.undefined;
return (typeof obj === 'undefined');
}
/**
* @returns whether the provided parameter is undefined or null.
*/
export function isUndefinedOrNull(obj: any): obj is undefined | null {
return isUndefined(obj) || obj === null;
return (isUndefined(obj) || obj === null);
}
@ -158,7 +134,7 @@ export function isEmptyObject(obj: any): obj is any {
* @returns whether the provided parameter is a JavaScript Function or not.
*/
export function isFunction(obj: any): obj is Function {
return typeof obj === _typeof.function;
return (typeof obj === 'function');
}
/**

Просмотреть файл

@ -237,11 +237,9 @@
.quick-input-list .quick-input-list-entry-action-bar .action-label {
/*
* By default, actions in the quick input action bar are hidden
* until hovered over them or selected. We do not use display:none
* so that the amount of visual flickering is little by reserving the
* space the button needs still.
* until hovered over them or selected.
*/
visibility: hidden;
display: none;
}
.quick-input-list .quick-input-list-entry-action-bar .action-label.codicon {
@ -266,5 +264,5 @@
.quick-input-list .quick-input-list-entry .quick-input-list-entry-action-bar .action-label.always-visible,
.quick-input-list .quick-input-list-entry:hover .quick-input-list-entry-action-bar .action-label,
.quick-input-list .monaco-list-row.focused .quick-input-list-entry-action-bar .action-label {
visibility: visible;
display: flex;
}

Просмотреть файл

@ -386,7 +386,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
private _matchOnLabel = true;
private _sortByLabel = true;
private _autoFocusOnList = true;
private _itemActivation = ItemActivation.FIRST;
private _itemActivation = this.ui.isScreenReaderOptimized() ? ItemActivation.NONE /* https://github.com/microsoft/vscode/issues/57501 */ : ItemActivation.FIRST;
private _activeItems: T[] = [];
private activeItemsUpdated = false;
private activeItemsToConfirm: T[] | null = [];
@ -637,7 +637,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
private trySelectFirst() {
if (this.autoFocusOnList) {
if (!this.ui.isScreenReaderOptimized() && !this.canSelectMany) {
if (!this.canSelectMany) {
this.ui.list.focus(QuickInputListFocus.First);
}
}
@ -683,22 +683,14 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
event.preventDefault();
break;
case KeyCode.PageDown:
if (this.ui.list.getFocusedElements().length) {
this.ui.list.focus(QuickInputListFocus.NextPage);
} else {
this.ui.list.focus(QuickInputListFocus.First);
}
this.ui.list.focus(QuickInputListFocus.NextPage);
if (this.canSelectMany) {
this.ui.list.domFocus();
}
event.preventDefault();
break;
case KeyCode.PageUp:
if (this.ui.list.getFocusedElements().length) {
this.ui.list.focus(QuickInputListFocus.PreviousPage);
} else {
this.ui.list.focus(QuickInputListFocus.Last);
}
this.ui.list.focus(QuickInputListFocus.PreviousPage);
if (this.canSelectMany) {
this.ui.list.domFocus();
}
@ -875,6 +867,9 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
this.ui.visibleCount.setCount(this.ui.list.getVisibleCount());
this.ui.count.setCount(this.ui.list.getCheckedCount());
switch (this._itemActivation) {
case ItemActivation.NONE:
this._itemActivation = ItemActivation.FIRST; // only valid once, then unset
break;
case ItemActivation.SECOND:
this.ui.list.focus(QuickInputListFocus.Second);
this._itemActivation = ItemActivation.FIRST; // only valid once, then unset
@ -1086,30 +1081,13 @@ export class QuickInputController extends Disposable {
}
private registerKeyModsListeners() {
this._register(dom.addDisposableListener(window, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
const event = new StandardKeyboardEvent(e);
switch (event.keyCode) {
case KeyCode.Ctrl:
case KeyCode.Meta:
this.keyMods.ctrlCmd = true;
break;
case KeyCode.Alt:
this.keyMods.alt = true;
break;
}
}));
this._register(dom.addDisposableListener(window, dom.EventType.KEY_UP, (e: KeyboardEvent) => {
const event = new StandardKeyboardEvent(e);
switch (event.keyCode) {
case KeyCode.Ctrl:
case KeyCode.Meta:
this.keyMods.ctrlCmd = false;
break;
case KeyCode.Alt:
this.keyMods.alt = false;
break;
}
}));
const listener = (e: KeyboardEvent | MouseEvent) => {
this.keyMods.ctrlCmd = e.ctrlKey || e.metaKey;
this.keyMods.alt = e.altKey;
};
this._register(dom.addDisposableListener(window, dom.EventType.KEY_DOWN, listener, true));
this._register(dom.addDisposableListener(window, dom.EventType.KEY_UP, listener, true));
this._register(dom.addDisposableListener(window, dom.EventType.MOUSE_DOWN, listener, true));
}
private getUI() {
@ -1362,6 +1340,9 @@ export class QuickInputController extends Disposable {
];
input.canSelectMany = !!options.canPickMany;
input.placeholder = options.placeHolder;
if (options.placeHolder) {
input.ariaLabel = options.placeHolder;
}
input.ignoreFocusOut = !!options.ignoreFocusLost;
input.matchOnDescription = !!options.matchOnDescription;
input.matchOnDetail = !!options.matchOnDetail;

Просмотреть файл

@ -302,14 +302,12 @@ export class QuickInputList {
}
break;
case KeyCode.UpArrow:
case KeyCode.PageUp:
const focus1 = this.list.getFocus();
if (focus1.length === 1 && focus1[0] === 0) {
this._onLeave.fire();
}
break;
case KeyCode.DownArrow:
case KeyCode.PageDown:
const focus2 = this.list.getFocus();
if (focus2.length === 1 && focus2[0] === this.list.length - 1) {
this._onLeave.fire();
@ -518,11 +516,11 @@ export class QuickInputList {
return;
}
if ((what === QuickInputListFocus.Next || what === QuickInputListFocus.NextPage) && this.list.getFocus()[0] === this.list.length - 1) {
if (what === QuickInputListFocus.Next && this.list.getFocus()[0] === this.list.length - 1) {
what = QuickInputListFocus.First;
}
if ((what === QuickInputListFocus.Previous || what === QuickInputListFocus.PreviousPage) && this.list.getFocus()[0] === 0) {
if (what === QuickInputListFocus.Previous && this.list.getFocus()[0] === 0) {
what = QuickInputListFocus.Last;
}

Просмотреть файл

@ -183,7 +183,8 @@ export interface IQuickPickAcceptEvent {
}
export enum ItemActivation {
FIRST = 1,
NONE,
FIRST,
SECOND,
LAST
}
@ -326,7 +327,7 @@ export type QuickPickInput<T = IQuickPickItem> = T | IQuickPickSeparator;
//region Fuzzy Scorer Support
export type IQuickPickItemWithResource = IQuickPickItem & { resource: URI | undefined };
export type IQuickPickItemWithResource = IQuickPickItem & { resource?: URI };
export class QuickPickItemScorerAccessor implements IItemAccessor<IQuickPickItemWithResource> {

Просмотреть файл

@ -42,20 +42,28 @@ class NullAccessorClass implements scorer.IItemAccessor<URI> {
}
}
function _doScore(target: string, query: string, fuzzy: boolean): scorer.Score {
return scorer.score(target, scorer.prepareQuery(query), fuzzy);
function _doScore(target: string, query: string, fuzzy: boolean): scorer.FuzzyScore {
const preparedQuery = scorer.prepareQuery(query);
return scorer.scoreFuzzy(target, preparedQuery.normalized, preparedQuery.normalizedLowercase, fuzzy);
}
function scoreItem<T>(item: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor<T>, cache: scorer.ScorerCache): scorer.IItemScore {
return scorer.scoreItem(item, scorer.prepareQuery(query), fuzzy, accessor, cache);
function _doScore2(target: string, query: string): scorer.FuzzyScore2 {
const preparedQuery = scorer.prepareQuery(query);
return scorer.scoreFuzzy2(target, preparedQuery);
}
function compareItemsByScore<T>(itemA: T, itemB: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor<T>, cache: scorer.ScorerCache): number {
return scorer.compareItemsByScore(itemA, itemB, scorer.prepareQuery(query), fuzzy, accessor, cache);
function scoreItem<T>(item: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor<T>, cache: scorer.FuzzyScorerCache): scorer.IItemScore {
return scorer.scoreItemFuzzy(item, scorer.prepareQuery(query), fuzzy, accessor, cache);
}
function compareItemsByScore<T>(itemA: T, itemB: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor<T>, cache: scorer.FuzzyScorerCache): number {
return scorer.compareItemsByFuzzyScore(itemA, itemB, scorer.prepareQuery(query), fuzzy, accessor, cache);
}
const NullAccessor = new NullAccessorClass();
let cache: scorer.ScorerCache = Object.create(null);
let cache: scorer.FuzzyScorerCache = Object.create(null);
suite('Fuzzy Scorer', () => {
@ -66,7 +74,7 @@ suite('Fuzzy Scorer', () => {
test('score (fuzzy)', function () {
const target = 'HeLlo-World';
const scores: scorer.Score[] = [];
const scores: scorer.FuzzyScore[] = [];
scores.push(_doScore(target, 'HelLo-World', true)); // direct case match
scores.push(_doScore(target, 'hello-world', true)); // direct mix-case match
scores.push(_doScore(target, 'HW', true)); // direct case prefix (multiple)
@ -109,42 +117,6 @@ suite('Fuzzy Scorer', () => {
assert.equal(_doScore(target, 'eo', false)[0], 0);
});
test('score (fuzzy, multiple)', function () {
const target = 'HeLlo-World';
const [firstSingleScore, firstSinglePositions] = _doScore(target, 'HelLo', true);
const [secondSingleScore, secondSinglePositions] = _doScore(target, 'World', true);
const firstAndSecondSinglePositions = [...firstSinglePositions, ...secondSinglePositions];
let [multiScore, multiPositions] = _doScore(target, 'HelLo World', true);
function assertScore() {
assert.ok(multiScore >= firstSingleScore + secondSingleScore);
for (let i = 0; i < multiPositions.length; i++) {
assert.equal(multiPositions[i], firstAndSecondSinglePositions[i]);
}
}
function assertNoScore() {
assert.equal(multiScore, 0);
assert.equal(multiPositions.length, 0);
}
assertScore();
[multiScore, multiPositions] = _doScore(target, 'World HelLo', true);
assertScore();
[multiScore, multiPositions] = _doScore(target, 'World HelLo World', true);
assertScore();
[multiScore, multiPositions] = _doScore(target, 'World HelLo Nothing', true);
assertNoScore();
[multiScore, multiPositions] = _doScore(target, 'More Nothing', true);
assertNoScore();
});
test('scoreItem - matches are proper', function () {
let res = scoreItem(null, 'something', true, ResourceAccessor, cache);
assert.ok(!res.score);
@ -217,6 +189,49 @@ suite('Fuzzy Scorer', () => {
assert.ok(pathRes.score > noRes.score);
});
test('scoreItem - multiple', function () {
const resource = URI.file('/xyz/some/path/someFile123.txt');
let res1 = scoreItem(resource, 'xyz some', true, ResourceAccessor, cache);
assert.ok(res1.score);
assert.equal(res1.labelMatch?.length, 1);
assert.equal(res1.labelMatch![0].start, 0);
assert.equal(res1.labelMatch![0].end, 4);
assert.equal(res1.descriptionMatch?.length, 1);
assert.equal(res1.descriptionMatch![0].start, 1);
assert.equal(res1.descriptionMatch![0].end, 4);
let res2 = scoreItem(resource, 'some xyz', true, ResourceAccessor, cache);
assert.ok(res2.score);
assert.equal(res1.score, res2.score);
assert.equal(res2.labelMatch?.length, 1);
assert.equal(res2.labelMatch![0].start, 0);
assert.equal(res2.labelMatch![0].end, 4);
assert.equal(res2.descriptionMatch?.length, 1);
assert.equal(res2.descriptionMatch![0].start, 1);
assert.equal(res2.descriptionMatch![0].end, 4);
let res3 = scoreItem(resource, 'some xyz file file123', true, ResourceAccessor, cache);
assert.ok(res3.score);
assert.ok(res3.score > res2.score);
assert.equal(res3.labelMatch?.length, 1);
assert.equal(res3.labelMatch![0].start, 0);
assert.equal(res3.labelMatch![0].end, 11);
assert.equal(res3.descriptionMatch?.length, 1);
assert.equal(res3.descriptionMatch![0].start, 1);
assert.equal(res3.descriptionMatch![0].end, 4);
let res4 = scoreItem(resource, 'path z y', true, ResourceAccessor, cache);
assert.ok(res4.score);
assert.ok(res4.score < res2.score);
assert.equal(res4.labelMatch?.length, 0);
assert.equal(res4.descriptionMatch?.length, 2);
assert.equal(res4.descriptionMatch![0].start, 2);
assert.equal(res4.descriptionMatch![0].end, 4);
assert.equal(res4.descriptionMatch![1].start, 10);
assert.equal(res4.descriptionMatch![1].end, 14);
});
test('scoreItem - invalid input', function () {
let res = scoreItem(null, null!, true, ResourceAccessor, cache);
@ -878,6 +893,11 @@ suite('Fuzzy Scorer', () => {
assert.equal(query.values?.[1].normalized, 'World');
assert.equal(query.values?.[1].normalizedLowercase, 'World'.toLowerCase());
let restoredQuery = scorer.pieceToQuery(query.values!);
assert.equal(restoredQuery.original, query.original);
assert.equal(restoredQuery.values?.length, query.values?.length);
assert.equal(restoredQuery.containsPathSeparator, query.containsPathSeparator);
// with spaces that are empty
query = scorer.prepareQuery(' Hello World ');
assert.equal(query.original, ' Hello World ');
@ -911,4 +931,48 @@ suite('Fuzzy Scorer', () => {
assert.equal(scorer.prepareQuery('\\some\\path').containsPathSeparator, true);
}
});
test('fuzzyScore2 (multiple queries)', function () {
const target = 'HeLlo-World';
const [firstSingleScore, firstSingleMatches] = _doScore2(target, 'HelLo');
const [secondSingleScore, secondSingleMatches] = _doScore2(target, 'World');
const firstAndSecondSingleMatches = [...firstSingleMatches || [], ...secondSingleMatches || []];
let [multiScore, multiMatches] = _doScore2(target, 'HelLo World');
function assertScore() {
assert.ok(multiScore ?? 0 >= ((firstSingleScore ?? 0) + (secondSingleScore ?? 0)));
for (let i = 0; multiMatches && i < multiMatches.length; i++) {
const multiMatch = multiMatches[i];
const firstAndSecondSingleMatch = firstAndSecondSingleMatches[i];
if (multiMatch && firstAndSecondSingleMatch) {
assert.equal(multiMatch.start, firstAndSecondSingleMatch.start);
assert.equal(multiMatch.end, firstAndSecondSingleMatch.end);
} else {
assert.fail();
}
}
}
function assertNoScore() {
assert.equal(multiScore, 0);
assert.equal(multiMatches.length, 0);
}
assertScore();
[multiScore, multiMatches] = _doScore2(target, 'World HelLo');
assertScore();
[multiScore, multiMatches] = _doScore2(target, 'World HelLo World');
assertScore();
[multiScore, multiMatches] = _doScore2(target, 'World HelLo Nothing');
assertNoScore();
[multiScore, multiMatches] = _doScore2(target, 'More Nothing');
assertNoScore();
});
});

Просмотреть файл

@ -704,6 +704,11 @@ export interface ICodeEditor extends editorCommon.IEditor {
*/
getVisibleRanges(): Range[];
/**
* @internal
*/
getVisibleRangesPlusViewportAboveBelow(): Range[];
/**
* Get the view zones.
* @internal

Просмотреть файл

@ -460,6 +460,13 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
return this._modelData.viewModel.getVisibleRanges();
}
public getVisibleRangesPlusViewportAboveBelow(): Range[] {
if (!this._modelData) {
return [];
}
return this._modelData.viewModel.getVisibleRangesPlusViewportAboveBelow();
}
public getWhitespaces(): IEditorWhitespace[] {
if (!this._modelData) {
return [];

Просмотреть файл

@ -890,15 +890,18 @@ export class TokensStore2 {
}
public setPartial(_range: Range, pieces: MultilineTokens2[]): Range {
if (pieces.length === 0) {
return _range;
// console.log(`setPartial ${_range} ${pieces.map(p => p.toString()).join(', ')}`);
let range = _range;
if (pieces.length > 0) {
const _firstRange = pieces[0].getRange();
const _lastRange = pieces[pieces.length - 1].getRange();
if (!_firstRange || !_lastRange) {
return _range;
}
range = _range.plusRange(_firstRange).plusRange(_lastRange);
}
const _firstRange = pieces[0].getRange();
const _lastRange = pieces[pieces.length - 1].getRange();
if (!_firstRange || !_lastRange) {
return _range;
}
const range = _range.plusRange(_firstRange).plusRange(_lastRange);
let insertPosition: { index: number; } | null = null;
for (let i = 0, len = this._pieces.length; i < len; i++) {
const piece = this._pieces[i];
@ -938,6 +941,15 @@ export class TokensStore2 {
// after removal, this piece contains the range
const [a, b] = piece.split(range);
if (a.isEmpty()) {
// this piece is actually after the range
insertPosition = insertPosition || { index: i };
continue;
}
if (b.isEmpty()) {
// this piece is actually before the range
continue;
}
this._pieces.splice(i, 1, a, b);
i++;
len++;
@ -947,10 +959,12 @@ export class TokensStore2 {
insertPosition = insertPosition || { index: this._pieces.length };
this._pieces = arrays.arrayInsert(this._pieces, insertPosition.index, pieces);
if (pieces.length > 0) {
this._pieces = arrays.arrayInsert(this._pieces, insertPosition.index, pieces);
}
// console.log(`I HAVE ${this._pieces.length} pieces`);
// console.log(`${this._pieces.map(p => p.toString()).join(', ')}`);
// console.log(`${this._pieces.map(p => p.toString()).join('\n')}`);
return range;
}

Просмотреть файл

@ -473,7 +473,7 @@ export class ModelServiceImpl extends Disposable implements IModelService {
const model = modelData.model;
let maintainUndoRedoStack = false;
let heapSize = 0;
if (MAINTAIN_UNDO_REDO_STACK && (resource.scheme === Schemas.file || resource.scheme === Schemas.vscodeRemote)) {
if (MAINTAIN_UNDO_REDO_STACK && (resource.scheme === Schemas.file || resource.scheme === Schemas.vscodeRemote || resource.scheme === Schemas.userData)) {
const elements = this._undoRedoService.getElements(resource);
if ((elements.past.length > 0 || elements.future.length > 0) && isEditStackPastFutureElements(elements)) {
maintainUndoRedoStack = true;
@ -577,9 +577,17 @@ export interface ILineSequence {
getLineContent(lineNumber: number): string;
}
class SemanticColoringFeature extends Disposable {
export const SEMANTIC_HIGHLIGHTING_SETTING_ID = 'editor.semanticHighlighting';
private static readonly SETTING_ID = 'editor.semanticHighlighting';
export function isSemanticColoringEnabled(model: ITextModel, themeService: IThemeService, configurationService: IConfigurationService): boolean {
if (!themeService.getColorTheme().semanticHighlighting) {
return false;
}
const options = configurationService.getValue<IEditorSemanticHighlightingOptions>(SEMANTIC_HIGHLIGHTING_SETTING_ID, { overrideIdentifier: model.getLanguageIdentifier().language, resource: model.uri });
return Boolean(options && options.enabled);
}
class SemanticColoringFeature extends Disposable {
private readonly _watchers: Record<string, ModelSemanticColoring>;
private readonly _semanticStyling: SemanticStyling;
@ -589,13 +597,6 @@ class SemanticColoringFeature extends Disposable {
this._watchers = Object.create(null);
this._semanticStyling = semanticStyling;
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;
};
const register = (model: ITextModel) => {
this._watchers[model.uri.toString()] = new ModelSemanticColoring(model, themeService, this._semanticStyling);
};
@ -606,7 +607,7 @@ class SemanticColoringFeature extends Disposable {
const handleSettingOrThemeChange = () => {
for (let model of modelService.getModels()) {
const curr = this._watchers[model.uri.toString()];
if (isSemanticColoringEnabled(model)) {
if (isSemanticColoringEnabled(model, themeService, configurationService)) {
if (!curr) {
register(model);
}
@ -618,7 +619,7 @@ class SemanticColoringFeature extends Disposable {
}
};
this._register(modelService.onModelAdded((model) => {
if (isSemanticColoringEnabled(model)) {
if (isSemanticColoringEnabled(model, themeService, configurationService)) {
register(model);
}
}));
@ -629,7 +630,7 @@ class SemanticColoringFeature extends Disposable {
}
}));
this._register(configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(SemanticColoringFeature.SETTING_ID)) {
if (e.affectsConfiguration(SEMANTIC_HIGHLIGHTING_SETTING_ID)) {
handleSettingOrThemeChange();
}
}));

Просмотреть файл

@ -402,8 +402,26 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
this._updateConfigurationViewLineCount.schedule();
}
public getVisibleRangesPlusViewportAboveBelow(): Range[] {
const layoutInfo = this.configuration.options.get(EditorOption.layoutInfo);
const lineHeight = this.configuration.options.get(EditorOption.lineHeight);
const linesAround = Math.max(20, Math.round(layoutInfo.height / lineHeight));
const partialData = this.viewLayout.getLinesViewportData();
const startViewLineNumber = Math.max(1, partialData.completelyVisibleStartLineNumber - linesAround);
const endViewLineNumber = Math.min(this.getLineCount(), partialData.completelyVisibleEndLineNumber + linesAround);
return this._toModelVisibleRanges(new Range(
startViewLineNumber, this.getLineMinColumn(startViewLineNumber),
endViewLineNumber, this.getLineMaxColumn(endViewLineNumber)
));
}
public getVisibleRanges(): Range[] {
const visibleViewRange = this.getCompletelyVisibleViewRange();
return this._toModelVisibleRanges(visibleViewRange);
}
private _toModelVisibleRanges(visibleViewRange: Range): Range[] {
const visibleRange = this.coordinatesConverter.convertViewRangeToModelRange(visibleViewRange);
const hiddenAreas = this.lines.getHiddenAreas();

Просмотреть файл

@ -924,7 +924,8 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
return null;
}
try {
new RegExp(value);
// use `g` and `u` which are also used by the TextModel search
new RegExp(value, 'gu');
return null;
} catch (e) {
return { content: e.message };

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.14646 9.76783L8.14644 14.7678L8.85355 14.7678L13.8535 9.76783L13.1464 9.06072L9 13.2072L9 1.00006L8 1.00006L8 13.2072L3.85356 9.06072L3.14646 9.76783Z" fill="#C5C5C5"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 324 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.14646 9.76783L8.14644 14.7678L8.85355 14.7678L13.8535 9.76783L13.1464 9.06072L9 13.2072L9 1.00006L8 1.00006L8 13.2072L3.85356 9.06072L3.14646 9.76783Z" fill="#424242"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 324 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.8535 6.29284L8.85356 1.29285H8.14645L3.14645 6.29284L3.85356 6.99995L8 2.85351V15.0606H9V2.85351L13.1464 6.99995L13.8535 6.29284Z" fill="#C5C5C5"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 304 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.8535 6.29284L8.85356 1.29285H8.14645L3.14645 6.29284L3.85356 6.99995L8 2.85351V15.0606H9V2.85351L13.1464 6.99995L13.8535 6.29284Z" fill="#424242"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 304 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 8.70714L11.6464 12.3536L12.3536 11.6465L8.70711 8.00004L12.3536 4.35359L11.6464 3.64648L8 7.29293L4.35355 3.64648L3.64645 4.35359L7.29289 8.00004L3.64645 11.6465L4.35355 12.3536L8 8.70714Z" fill="#C5C5C5"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 362 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 8.70714L11.6464 12.3536L12.3536 11.6465L8.70711 8.00004L12.3536 4.35359L11.6464 3.64648L8 7.29293L4.35355 3.64648L3.64645 4.35359L7.29289 8.00004L3.64645 11.6465L4.35355 12.3536L8 8.70714Z" fill="#424242"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 362 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 12L1 11H10V12H1ZM1 7H15V8H1L1 7ZM12 3V4H1L1 3H12Z" fill="#C5C5C5"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 183 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 12L1 11H10V12H1ZM1 7H15V8H1L1 7ZM12 3V4H1L1 3H12Z" fill="#424242"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 183 B

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.6009 2.67683C11.7474 2.36708 11.9559 2.2122 12.2263 2.2122C12.4742 2.2122 12.6651 2.32987 12.7991 2.56522C12.933 2.80056 13 3.12243 13 3.53082C13 3.97383 12.9218 4.32944 12.7653 4.59766C12.6088 4.86589 12.3997 5 12.138 5C11.9014 5 11.7224 4.87541 11.6009 4.62622H11.5934V4.93511H11V1H11.5934V2.67683H11.6009ZM11.584 3.77742C11.584 3.94873 11.6197 4.09063 11.6911 4.20311C11.7624 4.3156 11.8538 4.37184 11.9653 4.37184C12.1005 4.37184 12.205 4.30002 12.2789 4.15639C12.354 4.01103 12.3915 3.80597 12.3915 3.54121C12.3915 3.32144 12.3571 3.15012 12.2883 3.02726C12.2207 2.90266 12.1236 2.84036 11.9972 2.84036C11.8782 2.84036 11.7793 2.9018 11.7005 3.02466C11.6228 3.14752 11.584 3.30759 11.584 3.50487V3.77742ZM4.11969 7.695L2 5.56781L2.66188 4.90594L3.66781 5.90625V4.39594C3.66695 4.21309 3.70219 4.03187 3.7715 3.86266C3.84082 3.69346 3.94286 3.53961 4.07176 3.40992C4.20066 3.28023 4.3539 3.17727 4.52268 3.10692C4.69146 3.03658 4.87246 3.00024 5.05531 3H7.39906V3.90469H5.05531C4.92856 3.91026 4.8089 3.96476 4.72149 4.05672C4.63408 4.14868 4.58571 4.27094 4.58656 4.39781L4.59406 5.89781L5.54281 4.95375L6.19906 5.61L4.11969 7.695ZM9.3556 4.93017H10V3.22067C10 2.40689 9.68534 2 9.05603 2C8.92098 2 8.77083 2.02421 8.6056 2.07263C8.44181 2.12104 8.3125 2.17691 8.21767 2.24022V2.90503C8.45474 2.70205 8.70474 2.60056 8.96767 2.60056C9.22917 2.60056 9.35991 2.75698 9.35991 3.06983L8.76078 3.17318C8.25359 3.25885 8 3.57914 8 4.13408C8 4.39665 8.06106 4.60708 8.18319 4.76536C8.30675 4.92179 8.47557 5 8.68966 5C8.97989 5 9.19899 4.83985 9.34698 4.51955H9.3556V4.93017ZM9.35991 3.57542V3.76816C9.35991 3.9432 9.31968 4.08845 9.23922 4.20391C9.15876 4.3175 9.0546 4.3743 8.92672 4.3743C8.83477 4.3743 8.76149 4.34264 8.7069 4.27933C8.65374 4.21415 8.62716 4.13128 8.62716 4.03073C8.62716 3.80912 8.73779 3.6797 8.95905 3.64246L9.35991 3.57542ZM7 12.9302H6.3556V12.5196H6.34698C6.19899 12.8399 5.97989 13 5.68966 13C5.47557 13 5.30675 12.9218 5.18319 12.7654C5.06106 12.6071 5 12.3966 5 12.1341C5 11.5791 5.25359 11.2588 5.76078 11.1732L6.35991 11.0698C6.35991 10.757 6.22917 10.6006 5.96767 10.6006C5.70474 10.6006 5.45474 10.702 5.21767 10.905V10.2402C5.3125 10.1769 5.44181 10.121 5.6056 10.0726C5.77083 10.0242 5.92098 10 6.05603 10C6.68534 10 7 10.4069 7 11.2207V12.9302ZM6.35991 11.7682V11.5754L5.95905 11.6425C5.73779 11.6797 5.62716 11.8091 5.62716 12.0307C5.62716 12.1313 5.65374 12.2142 5.7069 12.2793C5.76149 12.3426 5.83477 12.3743 5.92672 12.3743C6.0546 12.3743 6.15876 12.3175 6.23922 12.2039C6.31968 12.0885 6.35991 11.9432 6.35991 11.7682ZM9.26165 13C9.58343 13 9.82955 12.9423 10 12.8268V12.1173C9.81999 12.2551 9.636 12.324 9.44803 12.324C9.23616 12.324 9.06969 12.2523 8.94863 12.1089C8.82756 11.9637 8.76702 11.7644 8.76702 11.5112C8.76702 11.2505 8.82995 11.0466 8.95579 10.8994C9.08323 10.7505 9.25528 10.676 9.47192 10.676C9.66627 10.676 9.84229 10.7449 10 10.8827V10.1341C9.87097 10.0447 9.66229 10 9.37395 10C8.95659 10 8.62286 10.1406 8.37276 10.4218C8.12425 10.7011 8 11.0838 8 11.5698C8 11.9907 8.11629 12.3343 8.34887 12.6006C8.58144 12.8669 8.8857 13 9.26165 13ZM2 9L3 8H12L13 9V14L12 15H3L2 14V9ZM3 9V14H12V9H3ZM6 7L7 6H14L15 7V12L14 13V12V7H7H6Z" fill="#C5C5C5"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 3.3 KiB

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.6009 2.67683C11.7474 2.36708 11.9559 2.2122 12.2263 2.2122C12.4742 2.2122 12.6651 2.32987 12.7991 2.56522C12.933 2.80056 13 3.12243 13 3.53082C13 3.97383 12.9218 4.32944 12.7653 4.59766C12.6088 4.86589 12.3997 5 12.138 5C11.9014 5 11.7224 4.87541 11.6009 4.62622H11.5934V4.93511H11V1H11.5934V2.67683H11.6009ZM11.584 3.77742C11.584 3.94873 11.6197 4.09063 11.6911 4.20311C11.7624 4.3156 11.8538 4.37184 11.9653 4.37184C12.1005 4.37184 12.205 4.30002 12.2789 4.15639C12.354 4.01103 12.3915 3.80597 12.3915 3.54121C12.3915 3.32144 12.3571 3.15012 12.2883 3.02726C12.2207 2.90266 12.1236 2.84036 11.9972 2.84036C11.8782 2.84036 11.7793 2.9018 11.7005 3.02466C11.6228 3.14752 11.584 3.30759 11.584 3.50487V3.77742ZM4.11969 7.695L2 5.56781L2.66188 4.90594L3.66781 5.90625V4.39594C3.66695 4.21309 3.70219 4.03187 3.7715 3.86266C3.84082 3.69346 3.94286 3.53961 4.07176 3.40992C4.20066 3.28023 4.3539 3.17727 4.52268 3.10692C4.69146 3.03658 4.87246 3.00024 5.05531 3H7.39906V3.90469H5.05531C4.92856 3.91026 4.8089 3.96476 4.72149 4.05672C4.63408 4.14868 4.58571 4.27094 4.58656 4.39781L4.59406 5.89781L5.54281 4.95375L6.19906 5.61L4.11969 7.695ZM9.3556 4.93017H10V3.22067C10 2.40689 9.68534 2 9.05603 2C8.92098 2 8.77083 2.02421 8.6056 2.07263C8.44181 2.12104 8.3125 2.17691 8.21767 2.24022V2.90503C8.45474 2.70205 8.70474 2.60056 8.96767 2.60056C9.22917 2.60056 9.35991 2.75698 9.35991 3.06983L8.76078 3.17318C8.25359 3.25885 8 3.57914 8 4.13408C8 4.39665 8.06106 4.60708 8.18319 4.76536C8.30675 4.92179 8.47557 5 8.68966 5C8.97989 5 9.19899 4.83985 9.34698 4.51955H9.3556V4.93017ZM9.35991 3.57542V3.76816C9.35991 3.9432 9.31968 4.08845 9.23922 4.20391C9.15876 4.3175 9.0546 4.3743 8.92672 4.3743C8.83477 4.3743 8.76149 4.34264 8.7069 4.27933C8.65374 4.21415 8.62716 4.13128 8.62716 4.03073C8.62716 3.80912 8.73779 3.6797 8.95905 3.64246L9.35991 3.57542ZM7 12.9302H6.3556V12.5196H6.34698C6.19899 12.8399 5.97989 13 5.68966 13C5.47557 13 5.30675 12.9218 5.18319 12.7654C5.06106 12.6071 5 12.3966 5 12.1341C5 11.5791 5.25359 11.2588 5.76078 11.1732L6.35991 11.0698C6.35991 10.757 6.22917 10.6006 5.96767 10.6006C5.70474 10.6006 5.45474 10.702 5.21767 10.905V10.2402C5.3125 10.1769 5.44181 10.121 5.6056 10.0726C5.77083 10.0242 5.92098 10 6.05603 10C6.68534 10 7 10.4069 7 11.2207V12.9302ZM6.35991 11.7682V11.5754L5.95905 11.6425C5.73779 11.6797 5.62716 11.8091 5.62716 12.0307C5.62716 12.1313 5.65374 12.2142 5.7069 12.2793C5.76149 12.3426 5.83477 12.3743 5.92672 12.3743C6.0546 12.3743 6.15876 12.3175 6.23922 12.2039C6.31968 12.0885 6.35991 11.9432 6.35991 11.7682ZM9.26165 13C9.58343 13 9.82955 12.9423 10 12.8268V12.1173C9.81999 12.2551 9.636 12.324 9.44803 12.324C9.23616 12.324 9.06969 12.2523 8.94863 12.1089C8.82756 11.9637 8.76702 11.7644 8.76702 11.5112C8.76702 11.2505 8.82995 11.0466 8.95579 10.8994C9.08323 10.7505 9.25528 10.676 9.47192 10.676C9.66627 10.676 9.84229 10.7449 10 10.8827V10.1341C9.87097 10.0447 9.66229 10 9.37395 10C8.95659 10 8.62286 10.1406 8.37276 10.4218C8.12425 10.7011 8 11.0838 8 11.5698C8 11.9907 8.11629 12.3343 8.34887 12.6006C8.58144 12.8669 8.8857 13 9.26165 13ZM2 9L3 8H12L13 9V14L12 15H3L2 14V9ZM3 9V14H12V9H3ZM6 7L7 6H14L15 7V12L14 13V12V7H7H6Z" fill="#424242"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 3.3 KiB

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.221 3.739L5.482 6.008L7.7 3.784L7 3.084L5.988 4.091L5.98 2.491C5.97909 2.35567 6.03068 2.22525 6.12392 2.12716C6.21716 2.02908 6.3448 1.97095 6.48 1.965H8V1H6.48C6.28496 1.00026 6.09189 1.03902 5.91186 1.11405C5.73183 1.18908 5.56838 1.29892 5.43088 1.43725C5.29338 1.57558 5.18455 1.73969 5.11061 1.92018C5.03667 2.10066 4.99908 2.29396 5 2.489V4.1L3.927 3.033L3.221 3.739ZM9.89014 5.53277H9.90141C10.0836 5.84426 10.3521 6 10.707 6C11.0995 6 11.4131 5.83236 11.6479 5.49708C11.8826 5.1618 12 4.71728 12 4.16353C12 3.65304 11.8995 3.2507 11.6986 2.95652C11.4977 2.66234 11.2113 2.51525 10.8394 2.51525C10.4338 2.51525 10.1211 2.70885 9.90141 3.09604H9.89014V1H9V5.91888H9.89014V5.53277ZM9.87606 4.47177V4.13108C9.87606 3.88449 9.93427 3.6844 10.0507 3.53082C10.169 3.37724 10.3174 3.30045 10.4958 3.30045C10.6854 3.30045 10.831 3.37833 10.9324 3.53407C11.0357 3.68765 11.0873 3.9018 11.0873 4.17651C11.0873 4.50746 11.031 4.76379 10.9183 4.94549C10.8075 5.12503 10.6507 5.2148 10.4479 5.2148C10.2808 5.2148 10.1437 5.14449 10.0366 5.00389C9.92958 4.86329 9.87606 4.68592 9.87606 4.47177ZM9 12.7691C8.74433 12.923 8.37515 13 7.89247 13C7.32855 13 6.87216 12.8225 6.5233 12.4674C6.17443 12.1124 6 11.6543 6 11.0931C6 10.4451 6.18638 9.93484 6.55914 9.5624C6.93429 9.18747 7.43489 9.00001 8.06093 9.00001C8.49343 9.00001 8.80645 9.0596 9 9.17878V10.1769C8.76344 9.99319 8.4994 9.90132 8.20789 9.90132C7.88292 9.90132 7.62485 10.0006 7.43369 10.1993C7.24492 10.3954 7.15054 10.6673 7.15054 11.0149C7.15054 11.3526 7.24134 11.6183 7.42294 11.8119C7.60454 12.0031 7.85424 12.0987 8.17204 12.0987C8.454 12.0987 8.72999 12.0068 9 11.8231V12.7691ZM4 7L3 8V14L4 15H11L12 14V8L11 7H4ZM4 8H5H10H11V9V13V14H10H5H4V13V9V8Z" fill="#C5C5C5"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 1.8 KiB

Просмотреть файл

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.221 3.739L5.482 6.008L7.7 3.784L7 3.084L5.988 4.091L5.98 2.491C5.97909 2.35567 6.03068 2.22525 6.12392 2.12716C6.21716 2.02908 6.3448 1.97095 6.48 1.965H8V1H6.48C6.28496 1.00026 6.09189 1.03902 5.91186 1.11405C5.73183 1.18908 5.56838 1.29892 5.43088 1.43725C5.29338 1.57558 5.18455 1.73969 5.11061 1.92018C5.03667 2.10066 4.99908 2.29396 5 2.489V4.1L3.927 3.033L3.221 3.739ZM9.89014 5.53277H9.90141C10.0836 5.84426 10.3521 6 10.707 6C11.0995 6 11.4131 5.83236 11.6479 5.49708C11.8826 5.1618 12 4.71728 12 4.16353C12 3.65304 11.8995 3.2507 11.6986 2.95652C11.4977 2.66234 11.2113 2.51525 10.8394 2.51525C10.4338 2.51525 10.1211 2.70885 9.90141 3.09604H9.89014V1H9V5.91888H9.89014V5.53277ZM9.87606 4.47177V4.13108C9.87606 3.88449 9.93427 3.6844 10.0507 3.53082C10.169 3.37724 10.3174 3.30045 10.4958 3.30045C10.6854 3.30045 10.831 3.37833 10.9324 3.53407C11.0357 3.68765 11.0873 3.9018 11.0873 4.17651C11.0873 4.50746 11.031 4.76379 10.9183 4.94549C10.8075 5.12503 10.6507 5.2148 10.4479 5.2148C10.2808 5.2148 10.1437 5.14449 10.0366 5.00389C9.92958 4.86329 9.87606 4.68592 9.87606 4.47177ZM9 12.7691C8.74432 12.923 8.37515 13 7.89247 13C7.32855 13 6.87216 12.8225 6.5233 12.4674C6.17443 12.1124 6 11.6543 6 11.0931C6 10.4451 6.18638 9.93484 6.55914 9.5624C6.93429 9.18747 7.43489 9.00001 8.06093 9.00001C8.49343 9.00001 8.80645 9.0596 9 9.17878V10.1769C8.76344 9.99319 8.4994 9.90132 8.20789 9.90132C7.88292 9.90132 7.62485 10.0006 7.43369 10.1993C7.24492 10.3954 7.15054 10.6673 7.15054 11.0149C7.15054 11.3526 7.24134 11.6183 7.42294 11.8119C7.60454 12.0031 7.85424 12.0987 8.17204 12.0987C8.454 12.0987 8.72999 12.0068 9 11.8231V12.7691ZM4 7L3 8V14L4 15H11L12 14V8L11 7H4ZM4 8H5H10H11V9V13V14H10H5H4V13V9V8Z" fill="#424242"/>
</svg>

До

Ширина:  |  Высота:  |  Размер: 1.8 KiB

Просмотреть файл

@ -563,11 +563,8 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
const disposables = new DisposableStore();
const actionsElement = dom.append(hoverElement, $('div.actions'));
if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) {
const peekProblemLabel = nls.localize('peek problem', "Peek Problem");
const peekProblemKeybinding = this._keybindingService.lookupKeybinding(NextMarkerAction.ID);
const peekProblemKeybindingLabel = peekProblemKeybinding && peekProblemKeybinding.getLabel();
disposables.add(this.renderAction(actionsElement, {
label: peekProblemKeybindingLabel ? nls.localize('titleAndKb', "{0} ({1})", peekProblemLabel, peekProblemKeybindingLabel) : peekProblemLabel,
label: nls.localize('peek problem', "Peek Problem"),
commandId: NextMarkerAction.ID,
run: () => {
this.hide();
@ -604,12 +601,8 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
}
}));
const quickFixLabel = nls.localize('quick fixes', "Quick Fix...");
const quickFixKeybinding = this._keybindingService.lookupKeybinding(QuickFixAction.Id);
const quickFixKeybindingLabel = quickFixKeybinding && quickFixKeybinding.getLabel();
disposables.add(this.renderAction(actionsElement, {
label: quickFixKeybindingLabel ? nls.localize('titleAndKb', "{0} ({1})", quickFixLabel, quickFixKeybindingLabel) : quickFixLabel,
label: nls.localize('quick fixes', "Quick Fix..."),
commandId: QuickFixAction.Id,
run: (target) => {
showing = true;
@ -645,11 +638,9 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
dom.append(action, $(`span.icon.${actionOptions.iconClass}`));
}
const label = dom.append(action, $('span'));
label.textContent = actionOptions.label;
const keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);
if (keybinding) {
label.title = `${actionOptions.label} (${keybinding.getLabel()})`;
}
const keybindingLabel = keybinding ? keybinding.getLabel() : null;
label.textContent = keybindingLabel ? `${actionOptions.label} (${keybindingLabel})` : actionOptions.label;
return dom.addDisposableListener(actionContainer, dom.EventType.CLICK, e => {
e.stopPropagation();
e.preventDefault();

Просмотреть файл

@ -52,6 +52,11 @@ export abstract class AbstractEditorNavigationQuickAccessProvider implements IQu
// Re-create whenever the active editor changes
disposables.add(this.onDidActiveTextEditorControlChange(() => {
// Clear old
pickerDisposable.value = undefined;
// Add new
pickerDisposable.value = this.doProvide(picker, token);
}));

Просмотреть файл

@ -15,14 +15,13 @@ import { DocumentSymbol, SymbolKinds, SymbolTag, DocumentSymbolProviderRegistry,
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';
import { assign } from 'vs/base/common/objects';
import { prepareQuery, IPreparedQuery } from 'vs/base/common/fuzzyScorer';
import { prepareQuery, IPreparedQuery, pieceToQuery, scoreFuzzy2 } from 'vs/base/common/fuzzyScorer';
import { IMatch } from 'vs/base/common/filters';
export interface IGotoSymbolQuickPickItem extends IQuickPickItem {
kind: SymbolKind,
index: number,
score?: FuzzyScore;
score?: number;
range?: { decoration: IRange, selection: IRange }
}
@ -37,7 +36,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
static PREFIX_BY_CATEGORY = `${AbstractGotoSymbolQuickAccessProvider.PREFIX}${AbstractGotoSymbolQuickAccessProvider.SCOPE_PREFIX}`;
constructor(protected options?: IGotoSymbolQuickAccessProviderOptions) {
super(assign(options, { canAcceptInBackground: true }));
super({ ...options, canAcceptInBackground: true });
}
protected provideWithoutTextEditor(picker: IQuickPick<IGotoSymbolQuickPickItem>): IDisposable {
@ -204,12 +203,12 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
const filterBySymbolKind = query.original.indexOf(AbstractGotoSymbolQuickAccessProvider.SCOPE_PREFIX) === 0;
const filterPos = filterBySymbolKind ? 1 : 0;
// Split between symbol and container query if separated by space
// Split between symbol and container query
let symbolQuery: IPreparedQuery;
let containerQuery: IPreparedQuery | undefined;
if (query.values && query.values.length > 1) {
symbolQuery = prepareQuery(query.values[0].original);
containerQuery = prepareQuery(query.values[1].original);
symbolQuery = pieceToQuery(query.values[0]); // symbol: only match on first part
containerQuery = pieceToQuery(query.values.slice(1)); // container: match on all but first parts
} else {
symbolQuery = query;
}
@ -220,69 +219,79 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
const symbol = symbols[index];
const symbolLabel = trim(symbol.name);
const symbolLabelWithIcon = `$(symbol-${SymbolKinds.toString(symbol.kind) || 'property'}) ${symbolLabel}`;
let containerLabel = symbol.containerName;
if (containerLabel && options?.extraContainerLabel) {
containerLabel = `${options.extraContainerLabel}${containerLabel}`;
} else {
containerLabel = options?.extraContainerLabel;
}
let symbolScore: FuzzyScore | undefined = undefined;
let containerScore: FuzzyScore | undefined = undefined;
let includeSymbol = true;
if (query.original.length > filterPos) {
// Score by symbol
symbolScore = fuzzyScore(symbolQuery.original, symbolQuery.originalLowercase, filterPos, symbolLabel, symbolLabel.toLowerCase(), 0, true);
includeSymbol = !!symbolScore;
// Score by container if specified
if (includeSymbol && containerQuery) {
if (containerLabel) {
containerScore = fuzzyScore(containerQuery.original, containerQuery.originalLowercase, filterPos, containerLabel, containerLabel.toLowerCase(), 0, true);
}
includeSymbol = !!containerScore;
if (options?.extraContainerLabel) {
if (containerLabel) {
containerLabel = `${options.extraContainerLabel}${containerLabel}`;
} else {
containerLabel = options.extraContainerLabel;
}
}
if (includeSymbol) {
const symbolLabelWithIcon = `$(symbol-${SymbolKinds.toString(symbol.kind) || 'property'}) ${symbolLabel}`;
const deprecated = symbol.tags && symbol.tags.indexOf(SymbolTag.Deprecated) >= 0;
let symbolScore: number | undefined = undefined;
let symbolMatches: IMatch[] | undefined = undefined;
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;
}
let containerScore: number | undefined = undefined;
let containerMatches: IMatch[] | undefined = 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")
}
];
})()
});
if (query.original.length > filterPos) {
// Score by symbol
[symbolScore, symbolMatches] = scoreFuzzy2(symbolLabel, symbolQuery, filterPos, symbolLabelWithIcon.length - symbolLabel.length /* Readjust matches to account for codicons in label */);
if (!symbolScore) {
continue;
}
// Score by container if specified
if (containerQuery) {
if (containerLabel && containerQuery.original.length > 0) {
[containerScore, containerMatches] = scoreFuzzy2(containerLabel, containerQuery);
}
if (!containerScore) {
continue;
}
if (symbolScore) {
symbolScore += containerScore; // boost symbolScore by containerScore
}
}
}
const deprecated = symbol.tags && symbol.tags.indexOf(SymbolTag.Deprecated) >= 0;
filteredSymbolPicks.push({
index,
kind: symbol.kind,
score: symbolScore,
label: symbolLabelWithIcon,
ariaLabel: symbolLabel,
description: containerLabel,
highlights: deprecated ? undefined : {
label: symbolMatches,
description: containerMatches
},
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
@ -351,9 +360,9 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
}
if (symbolA.score && symbolB.score) {
if (symbolA.score[0] > symbolB.score[0]) {
if (symbolA.score > symbolB.score) {
return -1;
} else if (symbolA.score[0] < symbolB.score[0]) {
} else if (symbolA.score < symbolB.score) {
return 1;
}
}

Просмотреть файл

@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { first } from 'vs/base/common/async';
import { assign } from 'vs/base/common/objects';
import { onUnexpectedExternalError, canceled, isPromiseCanceledError } from 'vs/base/common/errors';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
@ -98,7 +97,7 @@ export class CompletionItem {
this.resolve = (token) => {
if (!cached) {
cached = Promise.resolve(resolveCompletionItem.call(provider, model, Position.lift(position), completion, token)).then(value => {
assign(completion, value);
Object.assign(completion, value);
this.isResolved = true;
}, err => {
if (isPromiseCanceledError(err)) {

Просмотреть файл

@ -734,6 +734,7 @@ registerEditorCommand(new SuggestCommand({
registerEditorCommand(new SuggestCommand({
id: 'insertBestCompletion',
precondition: ContextKeyExpr.and(
EditorContextKeys.textInputFocus,
ContextKeyExpr.equals('config.editor.tabCompletion', 'on'),
WordContextKey.AtEnd,
SuggestContext.Visible.toNegated(),
@ -753,6 +754,7 @@ registerEditorCommand(new SuggestCommand({
registerEditorCommand(new SuggestCommand({
id: 'insertNextSuggestion',
precondition: ContextKeyExpr.and(
EditorContextKeys.textInputFocus,
ContextKeyExpr.equals('config.editor.tabCompletion', 'on'),
SuggestAlternatives.OtherSuggestions,
SuggestContext.Visible.toNegated(),
@ -769,6 +771,7 @@ registerEditorCommand(new SuggestCommand({
registerEditorCommand(new SuggestCommand({
id: 'insertPrevSuggestion',
precondition: ContextKeyExpr.and(
EditorContextKeys.textInputFocus,
ContextKeyExpr.equals('config.editor.tabCompletion', 'on'),
SuggestAlternatives.OtherSuggestions,
SuggestContext.Visible.toNegated(),

Просмотреть файл

@ -511,6 +511,8 @@ export class SuggestModel implements IDisposable {
if (!suggestOptions.showFolders) { result.add(CompletionItemKind.Folder); }
if (!suggestOptions.showTypeParameters) { result.add(CompletionItemKind.TypeParameter); }
if (!suggestOptions.showSnippets) { result.add(CompletionItemKind.Snippet); }
if (!suggestOptions.showUsers) { result.add(CompletionItemKind.User); }
if (!suggestOptions.showIssues) { result.add(CompletionItemKind.Issue); }
return result;
}

Просмотреть файл

@ -13,6 +13,9 @@ import { ITextModel } from 'vs/editor/common/model';
import { DocumentRangeSemanticTokensProviderRegistry, DocumentRangeSemanticTokensProvider, SemanticTokens } from 'vs/editor/common/modes';
import { IModelService } from 'vs/editor/common/services/modelService';
import { toMultilineTokens2, SemanticTokensProviderStyling } from 'vs/editor/common/services/semanticTokensProviderStyling';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { isSemanticColoringEnabled, SEMANTIC_HIGHLIGHTING_SETTING_ID } from 'vs/editor/common/services/modelServiceImpl';
class ViewportSemanticTokensContribution extends Disposable implements IEditorContribution {
@ -28,7 +31,9 @@ class ViewportSemanticTokensContribution extends Disposable implements IEditorCo
constructor(
editor: ICodeEditor,
@IModelService private readonly _modelService: IModelService
@IModelService private readonly _modelService: IModelService,
@IThemeService private readonly _themeService: IThemeService,
@IConfigurationService private readonly _configurationService: IConfigurationService
) {
super();
this._editor = editor;
@ -49,6 +54,16 @@ class ViewportSemanticTokensContribution extends Disposable implements IEditorCo
this._cancelAll();
this._tokenizeViewport.schedule();
}));
this._register(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(SEMANTIC_HIGHLIGHTING_SETTING_ID)) {
this._cancelAll();
this._tokenizeViewport.schedule();
}
}));
this._register(this._themeService.onDidColorThemeChange(() => {
this._cancelAll();
this._tokenizeViewport.schedule();
}));
}
private static _getSemanticColoringProvider(model: ITextModel): DocumentRangeSemanticTokensProvider | null {
@ -80,12 +95,15 @@ class ViewportSemanticTokensContribution extends Disposable implements IEditorCo
if (model.hasSemanticTokens()) {
return;
}
if (!isSemanticColoringEnabled(model, this._themeService, this._configurationService)) {
return;
}
const provider = ViewportSemanticTokensContribution._getSemanticColoringProvider(model);
if (!provider) {
return;
}
const styling = this._modelService.getSemanticTokensProviderStyling(provider);
const visibleRanges = this._editor.getVisibleRanges();
const visibleRanges = this._editor.getVisibleRangesPlusViewportAboveBelow();
this._outstandingRequests = this._outstandingRequests.concat(visibleRanges.map(range => this._requestRange(model, range, provider, styling)));
}

Просмотреть файл

@ -54,6 +54,7 @@ import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
import { StandaloneQuickInputServiceImpl } from 'vs/editor/standalone/browser/quickInput/standaloneQuickInputServiceImpl';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IStorageKeysSyncRegistryService, StorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
export interface IEditorOverrideServices {
[index: string]: any;
@ -166,6 +167,8 @@ export module StaticServices {
export const storageService = define(IStorageService, () => new InMemoryStorageService());
export const storageSyncService = define(IStorageKeysSyncRegistryService, () => new StorageKeysSyncRegistryService());
export const editorWorkerService = define(IEditorWorkerService, (o) => new EditorWorkerServiceImpl(modelService.get(o), resourceConfigurationService.get(o), logService.get(o)));
}

Просмотреть файл

@ -323,4 +323,68 @@ suite('TokensStore', () => {
assert.equal(lineTokens.getCount(), 3);
});
test('issue #94133: Semantic colors stick around when using (only) range provider', () => {
const store = new TokensStore2();
// setPartial: [1,1 -> 1,20] [(1,9-11)]
store.setPartial(new Range(1, 1, 1, 20), [
new MultilineTokens2(1, new SparseEncodedTokens(new Uint32Array([
0, 9, 11, 1,
])))
]);
// setPartial: [1,1 -> 1,20], []
store.setPartial(new Range(1, 1, 1, 20), []);
const lineTokens = store.addSemanticTokens(1, new LineTokens(new Uint32Array([12, 1]), `enum Enum1 {`));
assert.equal(lineTokens.getCount(), 1);
});
test('bug', () => {
function createTokens(str: string): MultilineTokens2 {
str = str.replace(/^\[\(/, '');
str = str.replace(/\)\]$/, '');
const strTokens = str.split('),(');
let result: number[] = [];
let firstLineNumber = 0;
for (const strToken of strTokens) {
const pieces = strToken.split(',');
const chars = pieces[1].split('-');
const lineNumber = parseInt(pieces[0], 10);
const startChar = parseInt(chars[0], 10);
const endChar = parseInt(chars[1], 10);
if (firstLineNumber === 0) {
// this is the first line
firstLineNumber = lineNumber;
}
result.push(lineNumber - firstLineNumber, startChar, endChar, (lineNumber + startChar) % 13);
}
return new MultilineTokens2(firstLineNumber, new SparseEncodedTokens(new Uint32Array(result)));
}
const store = new TokensStore2();
// setPartial [36446,1 -> 36475,115] [(36448,24-29),(36448,33-46),(36448,47-54),(36450,25-35),(36450,36-50),(36451,28-33),(36451,36-49),(36451,50-57),(36452,35-53),(36452,54-62),(36454,33-38),(36454,41-54),(36454,55-60),(36455,35-53),(36455,54-62),(36457,33-44),(36457,45-49),(36457,50-56),(36457,62-83),(36457,84-88),(36458,35-53),(36458,54-62),(36460,33-37),(36460,38-42),(36460,47-57),(36460,58-67),(36461,35-53),(36461,54-62),(36463,34-38),(36463,39-45),(36463,46-51),(36463,54-63),(36463,64-71),(36463,76-80),(36463,81-87),(36463,88-92),(36463,97-107),(36463,108-119),(36464,35-53),(36464,54-62),(36466,33-71),(36466,72-76),(36467,35-53),(36467,54-62),(36469,24-29),(36469,33-46),(36469,47-54),(36470,24-35),(36470,38-46),(36473,25-35),(36473,36-51),(36474,28-33),(36474,36-49),(36474,50-58),(36475,35-53),(36475,54-62)]
store.setPartial(
new Range(36446, 1, 36475, 115),
[createTokens('[(36448,24-29),(36448,33-46),(36448,47-54),(36450,25-35),(36450,36-50),(36451,28-33),(36451,36-49),(36451,50-57),(36452,35-53),(36452,54-62),(36454,33-38),(36454,41-54),(36454,55-60),(36455,35-53),(36455,54-62),(36457,33-44),(36457,45-49),(36457,50-56),(36457,62-83),(36457,84-88),(36458,35-53),(36458,54-62),(36460,33-37),(36460,38-42),(36460,47-57),(36460,58-67),(36461,35-53),(36461,54-62),(36463,34-38),(36463,39-45),(36463,46-51),(36463,54-63),(36463,64-71),(36463,76-80),(36463,81-87),(36463,88-92),(36463,97-107),(36463,108-119),(36464,35-53),(36464,54-62),(36466,33-71),(36466,72-76),(36467,35-53),(36467,54-62),(36469,24-29),(36469,33-46),(36469,47-54),(36470,24-35),(36470,38-46),(36473,25-35),(36473,36-51),(36474,28-33),(36474,36-49),(36474,50-58),(36475,35-53),(36475,54-62)]')]
);
// setPartial [36436,1 -> 36464,142] [(36437,33-37),(36437,38-42),(36437,47-57),(36437,58-67),(36438,35-53),(36438,54-62),(36440,24-29),(36440,33-46),(36440,47-53),(36442,25-35),(36442,36-50),(36443,30-39),(36443,42-46),(36443,47-53),(36443,54-58),(36443,63-73),(36443,74-84),(36443,87-91),(36443,92-98),(36443,101-105),(36443,106-112),(36443,113-119),(36444,28-37),(36444,38-42),(36444,47-57),(36444,58-75),(36444,80-95),(36444,96-105),(36445,35-53),(36445,54-62),(36448,24-29),(36448,33-46),(36448,47-54),(36450,25-35),(36450,36-50),(36451,28-33),(36451,36-49),(36451,50-57),(36452,35-53),(36452,54-62),(36454,33-38),(36454,41-54),(36454,55-60),(36455,35-53),(36455,54-62),(36457,33-44),(36457,45-49),(36457,50-56),(36457,62-83),(36457,84-88),(36458,35-53),(36458,54-62),(36460,33-37),(36460,38-42),(36460,47-57),(36460,58-67),(36461,35-53),(36461,54-62),(36463,34-38),(36463,39-45),(36463,46-51),(36463,54-63),(36463,64-71),(36463,76-80),(36463,81-87),(36463,88-92),(36463,97-107),(36463,108-119),(36464,35-53),(36464,54-62)]
store.setPartial(
new Range(36436, 1, 36464, 142),
[createTokens('[(36437,33-37),(36437,38-42),(36437,47-57),(36437,58-67),(36438,35-53),(36438,54-62),(36440,24-29),(36440,33-46),(36440,47-53),(36442,25-35),(36442,36-50),(36443,30-39),(36443,42-46),(36443,47-53),(36443,54-58),(36443,63-73),(36443,74-84),(36443,87-91),(36443,92-98),(36443,101-105),(36443,106-112),(36443,113-119),(36444,28-37),(36444,38-42),(36444,47-57),(36444,58-75),(36444,80-95),(36444,96-105),(36445,35-53),(36445,54-62),(36448,24-29),(36448,33-46),(36448,47-54),(36450,25-35),(36450,36-50),(36451,28-33),(36451,36-49),(36451,50-57),(36452,35-53),(36452,54-62),(36454,33-38),(36454,41-54),(36454,55-60),(36455,35-53),(36455,54-62),(36457,33-44),(36457,45-49),(36457,50-56),(36457,62-83),(36457,84-88),(36458,35-53),(36458,54-62),(36460,33-37),(36460,38-42),(36460,47-57),(36460,58-67),(36461,35-53),(36461,54-62),(36463,34-38),(36463,39-45),(36463,46-51),(36463,54-63),(36463,64-71),(36463,76-80),(36463,81-87),(36463,88-92),(36463,97-107),(36463,108-119),(36464,35-53),(36464,54-62)]')]
);
// setPartial [36457,1 -> 36485,140] [(36457,33-44),(36457,45-49),(36457,50-56),(36457,62-83),(36457,84-88),(36458,35-53),(36458,54-62),(36460,33-37),(36460,38-42),(36460,47-57),(36460,58-67),(36461,35-53),(36461,54-62),(36463,34-38),(36463,39-45),(36463,46-51),(36463,54-63),(36463,64-71),(36463,76-80),(36463,81-87),(36463,88-92),(36463,97-107),(36463,108-119),(36464,35-53),(36464,54-62),(36466,33-71),(36466,72-76),(36467,35-53),(36467,54-62),(36469,24-29),(36469,33-46),(36469,47-54),(36470,24-35),(36470,38-46),(36473,25-35),(36473,36-51),(36474,28-33),(36474,36-49),(36474,50-58),(36475,35-53),(36475,54-62),(36477,28-32),(36477,33-37),(36477,42-52),(36477,53-69),(36478,32-36),(36478,37-41),(36478,46-56),(36478,57-74),(36479,32-36),(36479,37-41),(36479,46-56),(36479,57-76),(36480,32-36),(36480,37-41),(36480,46-56),(36480,57-68),(36481,32-36),(36481,37-41),(36481,46-56),(36481,57-68),(36482,39-57),(36482,58-66),(36484,34-38),(36484,39-45),(36484,46-50),(36484,55-65),(36484,66-82),(36484,86-97),(36484,98-102),(36484,103-109),(36484,111-124),(36484,125-133),(36485,39-57),(36485,58-66)]
store.setPartial(
new Range(36457, 1, 36485, 140),
[createTokens('[(36457,33-44),(36457,45-49),(36457,50-56),(36457,62-83),(36457,84-88),(36458,35-53),(36458,54-62),(36460,33-37),(36460,38-42),(36460,47-57),(36460,58-67),(36461,35-53),(36461,54-62),(36463,34-38),(36463,39-45),(36463,46-51),(36463,54-63),(36463,64-71),(36463,76-80),(36463,81-87),(36463,88-92),(36463,97-107),(36463,108-119),(36464,35-53),(36464,54-62),(36466,33-71),(36466,72-76),(36467,35-53),(36467,54-62),(36469,24-29),(36469,33-46),(36469,47-54),(36470,24-35),(36470,38-46),(36473,25-35),(36473,36-51),(36474,28-33),(36474,36-49),(36474,50-58),(36475,35-53),(36475,54-62),(36477,28-32),(36477,33-37),(36477,42-52),(36477,53-69),(36478,32-36),(36478,37-41),(36478,46-56),(36478,57-74),(36479,32-36),(36479,37-41),(36479,46-56),(36479,57-76),(36480,32-36),(36480,37-41),(36480,46-56),(36480,57-68),(36481,32-36),(36481,37-41),(36481,46-56),(36481,57-68),(36482,39-57),(36482,58-66),(36484,34-38),(36484,39-45),(36484,46-50),(36484,55-65),(36484,66-82),(36484,86-97),(36484,98-102),(36484,103-109),(36484,111-124),(36484,125-133),(36485,39-57),(36485,58-66)]')]
);
// setPartial [36441,1 -> 36469,56] [(36442,25-35),(36442,36-50),(36443,30-39),(36443,42-46),(36443,47-53),(36443,54-58),(36443,63-73),(36443,74-84),(36443,87-91),(36443,92-98),(36443,101-105),(36443,106-112),(36443,113-119),(36444,28-37),(36444,38-42),(36444,47-57),(36444,58-75),(36444,80-95),(36444,96-105),(36445,35-53),(36445,54-62),(36448,24-29),(36448,33-46),(36448,47-54),(36450,25-35),(36450,36-50),(36451,28-33),(36451,36-49),(36451,50-57),(36452,35-53),(36452,54-62),(36454,33-38),(36454,41-54),(36454,55-60),(36455,35-53),(36455,54-62),(36457,33-44),(36457,45-49),(36457,50-56),(36457,62-83),(36457,84-88),(36458,35-53),(36458,54-62),(36460,33-37),(36460,38-42),(36460,47-57),(36460,58-67),(36461,35-53),(36461,54-62),(36463,34-38),(36463,39-45),(36463,46-51),(36463,54-63),(36463,64-71),(36463,76-80),(36463,81-87),(36463,88-92),(36463,97-107),(36463,108-119),(36464,35-53),(36464,54-62),(36466,33-71),(36466,72-76),(36467,35-53),(36467,54-62),(36469,24-29),(36469,33-46),(36469,47-54),(36470,24-35)]
store.setPartial(
new Range(36441, 1, 36469, 56),
[createTokens('[(36442,25-35),(36442,36-50),(36443,30-39),(36443,42-46),(36443,47-53),(36443,54-58),(36443,63-73),(36443,74-84),(36443,87-91),(36443,92-98),(36443,101-105),(36443,106-112),(36443,113-119),(36444,28-37),(36444,38-42),(36444,47-57),(36444,58-75),(36444,80-95),(36444,96-105),(36445,35-53),(36445,54-62),(36448,24-29),(36448,33-46),(36448,47-54),(36450,25-35),(36450,36-50),(36451,28-33),(36451,36-49),(36451,50-57),(36452,35-53),(36452,54-62),(36454,33-38),(36454,41-54),(36454,55-60),(36455,35-53),(36455,54-62),(36457,33-44),(36457,45-49),(36457,50-56),(36457,62-83),(36457,84-88),(36458,35-53),(36458,54-62),(36460,33-37),(36460,38-42),(36460,47-57),(36460,58-67),(36461,35-53),(36461,54-62),(36463,34-38),(36463,39-45),(36463,46-51),(36463,54-63),(36463,64-71),(36463,76-80),(36463,81-87),(36463,88-92),(36463,97-107),(36463,108-119),(36464,35-53),(36464,54-62),(36466,33-71),(36466,72-76),(36467,35-53),(36467,54-62),(36469,24-29),(36469,33-46),(36469,47-54),(36470,24-35)]')]
);
const lineTokens = store.addSemanticTokens(36451, new LineTokens(new Uint32Array([60, 1]), ` if (flags & ModifierFlags.Ambient) {`));
assert.equal(lineTokens.getCount(), 7);
});
});

Просмотреть файл

@ -25,10 +25,10 @@ import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common
export interface ICommandQuickPick extends IPickerQuickAccessItem {
commandId: string;
commandAlias: string | undefined;
commandAlias?: string;
}
export interface ICommandsQuickAccessOptions extends IPickerQuickAccessProviderOptions {
export interface ICommandsQuickAccessOptions extends IPickerQuickAccessProviderOptions<ICommandQuickPick> {
showAlias: boolean;
}
@ -122,8 +122,8 @@ export abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAcc
const commandPick = filteredCommandPicks[i];
const keybinding = this.keybindingService.lookupKeybinding(commandPick.commandId);
const ariaLabel = keybinding ?
localize('commandPickAriaLabelWithKeybinding', "{0}, {1}, commands picker", commandPick.label, keybinding.getAriaLabel()) :
localize('commandPickAriaLabel', "{0}, commands picker", commandPick.label);
localize('commandPickAriaLabelWithKeybinding', "{0}, {1}", commandPick.label, keybinding.getAriaLabel()) :
commandPick.label;
// Separator: recently used
if (i === 0 && this.commandsHistory.peek(commandPick.commandId)) {

Просмотреть файл

@ -77,7 +77,7 @@ export class HelpQuickAccessProvider implements IQuickAccessProvider {
(helpEntry.needsEditor ? editorProviders : globalProviders).push({
prefix,
label,
ariaLabel: localize('entryAriaLabel', "{0}, quick access help picker", label),
ariaLabel: localize('helpPickAriaLabel', "{0}, {1}", label, helpEntry.description),
description: helpEntry.description
});
}

Просмотреть файл

@ -59,8 +59,17 @@ export interface IPickerQuickAccessItem extends IQuickPickItem {
trigger?(buttonIndex: number, keyMods: IKeyMods): TriggerAction | Promise<TriggerAction>;
}
export interface IPickerQuickAccessProviderOptions {
export interface IPickerQuickAccessProviderOptions<T extends IPickerQuickAccessItem> {
/**
* Enables support for opening picks in the background via gesture.
*/
canAcceptInBackground?: boolean;
/**
* Enables to show a pick entry when no results are returned from a search.
*/
noResultsPick?: T;
}
export type Pick<T> = T | IQuickPickSeparator;
@ -85,7 +94,7 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
private static FAST_PICKS_RACE_DELAY = 200; // timeout before we accept fast results before slow results are present
constructor(private prefix: string, protected options?: IPickerQuickAccessProviderOptions) {
constructor(private prefix: string, protected options?: IPickerQuickAccessProviderOptions<T>) {
super();
}
@ -113,9 +122,10 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
// Collect picks and support both long running and short or combined
const picksToken = picksCts.token;
const providedPicks = this.getPicks(picker.value.substr(this.prefix.length).trim(), picksDisposables, picksToken);
const picksFilter = picker.value.substr(this.prefix.length).trim();
const providedPicks = this.getPicks(picksFilter, picksDisposables, picksToken);
function applyPicks(picks: Picks<T>, skipEmpty?: boolean): boolean {
const applyPicks = (picks: Picks<T>, skipEmpty?: boolean): boolean => {
let items: ReadonlyArray<Pick<T>>;
let activeItem: T | undefined = undefined;
@ -126,8 +136,14 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
items = picks;
}
if (items.length === 0 && skipEmpty) {
return false;
if (items.length === 0) {
if (skipEmpty) {
return false;
}
if (picksFilter.length > 0 && this.options?.noResultsPick) {
items = [this.options.noResultsPick];
}
}
picker.items = items;
@ -136,7 +152,7 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
}
return true;
}
};
// No Picks
if (providedPicks === null) {

Просмотреть файл

@ -90,9 +90,14 @@ export class QuickAccessController extends Disposable implements IQuickAccessCon
picker.placeholder = descriptor?.placeholder;
picker.quickNavigate = options?.quickNavigateConfiguration;
picker.hideInput = !!picker.quickNavigate && !visibleQuickAccess; // only hide input if there was no picker opened already
picker.itemActivation = options?.itemActivation || (options?.quickNavigateConfiguration ? ItemActivation.SECOND : ItemActivation.FIRST);
if (typeof options?.itemActivation === 'number' || options?.quickNavigateConfiguration) {
picker.itemActivation = options?.itemActivation ?? ItemActivation.SECOND /* quick nav is always second */;
}
picker.contextKey = descriptor?.contextKey;
picker.filterValue = (value: string) => value.substring(descriptor ? descriptor.prefix.length : 0);
if (descriptor?.placeholder) {
picker.ariaLabel = descriptor?.placeholder;
}
// Register listeners
const cancellationToken = this.registerPickerListeners(picker, provider, descriptor, value, disposables);

343
src/vs/vscode.d.ts поставляемый
Просмотреть файл

@ -3164,7 +3164,7 @@ declare module 'vscode' {
*/
public readonly tokenModifiers: string[];
constructor(tokenTypes: string[], tokenModifiers: string[]);
constructor(tokenTypes: string[], tokenModifiers?: string[]);
}
/**
@ -3184,7 +3184,7 @@ declare module 'vscode' {
* @param tokenType The encoded token type.
* @param tokenModifiers The encoded token modifiers.
*/
push(line: number, char: number, length: number, tokenType: number, tokenModifiers: number): void;
push(line: number, char: number, length: number, tokenType: number, tokenModifiers?: number): void;
/**
* Add another token. Use only when providing a legend.
@ -3203,8 +3203,8 @@ declare module 'vscode' {
/**
* Represents semantic tokens, either in a range or in an entire document.
* See [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens) for an explanation of the format.
* See `SemanticTokensBuilder` for a helper to create an instance.
* @see [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens) for an explanation of the format.
* @see [SemanticTokensBuilder](#SemanticTokensBuilder) for a helper to create an instance.
*/
export class SemanticTokens {
/**
@ -3215,7 +3215,7 @@ declare module 'vscode' {
readonly resultId?: string;
/**
* The actual tokens data.
* See [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens) for an explanation of the format.
* @see [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens) for an explanation of the format.
*/
readonly data: Uint32Array;
@ -3224,7 +3224,7 @@ declare module 'vscode' {
/**
* Represents edits to semantic tokens.
* See [provideDocumentSemanticTokensEdits](#DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits) for an explanation of the format.
* @see [provideDocumentSemanticTokensEdits](#DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits) for an explanation of the format.
*/
export class SemanticTokensEdits {
/**
@ -3244,7 +3244,7 @@ declare module 'vscode' {
/**
* Represents an edit to semantic tokens.
* See [provideDocumentSemanticTokensEdits](#DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits) for an explanation of the format.
* @see [provideDocumentSemanticTokensEdits](#DocumentSemanticTokensProvider.provideDocumentSemanticTokensEdits) for an explanation of the format.
*/
export class SemanticTokensEdit {
/**
@ -3274,11 +3274,8 @@ declare module 'vscode' {
onDidChangeSemanticTokens?: Event<void>;
/**
* A file can contain many tokens, perhaps even hundreds of thousands of tokens. Therefore, to improve
* the memory consumption around describing semantic tokens, we have decided to avoid allocating an object
* for each token and we represent tokens from a file as an array of integers. Furthermore, the position
* of each token is expressed relative to the token before it because most tokens remain stable relative to
* each other when edits are made in a file.
* Tokens in a file are represented as an array of integers. The position of each token is expressed relative to
* the token before it, because most tokens remain stable relative to each other when edits are made in a file.
*
* ---
* In short, each token takes 5 integers to represent, so a specific token `i` in the file consists of the following array indices:
@ -3331,6 +3328,7 @@ declare module 'vscode' {
* [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ]
* ```
*
* @see [SemanticTokensBuilder](#SemanticTokensBuilder) for a helper to encode tokens as integers.
* *NOTE*: When doing edits, it is possible that multiple edits occur until VS Code decides to invoke the semantic tokens provider.
* *NOTE*: If the provider cannot temporarily compute semantic tokens, it can indicate this by throwing an error with the message 'Busy'.
*/
@ -3338,21 +3336,18 @@ declare module 'vscode' {
/**
* Instead of always returning all the tokens in a file, it is possible for a `DocumentSemanticTokensProvider` to implement
* this method (`updateSemanticTokens`) and then return incremental updates to the previously provided semantic tokens.
* this method (`provideDocumentSemanticTokensEdits`) and then return incremental updates to the previously provided semantic tokens.
*
* ---
* ### How tokens change when the document changes
*
* Let's look at how tokens might change.
* Suppose that `provideDocumentSemanticTokens` has previously returned the following semantic tokens:
* ```
* // 1st token, 2nd token, 3rd token
* [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ]
* ```
*
* Continuing with the above example, suppose a new line was inserted at the top of the file.
* That would make all the tokens move down by one line (notice how the line has changed for each one):
* ```
* { line: 3, startChar: 5, length: 3, tokenType: "property", tokenModifiers: ["private", "static"] },
* { line: 3, startChar: 10, length: 4, tokenType: "type", tokenModifiers: [] },
* { line: 6, startChar: 2, length: 7, tokenType: "class", tokenModifiers: [] }
* ```
* The integer encoding of the tokens does not change substantially because of the delta-encoding of positions:
* Also suppose that after some edits, the new semantic tokens in a file are:
* ```
* // 1st token, 2nd token, 3rd token
* [ 3,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ]
@ -3365,26 +3360,6 @@ declare module 'vscode' {
* edit: { start: 0, deleteCount: 1, data: [3] } // replace integer at offset 0 with 3
* ```
*
* Furthermore, let's assume that a new token has appeared on line 4:
* ```
* { line: 3, startChar: 5, length: 3, tokenType: "property", tokenModifiers: ["private", "static"] },
* { line: 3, startChar: 10, length: 4, tokenType: "type", tokenModifiers: [] },
* { line: 4, startChar: 3, length: 5, tokenType: "property", tokenModifiers: ["static"] },
* { line: 6, startChar: 2, length: 7, tokenType: "class", tokenModifiers: [] }
* ```
* The integer encoding of the tokens is:
* ```
* // 1st token, 2nd token, 3rd token, 4th token
* [ 3,5,3,0,3, 0,5,4,1,0, 1,3,5,0,2, 2,2,7,2,0, ]
* ```
* Again, it is possible to express these new tokens in terms of an edit applied to the previous tokens:
* ```
* [ 3,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] // old tokens
* [ 3,5,3,0,3, 0,5,4,1,0, 1,3,5,0,2, 2,2,7,2,0, ] // new tokens
*
* edit: { start: 10, deleteCount: 1, data: [1,3,5,0,2,2] } // replace integer at offset 10 with [1,3,5,0,2,2]
* ```
*
* *NOTE*: If the provider cannot compute `SemanticTokensEdits`, it can "give up" and return all the tokens in the document again.
* *NOTE*: All edits in `SemanticTokensEdits` contain indices in the old integers array, so they all refer to the previous result state.
*/
@ -3397,7 +3372,7 @@ declare module 'vscode' {
*/
export interface DocumentRangeSemanticTokensProvider {
/**
* See [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens).
* @see [provideDocumentSemanticTokens](#DocumentSemanticTokensProvider.provideDocumentSemanticTokens).
*/
provideDocumentRangeSemanticTokens(document: TextDocument, range: Range, token: CancellationToken): ProviderResult<SemanticTokens>;
}
@ -5233,6 +5208,9 @@ declare module 'vscode' {
* [`Command`](#Command) or identifier of a command to run on click.
*
* The command must be [known](#commands.getCommands).
*
* Note that if this is a [`Command`](#Command) object, only the [`command`](#Command.command) and [`arguments`](#Command.arguments)
* are used by VS Code.
*/
command: string | Command | undefined;
@ -6840,9 +6818,6 @@ declare module 'vscode' {
* Text based custom editors use a [`TextDocument`](#TextDocument) as their data model. This considerably simplifies
* implementing a custom editor as it allows VS Code to handle many common operations such as
* undo and backup. The provider is responsible for synchronizing text changes between the webview and the `TextDocument`.
*
* You should use text based custom editors when dealing with text based file formats, such as `xml` or `json`.
* For binary files or more specialized use cases, see [CustomEditorProvider](#CustomEditorProvider).
*/
export interface CustomTextEditorProvider {
@ -6865,259 +6840,6 @@ declare module 'vscode' {
resolveCustomTextEditor(document: TextDocument, webviewPanel: WebviewPanel, token: CancellationToken): Thenable<void> | void;
}
/**
* Defines the editing capability of a custom editor. This allows the custom editor to hook into standard
* editor events such as `undo` or `save`.
*
* @param EditType Type of edits used for the documents this delegate handles.
*/
interface CustomEditorEditingDelegate<EditType = unknown> {
/**
* Save the resource.
*
* @param document Document to save.
* @param cancellation Token that signals the save is no longer required (for example, if another save was triggered).
*
* @return Thenable signaling that the save has completed.
*/
save(document: CustomDocument<EditType>, cancellation: CancellationToken): Thenable<void>;
/**
* Save the existing resource at a new path.
*
* @param document Document to save.
* @param targetResource Location to save to.
*
* @return Thenable signaling that the save has completed.
*/
saveAs(document: CustomDocument<EditType>, targetResource: Uri): Thenable<void>;
/**
* Event triggered by extensions to signal to VS Code that an edit has occurred.
*/
readonly onDidEdit: Event<CustomDocumentEditEvent<EditType>>;
/**
* Apply a set of edits.
*
* Note that is not invoked when `onDidEdit` is called because `onDidEdit` implies also updating the view to reflect the edit.
*
* @param document Document to apply edits to.
* @param edit Array of edits. Sorted from oldest to most recent.
*
* @return Thenable signaling that the change has completed.
*/
applyEdits(document: CustomDocument<EditType>, edits: ReadonlyArray<EditType>): Thenable<void>;
/**
* Undo a set of edits.
*
* This is triggered when a user undoes an edit.
*
* @param document Document to undo edits from.
* @param edit Array of edits. Sorted from most recent to oldest.
*
* @return Thenable signaling that the change has completed.
*/
undoEdits(document: CustomDocument<EditType>, edits: ReadonlyArray<EditType>): Thenable<void>;
/**
* Revert the file to its last saved state.
*
* @param document Document to revert.
* @param edits Added or applied edits.
*
* @return Thenable signaling that the change has completed.
*/
revert(document: CustomDocument<EditType>, edits: CustomDocumentRevert<EditType>): Thenable<void>;
/**
* Back up the resource in its current state.
*
* Backups are used for hot exit and to prevent data loss. Your `backup` method should persist the resource in
* its current state, i.e. with the edits applied. Most commonly this means saving the resource to disk in
* the `ExtensionContext.storagePath`. When VS Code reloads and your custom editor is opened for a resource,
* your extension should first check to see if any backups exist for the resource. If there is a backup, your
* extension should load the file contents from there instead of from the resource in the workspace.
*
* `backup` is triggered whenever an edit it made. Calls to `backup` are debounced so that if multiple edits are
* made in quick succession, `backup` is only triggered after the last one. `backup` is not invoked when
* `auto save` is enabled (since auto save already persists resource ).
*
* @param document Document to backup.
* @param cancellation Token that signals the current backup since a new backup is coming in. It is up to your
* extension to decided how to respond to cancellation. If for example your extension is backing up a large file
* in an operation that takes time to complete, your extension may decide to finish the ongoing backup rather
* than cancelling it to ensure that VS Code has some valid backup.
*/
backup(document: CustomDocument<EditType>, cancellation: CancellationToken): Thenable<void>;
}
/**
* Event triggered by extensions to signal to VS Code that an edit has occurred on a `CustomDocument`.
*
* @param EditType Type of edits used for the document.
*/
interface CustomDocumentEditEvent<EditType = unknown> {
/**
* Document the edit is for.
*/
readonly document: CustomDocument<EditType>;
/**
* Object that describes the edit.
*
* Edit objects are passed back to your extension in `CustomEditorEditingDelegate.undoEdits`,
* `CustomEditorEditingDelegate.applyEdits`, and `CustomEditorEditingDelegate.revert`.
*/
readonly edit: EditType;
/**
* Display name describing the edit.
*/
readonly label?: string;
}
/**
* Delta for edits undone/redone while reverting for a `CustomDocument`.
*
* @param EditType Type of edits used for the document being reverted.
*/
interface CustomDocumentRevert<EditType = unknown> {
/**
* List of edits that were undone to get the document back to its on disk state.
*/
readonly undoneEdits: ReadonlyArray<EditType>;
/**
* List of edits that were reapplied to get the document back to its on disk state.
*/
readonly appliedEdits: ReadonlyArray<EditType>;
}
/**
* Represents a custom document used by a [`CustomEditorProvider`](#CustomEditorProvider).
*
* All custom documents must subclass `CustomDocument`. Custom documents are only used within a given
* `CustomEditorProvider`. The lifecycle of a `CustomDocument` is managed by VS Code. When no more references
* remain to a `CustomDocument`, it is disposed of.
*
* @param EditType Type of edits used in this document.
*/
class CustomDocument<EditType = unknown> {
/**
* @param uri The associated resource for this document.
*/
constructor(uri: Uri);
/**
* The associated uri for this document.
*/
readonly uri: Uri;
/**
* Is this document representing an untitled file which has never been saved yet.
*/
readonly isUntitled: boolean;
/**
* The version number of this document (it will strictly increase after each
* change, including undo/redo).
*/
readonly version: number;
/**
* `true` if there are unpersisted changes.
*/
readonly isDirty: boolean;
/**
* List of edits from document open to the document's current state.
*
* `appliedEdits` returns a copy of the edit stack at the current point in time. Your extension should always
* use `CustomDocument.appliedEdits` to check the edit stack instead of holding onto a reference to `appliedEdits`.
*/
readonly appliedEdits: ReadonlyArray<EditType>;
/**
* List of edits from document open to the document's last saved point.
*
* The save point will be behind `appliedEdits` if the user saves and then continues editing,
* or in front of the last entry in `appliedEdits` if the user saves and then hits undo.
*
* `savedEdits` returns a copy of the edit stack at the current point in time. Your extension should always
* use `CustomDocument.savedEdits` to check the edit stack instead of holding onto a reference to `savedEdits`.
*/
readonly savedEdits: ReadonlyArray<EditType>;
/**
* `true` if the document has been closed. A closed document isn't synchronized anymore
* and won't be reused when the same resource is opened again.
*/
readonly isClosed: boolean;
/**
* Event fired when there are no more references to the `CustomDocument`.
*
* This happens when all custom editors for the document have been closed. Once a `CustomDocument` is disposed,
* it will not be reused when the same resource is opened again.
*/
readonly onDidDispose: Event<void>;
}
/**
* Provider for custom editors that use a custom document model.
*
* Custom editors use [`CustomDocument`](#CustomDocument) as their document model instead of a [`TextDocument`](#TextDocument).
* This gives extensions full control over actions such as edit, save, and backup.
*
* You should use this type of custom editor when dealing with binary files or more complex scenarios. For simple
* text based documents, use [`CustomTextEditorProvider`](#CustomTextEditorProvider) instead.
*
* @param EditType Type of edits used by the editors of this provider.
*/
export interface CustomEditorProvider<EditType = unknown> {
/**
* Create a new document for a given resource.
*
* `openCustomDocument` is called when the first editor for a given resource is opened, and the resolve document
* is passed to `resolveCustomEditor`. The resolved `CustomDocument` is re-used for subsequent editor opens.
* If all editors for a given resource are closed, the `CustomDocument` is disposed of. Opening an editor at
* this point will trigger another call to `openCustomDocument`.
*
* @param uri Uri of the document to open.
* @param token A cancellation token that indicates the result is no longer needed.
*
* @return The custom document.
*/
openCustomDocument(uri: Uri, token: CancellationToken): Thenable<CustomDocument<EditType>> | CustomDocument<EditType>;
/**
* Resolve a custom editor for a given resource.
*
* This is called whenever the user opens a new editor for this `CustomEditorProvider`.
*
* To resolve a custom editor, the provider must fill in its initial html content and hook up all
* the event listeners it is interested it. The provider can also hold onto the `WebviewPanel` to use later,
* for example in a command. See [`WebviewPanel`](#WebviewPanel) for additional details.
*
* @param document Document for the resource being resolved.
* @param webviewPanel Webview to resolve.
* @param token A cancellation token that indicates the result is no longer needed.
*
* @return Optional thenable indicating that the custom editor has been resolved.
*/
resolveCustomEditor(document: CustomDocument<EditType>, webviewPanel: WebviewPanel, token: CancellationToken): Thenable<void> | void;
/**
* Defines the editing capability of the provider.
*
* When not provided, editors for this provider are considered readonly.
*/
readonly editingDelegate?: CustomEditorEditingDelegate<EditType>;
}
/**
* The clipboard provides read and write access to the system's clipboard.
*/
@ -7956,22 +7678,19 @@ declare module 'vscode' {
export function registerWebviewPanelSerializer(viewType: string, serializer: WebviewPanelSerializer): Disposable;
/**
* Register a new provider for a custom editor.
* Register a provider for custom editors for the `viewType` contributed by the `customEditors` extension point.
*
* @param viewType Type of the custom editor provider. This should match the `viewType` from the
* `package.json` contributions.
* When a custom editor is opened, VS Code fires an `onCustomEditor:viewType` activation event. Your extension
* must register a [`CustomTextEditorProvider`](#CustomTextEditorProvider) for `viewType` as part of activation.
*
* @param viewType Unique identifier for the custom editor provider. This should match the `viewType` from the
* `customEditors` contribution point.
* @param provider Provider that resolves custom editors.
* @param options Options for the provider.
*
* @return Disposable that unregisters the provider.
*/
export function registerCustomEditorProvider(
viewType: string,
provider: CustomEditorProvider | CustomTextEditorProvider,
options?: {
readonly webviewOptions?: WebviewPanelOptions;
}
): Disposable;
export function registerCustomEditorProvider(viewType: string, provider: CustomTextEditorProvider, options?: { readonly webviewOptions?: WebviewPanelOptions; }): Disposable;
}
/**
@ -9861,6 +9580,12 @@ declare module 'vscode' {
/**
* Register a semantic tokens provider for a document range.
*
* *Note:* If a document has both a `DocumentSemanticTokensProvider` and a `DocumentRangeSemanticTokensProvider`,
* the range provider will be invoked only initially, for the time in which the full document provider takes
* to resolve the first request. Once the full document provider resolves the first request, the semantic tokens
* provided via the range provider will be discarded and from that point forward, only the document provider
* will be used.
*
* Multiple providers can be registered for a language. In that case providers are sorted
* by their [score](#languages.match) and the best-matching provider is used. Failure
* of the selected provider will cause a failure of the whole operation.

326
src/vs/vscode.proposed.d.ts поставляемый
Просмотреть файл

@ -1182,6 +1182,330 @@ declare module 'vscode' {
//#endregion
//#region Custom editor https://github.com/microsoft/vscode/issues/77131
/**
* Implements the editing functionality of a custom editor.
*
* This delegate is how custom editors hook into standard VS Code operations such as save and undo. The delegate
* is also how custom editors notify VS Code that an edit has taken place.
*
* @param EditType Type of edits used for the documents this delegate handles.
*/
interface CustomEditorEditingDelegate<EditType = unknown> {
/**
* Save the resource for a custom editor.
*
* This method is invoked by VS Code when the user saves a custom editor. This can happen when the user
* triggers save while the custom editor is active, by commands such as `save all`, or by auto save if enabled.
*
* To implement `save`, the delegate must persist the custom editor. This usually means writing the
* file data for the custom document to disk. After `save` completes, any associated editor instances will
* no longer be marked as dirty.
*
* @param document Document to save.
* @param cancellation Token that signals the save is no longer required (for example, if another save was triggered).
*
* @return Thenable signaling that saving has completed.
*/
save(document: CustomDocument<EditType>, cancellation: CancellationToken): Thenable<void>;
/**
* Save the resource for a custom editor to a different location.
*
* This method is invoked by VS Code when the user triggers `save as` on a custom editor.
*
* To implement `saveAs`, the delegate must persist the custom editor to `targetResource`. The
* existing editor will remain open after `saveAs` completes.
*
* @param document Document to save.
* @param targetResource Location to save to.
* @param cancellation Token that signals the save is no longer required.
*
* @return Thenable signaling that saving has completed.
*/
saveAs(document: CustomDocument<EditType>, targetResource: Uri, cancellation: CancellationToken): Thenable<void>;
/**
* Signal that an edit has occurred inside a custom editor.
*
* This event must be fired by your extension whenever an edit happens in a custom editor. An edit can be
* anything from changing some text, to cropping an image, to reordering a list. Your extension is free to
* define what an edit is and what data is stored on each edit.
*
* VS Code uses edits to determine if a custom editor is dirty or not. VS Code also passes the edit objects back
* to your extension when triggers undo, redo, or revert (using the `undoEdits`, `applyEdits`, and `revert`
* methods of `CustomEditorEditingDelegate`)
*/
readonly onDidEdit: Event<CustomDocumentEditEvent<EditType>>;
/**
* Apply a list of edits to a custom editor.
*
* This method is invoked by VS Code when the user triggers `redo` in a custom editor.
*
* To implement `applyEdits`, the delegate must make sure all editor instances (webviews) for `document`
* are updated to render the document's new state (that is, every webview must be updated to show the document
* after applying `edits` to it).
*
* Note that `applyEdits` not invoked when `onDidEdit` is fired by your extension because `onDidEdit` implies
* that your extension has also updated its editor instances (webviews) to reflect the edit that just occurred.
*
* @param document Document to apply edits to.
* @param redoneEdits Array of edits that were redone. Sorted from oldest to most recent. Use [`document.appliedEdits`](#CustomDocument.appliedEdits)
* to get the full set of edits applied to the file (when `applyEdits` is called `appliedEdits` will already include
* the newly applied edit at the end).
*
* @return Thenable signaling that the change has completed.
*/
applyEdits(document: CustomDocument<EditType>, redoneEdits: ReadonlyArray<EditType>): Thenable<void>;
/**
* Undo a list of edits to a custom editor.
*
* This method is invoked by VS Code when the user triggers `undo` in a custom editor.
*
* To implement `undoEdits`, the delegate must make sure all editor instances (webviews) for `document`
* are updated to render the document's new state (that is, every webview must be updated to show the document
* after undoing `edits` from it).
*
* @param document Document to undo edits from.
* @param undoneEdits Array of undone edits. Sorted from most recent to oldest. Use [`document.appliedEdits`](#CustomDocument.appliedEdits)
* to get the full set of edits applied to the file (when `undoEdits` is called, `appliedEdits` will already include
* have the undone edits removed).
*
* @return Thenable signaling that the change has completed.
*/
undoEdits(document: CustomDocument<EditType>, undoneEdits: ReadonlyArray<EditType>): Thenable<void>;
/**
* Revert a custom editor to its last saved state.
*
* This method is invoked by VS Code when the user triggers `File: Revert File` in a custom editor. (Note that
* this is only used using VS Code's `File: Revert File` command and not on a `git revert` of the file).
*
* To implement `revert`, the delegate must make sure all editor instances (webviews) for `document`
* are displaying the document in the same state is saved in. This usually means reloading the file from the
* workspace.
*
* During `revert`, your extension should also clear any backups for the custom editor. Backups are only needed
* when there is a difference between an editor's state in VS Code and its save state on disk.
*
* @param document Document to revert.
* @param revert Object with added or removed edits to get back to the saved state. Use [`document.appliedEdits`](#CustomDocument.appliedEdits)
* to get the full set of edits applied to the file (when `revet` is called, `appliedEdits` will already have
* removed any edits undone by the revert and added any edits applied by the revert).
*
* @return Thenable signaling that the change has completed.
*/
revert(document: CustomDocument<EditType>, revert: CustomDocumentRevert<EditType>): Thenable<void>;
/**
* Back up the resource in its current state.
*
* Backups are used for hot exit and to prevent data loss. Your `backup` method should persist the resource in
* its current state, i.e. with the edits applied. Most commonly this means saving the resource to disk in
* the `ExtensionContext.storagePath`. When VS Code reloads and your custom editor is opened for a resource,
* your extension should first check to see if any backups exist for the resource. If there is a backup, your
* extension should load the file contents from there instead of from the resource in the workspace.
*
* `backup` is triggered whenever an edit it made. Calls to `backup` are debounced so that if multiple edits are
* made in quick succession, `backup` is only triggered after the last one. `backup` is not invoked when
* `auto save` is enabled (since auto save already persists resource ).
*
* @param document Document to backup.
* @param cancellation Token that signals the current backup since a new backup is coming in. It is up to your
* extension to decided how to respond to cancellation. If for example your extension is backing up a large file
* in an operation that takes time to complete, your extension may decide to finish the ongoing backup rather
* than cancelling it to ensure that VS Code has some valid backup.
*/
backup(document: CustomDocument<EditType>, cancellation: CancellationToken): Thenable<void>;
}
/**
* Event triggered by extensions to signal to VS Code that an edit has occurred on a `CustomDocument`.
*
* @param EditType Type of edits used for the document.
*/
interface CustomDocumentEditEvent<EditType = unknown> {
/**
* Document the edit is for.
*/
readonly document: CustomDocument<EditType>;
/**
* Object that describes the edit.
*
* Edit objects are controlled entirely by your extension. Your extension should store whatever information it
* needs to on the edit to understand what type of edit was made, how to render that edit, and how to save that
* edit to disk.
*
* Edit objects are passed back to your extension in `CustomEditorEditingDelegate.undoEdits`,
* `CustomEditorEditingDelegate.applyEdits`, and `CustomEditorEditingDelegate.revert`. They can also be accessed
* using [`CustomDocument.appliedEdits`](#CustomDocument.appliedEdits) and [`CustomDocument.savedEdits`](#CustomDocument.savedEdits).
*/
readonly edit: EditType;
/**
* Display name describing the edit.
*/
readonly label?: string;
}
/**
* Delta for edits undone/redone while reverting for a `CustomDocument`.
*
* @param EditType Type of edits used for the document being reverted.
*/
interface CustomDocumentRevert<EditType = unknown> {
/**
* List of edits that were undone to get the document back to its on disk state.
*/
readonly undoneEdits: ReadonlyArray<EditType>;
/**
* List of edits that were reapplied to get the document back to its on disk state.
*/
readonly appliedEdits: ReadonlyArray<EditType>;
}
/**
* Represents a custom document used by a [`CustomEditorProvider`](#CustomEditorProvider).
*
* Custom documents are only used within a given `CustomEditorProvider`. The lifecycle of a `CustomDocument` is
* managed by VS Code. When no more references remain to a `CustomDocument`, it is disposed of.
*
* @param EditType Type of edits used in this document.
*/
class CustomDocument<EditType = unknown> {
/**
* @param uri The associated resource for this document.
*/
constructor(uri: Uri);
/**
* The associated uri for this document.
*/
readonly uri: Uri;
/**
* Is this document representing an untitled file which has never been saved yet.
*/
readonly isUntitled: boolean;
/**
* The version number of this document (it will strictly increase after each
* change, including undo/redo).
*/
readonly version: number;
/**
* `true` if there are unpersisted changes.
*/
readonly isDirty: boolean;
/**
* List of edits from document open to the document's current state.
*
* `appliedEdits` returns a copy of the edit stack at the current point in time. Your extension should always
* use `CustomDocument.appliedEdits` to check the edit stack instead of holding onto a reference to `appliedEdits`.
*/
readonly appliedEdits: ReadonlyArray<EditType>;
/**
* List of edits from document open to the document's last saved point.
*
* The save point will be behind `appliedEdits` if the user saves and then continues editing,
* or in front of the last entry in `appliedEdits` if the user saves and then hits undo.
*
* `savedEdits` returns a copy of the edit stack at the current point in time. Your extension should always
* use `CustomDocument.savedEdits` to check the edit stack instead of holding onto a reference to `savedEdits`.
*/
readonly savedEdits: ReadonlyArray<EditType>;
/**
* `true` if the document has been closed. A closed document isn't synchronized anymore
* and won't be reused when the same resource is opened again.
*/
readonly isClosed: boolean;
/**
* Event fired when there are no more references to the `CustomDocument`.
*
* This happens when all custom editors for the document have been closed. Once a `CustomDocument` is disposed,
* it will not be reused when the same resource is opened again.
*/
readonly onDidDispose: Event<void>;
}
/**
* Provider for custom editors that use a custom document model.
*
* Custom editors use [`CustomDocument`](#CustomDocument) as their document model instead of a [`TextDocument`](#TextDocument).
* This gives extensions full control over actions such as edit, save, and backup.
*
* You should use this type of custom editor when dealing with binary files or more complex scenarios. For simple
* text based documents, use [`CustomTextEditorProvider`](#CustomTextEditorProvider) instead.
*
* @param EditType Type of edits used by the editors of this provider.
*/
export interface CustomEditorProvider<EditType = unknown> {
/**
* Create a new document for a given resource.
*
* `openCustomDocument` is called when the first editor for a given resource is opened, and the resolve document
* is passed to `resolveCustomEditor`. The resolved `CustomDocument` is re-used for subsequent editor opens.
* If all editors for a given resource are closed, the `CustomDocument` is disposed of. Opening an editor at
* this point will trigger another call to `openCustomDocument`.
*
* @param uri Uri of the document to open.
* @param token A cancellation token that indicates the result is no longer needed.
*
* @return The custom document.
*/
openCustomDocument(uri: Uri, token: CancellationToken): Thenable<CustomDocument<EditType>> | CustomDocument<EditType>;
/**
* Resolve a custom editor for a given resource.
*
* This is called whenever the user opens a new editor for this `CustomEditorProvider`.
*
* To resolve a custom editor, the provider must fill in its initial html content and hook up all
* the event listeners it is interested it. The provider can also hold onto the `WebviewPanel` to use later,
* for example in a command. See [`WebviewPanel`](#WebviewPanel) for additional details.
*
* @param document Document for the resource being resolved.
* @param webviewPanel Webview to resolve.
* @param token A cancellation token that indicates the result is no longer needed.
*
* @return Optional thenable indicating that the custom editor has been resolved.
*/
resolveCustomEditor(document: CustomDocument<EditType>, webviewPanel: WebviewPanel, token: CancellationToken): Thenable<void> | void;
/**
* Defines the editing capability of the provider.
*
* When not provided, editors for this provider are considered readonly.
*/
readonly editingDelegate?: CustomEditorEditingDelegate<EditType>;
}
namespace window {
/**
* Temporary overload for `registerCustomEditorProvider` that takes a `CustomEditorProvider`.
*/
export function registerCustomEditorProvider2(
viewType: string,
provider: CustomEditorProvider,
options?: {
readonly webviewOptions?: WebviewPanelOptions;
}
): Disposable;
}
// #endregion
//#region Custom editor move https://github.com/microsoft/vscode/issues/86146
// TODO: Also for custom editor
@ -1352,7 +1676,7 @@ declare module 'vscode' {
}
export interface NotebookEditorCellEdit {
insert(index: number, content: string, language: string, type: CellKind, outputs: CellOutput[], metadata: NotebookCellMetadata | undefined): void;
insert(index: number, content: string | string[], language: string, type: CellKind, outputs: CellOutput[], metadata: NotebookCellMetadata | undefined): void;
delete(index: number): void;
}

Просмотреть файл

@ -35,6 +35,7 @@ const BUILT_IN_AUTH_DEPENDENTS: AuthDependent[] = [
interface AllowedExtension {
id: string;
name: string;
sessionIds?: string[];
}
function readAllowedExtensions(storageService: IStorageService, providerId: string, accountName: string): AllowedExtension[] {
@ -85,6 +86,16 @@ export class MainThreadAuthenticationProvider extends Disposable {
quickPick.onDidAccept(() => {
const updatedAllowedList = quickPick.selectedItems.map(item => item.extension);
storageService.store(`${this.id}-${accountName}`, JSON.stringify(updatedAllowedList), StorageScope.GLOBAL);
// Remove sessions of untrusted extensions
const deselectedItems = items.filter(item => !quickPick.selectedItems.includes(item));
deselectedItems.forEach(item => {
const extensionData = allowedExtensions.find(extension => item.extension.id === extension.id);
extensionData?.sessionIds?.forEach(sessionId => {
this.logout(sessionId);
});
});
quickPick.dispose();
});
@ -275,9 +286,19 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
this.authenticationService.sessionsUpdate(id, event);
}
async $getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
let allowList = readAllowedExtensions(this.storageService, providerId, accountName);
if (allowList.some(extension => extension.id === extensionId)) {
async $getSessionsPrompt(providerId: string, accountName: string, sessionId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
const extensionData = allowList.find(extension => extension.id === extensionId);
if (extensionData) {
if (!extensionData.sessionIds) {
extensionData.sessionIds = [];
}
if (!extensionData.sessionIds.find(id => id === sessionId)) {
extensionData.sessionIds.push(sessionId);
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
}
return true;
}
@ -292,7 +313,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
const allow = choice === 1;
if (allow) {
allowList = allowList.concat({ id: extensionId, name: extensionName });
allowList.push({ id: extensionId, name: extensionName, sessionIds: [sessionId] });
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
}
@ -313,7 +334,10 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
}
async $setTrustedExtension(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise<void> {
const allowList = readAllowedExtensions(this.storageService, providerId, accountName).concat({ id: extensionId, name: extensionName });
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
if (!allowList.find(allowed => allowed.id === extensionId)) {
allowList.push({ id: extensionId, name: extensionName, sessionIds: [] });
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
}
}
}

Просмотреть файл

@ -267,7 +267,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
resolveWebview: async (webviewInput): Promise<void> => {
const viewType = webviewPanelViewType.toExternal(webviewInput.viewType);
if (!viewType) {
webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(webviewInput.viewType);
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(webviewInput.viewType);
return;
}
@ -288,7 +288,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
await this._proxy.$deserializeWebviewPanel(handle, viewType, webviewInput.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options);
} catch (error) {
onUnexpectedError(error);
webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(viewType);
}
}
}));
@ -339,7 +339,15 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
webviewInput.webview.options = options;
webviewInput.webview.extension = extension;
let modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, cancellation);
let modelRef: IReference<ICustomEditorModel>;
try {
modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, cancellation);
} catch (error) {
onUnexpectedError(error);
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(viewType);
return;
}
if (cancellation.isCancellationRequested) {
modelRef.dispose();
return;
@ -362,7 +370,8 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
await this._proxy.$resolveWebviewEditor(resource, handle, viewType, webviewInput.getTitle(), editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options, cancellation);
} catch (error) {
onUnexpectedError(error);
webviewInput.webview.html = MainThreadWebviews.getDeserializationFailedContents(viewType);
webviewInput.webview.html = MainThreadWebviews.getWebviewResolvedFailedContent(viewType);
modelRef.dispose();
return;
}
}
@ -522,14 +531,14 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
return this._webviewInputs.getInputForHandle(handle);
}
private static getDeserializationFailedContents(viewType: string) {
private static getWebviewResolvedFailedContent(viewType: string) {
return `<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none';">
</head>
<body>${localize('errorMessage', "An error occurred while restoring view:{0}", escape(viewType))}</body>
<body>${localize('errorMessage', "An error occurred while loading view: {0}", escape(viewType))}</body>
</html>`;
}
}
@ -795,6 +804,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
return undefined;
}
// TODO: handle save untitled case
// TODO: handle cancellation
await createCancelablePromise(token => this._proxy.$onSave(this._editorResource, this.viewType, token));
this.change(() => {
this._savePoint = this._currentEditIndex;
@ -804,7 +814,8 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
public async saveCustomEditorAs(resource: URI, targetResource: URI, _options?: ISaveOptions): Promise<boolean> {
if (this._editable) {
await this._proxy.$onSaveAs(this._editorResource, this.viewType, targetResource);
// TODO: handle cancellation
await createCancelablePromise(token => this._proxy.$onSaveAs(this._editorResource, this.viewType, targetResource, token));
this.change(() => {
this._savePoint = this._currentEditIndex;
});

Просмотреть файл

@ -134,7 +134,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors));
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol, extHostStorage));
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment, extHostWorkspace, extHostLogService, extHostApiDeprecation, extHostDocuments));
@ -585,7 +585,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
return extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializer);
},
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomEditorProvider | vscode.CustomTextEditorProvider, options?: { webviewOptions?: vscode.WebviewPanelOptions }) => {
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomTextEditorProvider, options?: { webviewOptions?: vscode.WebviewPanelOptions }) => {
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options?.webviewOptions);
},
registerCustomEditorProvider2: (viewType: string, provider: vscode.CustomEditorProvider, options?: { webviewOptions?: vscode.WebviewPanelOptions }) => {
checkProposedApiEnabled(extension);
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options?.webviewOptions);
},
registerDecorationProvider(provider: vscode.DecorationProvider) {

Просмотреть файл

@ -162,7 +162,7 @@ export interface MainThreadAuthenticationShape extends IDisposable {
$registerAuthenticationProvider(id: string, displayName: string): void;
$unregisterAuthenticationProvider(id: string): void;
$onDidChangeSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent): void;
$getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
$getSessionsPrompt(providerId: string, accountName: string, sessionId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
$loginPrompt(providerName: string, extensionName: string): Promise<boolean>;
$setTrustedExtension(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise<void>;
}
@ -653,7 +653,7 @@ export interface ExtHostWebviewsShape {
$disposeEdits(resourceComponents: UriComponents, viewType: string, editIds: number[]): void;
$onSave(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void>;
$onSaveAs(resource: UriComponents, viewType: string, targetResource: UriComponents): Promise<void>;
$onSaveAs(resource: UriComponents, viewType: string, targetResource: UriComponents, cancellation: CancellationToken): Promise<void>;
$backup(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void>;

Просмотреть файл

@ -9,6 +9,7 @@ import { Emitter, Event } from 'vs/base/common/event';
import { IMainContext, MainContext, MainThreadAuthenticationShape, ExtHostAuthenticationShape } from 'vs/workbench/api/common/extHost.protocol';
import { Disposable } from 'vs/workbench/api/common/extHostTypes';
import { IExtensionDescription, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
export class ExtHostAuthentication implements ExtHostAuthenticationShape {
private _proxy: MainThreadAuthenticationShape;
@ -20,7 +21,8 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
private _onDidChangeSessions = new Emitter<{ [providerId: string]: vscode.AuthenticationSessionsChangeEvent }>();
readonly onDidChangeSessions: Event<{ [providerId: string]: vscode.AuthenticationSessionsChangeEvent }> = this._onDidChangeSessions.event;
constructor(mainContext: IMainContext) {
constructor(mainContext: IMainContext,
@IExtHostStorage private readonly storageService: IExtHostStorage) {
this._proxy = mainContext.getProxy(MainContext.MainThreadAuthentication);
}
@ -33,15 +35,34 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
return ids;
}
private async hasNotBeenReadByOtherExtension(providerId: string, session: vscode.AuthenticationSession, extensionId: string): Promise<boolean> {
const readerId = await this.storageService.getValue(true, `${providerId}-${session.accountName}-${session.id}`);
if (!readerId) {
await this.storageService.setValue(true, `${providerId}-${session.accountName}-${session.id}`, extensionId as any);
return true;
}
return readerId === extensionId;
}
private async isMatchingSession(session: vscode.AuthenticationSession, scopes: string, providerId: string, extensionId: string): Promise<boolean> {
return session.scopes.sort().join(' ') === scopes && (await this.hasNotBeenReadByOtherExtension(providerId, session, extensionId));
}
async getSessions(requestingExtension: IExtensionDescription, providerId: string, scopes: string[]): Promise<readonly vscode.AuthenticationSession[]> {
const provider = this._authenticationProviders.get(providerId);
if (!provider) {
throw new Error(`No authentication provider with id '${providerId}' is currently registered.`);
}
const extensionId = ExtensionIdentifier.toKey(requestingExtension.identifier);
const orderedScopes = scopes.sort().join(' ');
return (await provider.getSessions())
.filter(session => session.scopes.sort().join(' ') === orderedScopes)
const sessions = await provider.getSessions();
const filteredSessions = await Promise.all(sessions.map(session => this.isMatchingSession(session, orderedScopes, providerId, extensionId)));
return sessions
.filter((_, i) => { return filteredSessions[i]; })
.map(session => {
return {
id: session.id,
@ -51,8 +72,9 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
const isAllowed = await this._proxy.$getSessionsPrompt(
provider.id,
session.accountName,
session.id,
provider.displayName,
ExtensionIdentifier.toKey(requestingExtension.identifier),
extensionId,
requestingExtension.displayName || requestingExtension.name);
if (!isAllowed) {
@ -77,9 +99,28 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
throw new Error('User did not consent to login.');
}
const newSession = await provider.login(scopes);
await this._proxy.$setTrustedExtension(provider.id, newSession.accountName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
return newSession;
const session = await provider.login(scopes);
await this._proxy.$setTrustedExtension(provider.id, session.accountName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
return {
id: session.id,
accountName: session.accountName,
scopes: session.scopes,
getAccessToken: async () => {
const isAllowed = await this._proxy.$getSessionsPrompt(
provider.id,
session.accountName,
session.id,
provider.displayName,
ExtensionIdentifier.toKey(requestingExtension.identifier),
requestingExtension.displayName || requestingExtension.name);
if (!isAllowed) {
throw new Error('User did not consent to token access.');
}
return session.getAccessToken();
}
};
}
registerAuthenticationProvider(provider: vscode.AuthenticationProvider): vscode.Disposable {

Просмотреть файл

@ -402,11 +402,12 @@ export class NotebookEditorCellEdit {
}
}
insert(index: number, content: string, language: string, type: CellKind, outputs: vscode.CellOutput[], metadata: vscode.NotebookCellMetadata | undefined): void {
insert(index: number, content: string | string[], language: string, type: CellKind, outputs: vscode.CellOutput[], metadata: vscode.NotebookCellMetadata | undefined): void {
this._throwIfFinalized();
const sourceArr = Array.isArray(content) ? content : content.split(/\r|\n|\r\n/g);
let cell = {
source: [content],
source: sourceArr,
language,
cellKind: type,
outputs: (outputs as any[]), // TODO@rebornix

Просмотреть файл

@ -16,7 +16,7 @@ import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/p
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
import type * as vscode from 'vscode';
import { Cache } from './cache';
import { assertIsDefined } from 'vs/base/common/types';
import { assertIsDefined, isStringArray } from 'vs/base/common/types';
import { Schemas } from 'vs/base/common/network';
function es5ClassCompat(target: Function): any {
@ -2420,25 +2420,14 @@ export class SemanticTokensLegend {
public readonly tokenTypes: string[];
public readonly tokenModifiers: string[];
constructor(tokenTypes: string[], tokenModifiers: string[]) {
constructor(tokenTypes: string[], tokenModifiers: string[] = []) {
this.tokenTypes = tokenTypes;
this.tokenModifiers = tokenModifiers;
}
}
function isStrArrayOrUndefined(arg: any): arg is string[] | undefined {
if (typeof arg === 'undefined') {
return true;
}
if (Array.isArray(arg)) {
for (const element of arg) {
if (typeof element !== 'string') {
return false;
}
}
return true;
}
return false;
return ((typeof arg === 'undefined') || isStringArray(arg));
}
export class SemanticTokensBuilder {
@ -2472,10 +2461,13 @@ export class SemanticTokensBuilder {
}
}
public push(line: number, char: number, length: number, tokenType: number, tokenModifiers: number): void;
public push(line: number, char: number, length: number, tokenType: number, tokenModifiers?: number): void;
public push(range: Range, tokenType: string, tokenModifiers?: string[]): void;
public push(arg0: any, arg1: any, arg2: any, arg3?: any, arg4?: any): void {
if (typeof arg0 === 'number' && typeof arg1 === 'number' && typeof arg2 === 'number' && typeof arg3 === 'number' && typeof arg4 === 'number') {
if (typeof arg0 === 'number' && typeof arg1 === 'number' && typeof arg2 === 'number' && typeof arg3 === 'number' && (typeof arg4 === 'number' || typeof arg4 === 'undefined')) {
if (typeof arg4 === 'undefined') {
arg4 = 0;
}
// 1st overload
return this._pushEncoded(arg0, arg1, arg2, arg3, arg4);
}

Просмотреть файл

@ -630,10 +630,10 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
return delegate.save(document, cancellation);
}
async $onSaveAs(resourceComponents: UriComponents, viewType: string, targetResource: UriComponents): Promise<void> {
async $onSaveAs(resourceComponents: UriComponents, viewType: string, targetResource: UriComponents, cancellation: CancellationToken): Promise<void> {
const delegate = this.getEditingDelegate(viewType);
const document = this.getCustomDocument(viewType, resourceComponents);
return delegate.saveAs(document, URI.revive(targetResource));
return delegate.saveAs(document, URI.revive(targetResource), cancellation);
}
async $backup(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void> {

Просмотреть файл

@ -41,10 +41,10 @@ namespace schema {
case 'menuBar/webNavigation': return MenuId.MenubarWebNavigationMenu;
case 'scm/title': return MenuId.SCMTitle;
case 'scm/sourceControl': return MenuId.SCMSourceControl;
case 'scm/resourceState/context': return MenuId.SCMResourceContext;
case 'scm/resourceState/context': return MenuId.SCMResourceContext;//
case 'scm/resourceFolder/context': return MenuId.SCMResourceFolderContext;
case 'scm/resourceGroup/context': return MenuId.SCMResourceGroupContext;
case 'scm/change/title': return MenuId.SCMChangeContext;
case 'scm/change/title': return MenuId.SCMChangeContext;//
case 'statusBar/windowIndicator': return MenuId.StatusBarWindowIndicatorMenu;
case 'view/title': return MenuId.ViewTitle;
case 'view/item/context': return MenuId.ViewItemContext;
@ -171,6 +171,11 @@ namespace schema {
type: 'array',
items: menuItem
},
'menuBar/webNavigation': {
description: localize('menus.webNavigation', "The top level navigational menu (web only)"),
type: 'array',
items: menuItem
},
'scm/title': {
description: localize('menus.scmTitle', "The Source Control title menu"),
type: 'array',
@ -191,6 +196,16 @@ namespace schema {
type: 'array',
items: menuItem
},
'scm/resourceFolder/context': {
description: localize('menus.resourceFolderContext', "The Source Control resource folder context menu"),
type: 'array',
items: menuItem
},
'scm/change/title': {
description: localize('menus.changeTitle', "The Source Control inline change menu"),
type: 'array',
items: menuItem
},
'view/title': {
description: localize('view.viewTitle', "The contributed view title menu"),
type: 'array',

Просмотреть файл

@ -504,6 +504,37 @@ export class ResetViewLocationsAction extends Action {
registry.registerWorkbenchAction(SyncActionDescriptor.create(ResetViewLocationsAction, ResetViewLocationsAction.ID, ResetViewLocationsAction.LABEL), 'View: Reset View Locations', viewCategory);
// --- Toggle View with Command
export abstract class ToggleViewAction extends Action {
constructor(
id: string,
label: string,
private readonly viewId: string,
protected viewsService: IViewsService,
protected viewDescriptorService: IViewDescriptorService,
protected contextKeyService: IContextKeyService,
private layoutService: IWorkbenchLayoutService,
cssClass?: string
) {
super(id, label, cssClass);
}
async run(): Promise<void> {
const focusedViewId = FocusedViewContext.getValue(this.contextKeyService);
if (focusedViewId === this.viewId) {
if (this.viewDescriptorService.getViewLocation(this.viewId) === ViewContainerLocation.Sidebar) {
this.layoutService.setSideBarHidden(true);
} else {
this.layoutService.setPanelHidden(true);
}
} else {
this.viewsService.openView(this.viewId, true);
}
}
}
// --- Move View with Command
export class MoveFocusedViewAction extends Action {
static readonly ID = 'workbench.action.moveFocusedView';
@ -541,6 +572,7 @@ export class MoveFocusedViewAction extends Action {
const quickPick = this.quickInputService.createQuickPick();
quickPick.placeholder = nls.localize('moveFocusedView.selectDestination', "Select a Destination for the View");
quickPick.title = nls.localize('moveFocusedView.title', "View: Move {0}", viewDescriptor.name);
const items: Array<IQuickPickItem | IQuickPickSeparator> = [];
@ -549,10 +581,16 @@ export class MoveFocusedViewAction extends Action {
label: nls.localize('sidebar', "Side Bar")
});
items.push({
id: '_.sidebar.newcontainer',
label: nls.localize('moveFocusedView.newContainerInSidebar', "New Container in Side Bar")
});
const currentContainer = this.viewDescriptorService.getViewContainer(focusedViewId)!;
const currentLocation = this.viewDescriptorService.getViewLocation(focusedViewId)!;
const isViewSolo = this.viewDescriptorService.getViewDescriptors(currentContainer).allViewDescriptors.length === 1;
if (!(isViewSolo && currentLocation === ViewContainerLocation.Sidebar)) {
items.push({
id: '_.sidebar.newcontainer',
label: nls.localize('moveFocusedView.newContainerInSidebar', "New Container in Side Bar")
});
}
const pinnedViewlets = this.activityBarService.getPinnedViewletIds();
items.push(...pinnedViewlets
@ -574,10 +612,13 @@ export class MoveFocusedViewAction extends Action {
type: 'separator',
label: nls.localize('panel', "Panel")
});
items.push({
id: '_.panel.newcontainer',
label: nls.localize('moveFocusedView.newContainerInPanel', "New Container in Panel"),
});
if (!(isViewSolo && currentLocation === ViewContainerLocation.Panel)) {
items.push({
id: '_.panel.newcontainer',
label: nls.localize('moveFocusedView.newContainerInPanel', "New Container in Panel"),
});
}
const pinnedPanels = this.panelService.getPinnedPanels();
items.push(...pinnedPanels

Просмотреть файл

@ -127,7 +127,7 @@ abstract class BaseOpenRecentAction extends Action {
const pick = await this.quickInputService.pick(picks, {
contextKey: inRecentFilesPickerContextKey,
activeItem: [...workspacePicks, ...filePicks][autoFocusSecondEntry ? 1 : 0],
placeHolder: isMacintosh ? nls.localize('openRecentPlaceHolderMac', "Select to open (hold Cmd-key to force new window or Alt-key for same window)") : nls.localize('openRecentPlaceHolder', "Select to open (hold Ctrl-key to force new window or Alt-key for same window)"),
placeHolder: isMacintosh ? nls.localize('openRecentPlaceholderMac', "Select to open (hold Cmd-key to force new window or Alt-key for same window)") : nls.localize('openRecentPlaceholder', "Select to open (hold Ctrl-key to force new window or Alt-key for same window)"),
matchOnDescription: true,
onKeyMods: mods => keyMods = mods,
quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined,
@ -196,6 +196,7 @@ abstract class BaseOpenRecentAction extends Action {
return {
iconClasses,
label: name,
ariaLabel: isDirty ? nls.localize('recentDirtyAriaLabel', "{0}, dirty workspace", name) : name,
description: parentPath,
buttons: isDirty ? [this.dirtyRecentlyOpened] : [this.removeFromRecentlyOpened],
openable,

Просмотреть файл

@ -509,8 +509,10 @@ export function containsDragType(event: DragEvent, ...dragTypesToFind: string[])
return false;
}
export type Before2D = { verticallyBefore: boolean; horizontallyBefore: boolean; };
export interface ICompositeDragAndDrop {
drop(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent, before?: boolean): void;
drop(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent, before?: Before2D): void;
onDragOver(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent): boolean;
onDragEnter(data: IDragAndDropData, target: string | undefined, originalEvent: DragEvent): boolean;
}

Просмотреть файл

@ -6,11 +6,7 @@
import { Registry } from 'vs/platform/registry/common/platform';
import { IPanel } from 'vs/workbench/common/panel';
import { Composite, CompositeDescriptor, CompositeRegistry } from 'vs/workbench/browser/composite';
import { Action } from 'vs/base/common/actions';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import { IConstructorSignature0, BrandedService } from 'vs/platform/instantiation/common/instantiation';
import { isAncestor } from 'vs/base/browser/dom';
import { assertIsDefined } from 'vs/base/common/types';
import { PaneComposite } from 'vs/workbench/browser/panecomposite';
@ -85,44 +81,6 @@ export class PanelRegistry extends CompositeRegistry<Panel> {
}
}
/**
* A reusable action to toggle a panel with a specific id depending on focus.
*/
export abstract class TogglePanelAction extends Action {
constructor(
id: string,
label: string,
private readonly panelId: string,
protected panelService: IPanelService,
private layoutService: IWorkbenchLayoutService,
cssClass?: string
) {
super(id, label, cssClass);
}
async run(): Promise<void> {
if (this.isPanelFocused()) {
this.layoutService.setPanelHidden(true);
} else {
await this.panelService.openPanel(this.panelId, true);
}
}
private isPanelActive(): boolean {
const activePanel = this.panelService.getActivePanel();
return activePanel?.getId() === this.panelId;
}
private isPanelFocused(): boolean {
const activeElement = document.activeElement;
const panelPart = this.layoutService.getContainer(Parts.PANEL_PART);
return !!(this.isPanelActive() && activeElement && panelPart && isAncestor(activeElement, panelPart));
}
}
export const Extensions = {
Panels: 'workbench.contributions.panels'
};

Просмотреть файл

@ -42,6 +42,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { getUserDataSyncStore } from 'vs/platform/userDataSync/common/userDataSync';
import { IProductService } from 'vs/platform/product/common/productService';
import { Before2D } from 'vs/workbench/browser/dnd';
interface IPlaceholderViewlet {
id: string;
@ -152,7 +153,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
hidePart: () => this.layoutService.setSideBarHidden(true),
dndHandler: new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Sidebar,
(id: string, focus?: boolean) => this.viewletService.openViewlet(id, focus),
(from: string, to: string, before?: boolean) => this.compositeBar.move(from, to, before)
(from: string, to: string, before?: Before2D) => this.compositeBar.move(from, to, before?.verticallyBefore)
),
compositeSize: 50,
colors: (theme: IColorTheme) => this.getActivitybarItemColors(theme),

Просмотреть файл

@ -23,7 +23,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation, IViewDescriptorService } from 'vs/workbench/common/views';
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
import { IComposite } from 'vs/workbench/common/composite';
import { CompositeDragAndDropData, CompositeDragAndDropObserver, IDraggedCompositeData, ICompositeDragAndDrop } from 'vs/workbench/browser/dnd';
import { CompositeDragAndDropData, CompositeDragAndDropObserver, IDraggedCompositeData, ICompositeDragAndDrop, Before2D } from 'vs/workbench/browser/dnd';
export interface ICompositeBarItem {
id: string;
@ -39,9 +39,9 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
private viewDescriptorService: IViewDescriptorService,
private targetContainerLocation: ViewContainerLocation,
private openComposite: (id: string, focus?: boolean) => Promise<IPaneComposite | undefined>,
private moveComposite: (from: string, to: string, before?: boolean) => void,
private moveComposite: (from: string, to: string, before?: Before2D) => void,
) { }
drop(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent, before?: boolean): void {
drop(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent, before?: Before2D): void {
const dragData = data.getData();
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
@ -255,7 +255,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
},
onDrop: (e: IDraggedCompositeData) => {
const pinnedItems = this.getPinnedComposites();
this.options.dndHandler.drop(e.dragAndDropData, pinnedItems[pinnedItems.length - 1].id, e.eventData, false);
this.options.dndHandler.drop(e.dragAndDropData, pinnedItems[pinnedItems.length - 1].id, e.eventData, { horizontallyBefore: false, verticallyBefore: false });
toggleClass(parent, 'dragged-over', false);
}
}));

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше