Archived
Merge from vscode 1ec43773e37997841c5af42b33ddb180e9735bf2
This commit is contained in:
@@ -6,6 +6,7 @@ labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
<!-- ⚠️⚠️ Do Not Delete This! bug_report_template ⚠️⚠️ -->
|
||||
<!-- Please read our Rules of Conduct: https://opensource.microsoft.com/codeofconduct/ -->
|
||||
<!-- Please search existing issues to avoid creating duplicates. -->
|
||||
<!-- Also please test using the latest insiders build to make sure your issue has not already been fixed. -->
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
daysAfterClose: 45,
|
||||
daysSinceLastUpdate: 3,
|
||||
ignoredLabels: ['A11y_ADS_OctTestPass', 'A11y_ADS_Schema_Dacpac_Backup', 'A11y_AzureDataStudio', 'A11yExclusion', 'A11yMAS', 'A11yResolved: Will Not Fix', 'A11yTCS'],
|
||||
perform: true
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
newReleaseLabel: 'new-release',
|
||||
newReleaseColor: '006b75',
|
||||
daysAfterRelease: 5,
|
||||
perform: true
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
name: Test Plan Item Validator
|
||||
on:
|
||||
issues:
|
||||
types: [edited, labeled]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: 'JacksonKearl/vscode-triage-github-actions'
|
||||
ref: v15
|
||||
- name: Run Test Plan Item Validator
|
||||
uses: ./test-plan-item-validator
|
||||
with:
|
||||
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
|
||||
label: testplan-item
|
||||
invalidLabel: invalid-testplan-item
|
||||
comment: Invalid test plan item. See errors below and the [test plan item spec](https://github.com/microsoft/vscode/wiki/Writing-Test-Plan-Items) for more information. This comment will go away when the issues are resolved.
|
||||
@@ -123,7 +123,6 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
|
||||
resources: vscodeResources,
|
||||
loaderConfig: common.loaderConfig(nodeModules),
|
||||
out: 'out-vscode',
|
||||
inlineAmdImages: true,
|
||||
bundleInfo: undefined
|
||||
})
|
||||
));
|
||||
|
||||
@@ -126,10 +126,6 @@
|
||||
"name": "vs/workbench/contrib/quickaccess",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/quickopen",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/contrib/userData",
|
||||
"project": "vscode-workbench"
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.minifyTask = exports.optimizeTask = exports.loaderConfig = void 0;
|
||||
const es = require("event-stream");
|
||||
const fs = require("fs");
|
||||
const gulp = require("gulp");
|
||||
const concat = require("gulp-concat");
|
||||
const minifyCSS = require("gulp-cssnano");
|
||||
@@ -136,14 +135,6 @@ function optimizeTask(opts) {
|
||||
if (err || !result) {
|
||||
return bundlesStream.emit('error', JSON.stringify(err));
|
||||
}
|
||||
if (opts.inlineAmdImages) {
|
||||
try {
|
||||
result = inlineAmdImages(src, result);
|
||||
}
|
||||
catch (err) {
|
||||
return bundlesStream.emit('error', JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream);
|
||||
// Remove css inlined resources
|
||||
const filteredResources = resources.slice();
|
||||
@@ -179,39 +170,6 @@ function optimizeTask(opts) {
|
||||
};
|
||||
}
|
||||
exports.optimizeTask = optimizeTask;
|
||||
function inlineAmdImages(src, result) {
|
||||
for (const outputFile of result.files) {
|
||||
for (const sourceFile of outputFile.sources) {
|
||||
if (sourceFile.path && /\.js$/.test(sourceFile.path)) {
|
||||
sourceFile.contents = sourceFile.contents.replace(/\([^.]+\.registerAndGetAmdImageURL\(([^)]+)\)\)/g, (_, m0) => {
|
||||
let imagePath = m0;
|
||||
// remove `` or ''
|
||||
if ((imagePath.charAt(0) === '`' && imagePath.charAt(imagePath.length - 1) === '`')
|
||||
|| (imagePath.charAt(0) === '\'' && imagePath.charAt(imagePath.length - 1) === '\'')) {
|
||||
imagePath = imagePath.substr(1, imagePath.length - 2);
|
||||
}
|
||||
if (!/\.(png|svg)$/.test(imagePath)) {
|
||||
console.log(`original: ${_}`);
|
||||
return _;
|
||||
}
|
||||
const repoLocation = path.join(src, imagePath);
|
||||
const absoluteLocation = path.join(REPO_ROOT_PATH, repoLocation);
|
||||
if (!fs.existsSync(absoluteLocation)) {
|
||||
const message = `Invalid amd image url in file ${sourceFile.path}: ${imagePath}`;
|
||||
console.log(message);
|
||||
throw new Error(message);
|
||||
}
|
||||
const fileContents = fs.readFileSync(absoluteLocation);
|
||||
const mime = /\.svg$/.test(imagePath) ? 'image/svg+xml' : 'image/png';
|
||||
// Mark the file as inlined so we don't ship it by itself
|
||||
result.cssInlinedResources.push(repoLocation);
|
||||
return `("data:${mime};base64,${fileContents.toString('base64')}")`;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Wrap around uglify and allow the preserveComments function
|
||||
* to have a file "context" to include our copyright only once per file.
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
'use strict';
|
||||
|
||||
import * as es from 'event-stream';
|
||||
import * as fs from 'fs';
|
||||
import * as gulp from 'gulp';
|
||||
import * as concat from 'gulp-concat';
|
||||
import * as minifyCSS from 'gulp-cssnano';
|
||||
@@ -162,10 +161,6 @@ export interface IOptimizeTaskOpts {
|
||||
* (emit bundleInfo.json file)
|
||||
*/
|
||||
bundleInfo: boolean;
|
||||
/**
|
||||
* replace calls to `registerAndGetAmdImageURL` with data uris
|
||||
*/
|
||||
inlineAmdImages: boolean;
|
||||
/**
|
||||
* (out folder name)
|
||||
*/
|
||||
@@ -199,14 +194,6 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
|
||||
bundle.bundle(entryPoints, loaderConfig, function (err, result) {
|
||||
if (err || !result) { return bundlesStream.emit('error', JSON.stringify(err)); }
|
||||
|
||||
if (opts.inlineAmdImages) {
|
||||
try {
|
||||
result = inlineAmdImages(src, result);
|
||||
} catch (err) {
|
||||
return bundlesStream.emit('error', JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
|
||||
toBundleStream(src, bundledFileHeader, result.files).pipe(bundlesStream);
|
||||
|
||||
// Remove css inlined resources
|
||||
@@ -251,42 +238,6 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr
|
||||
};
|
||||
}
|
||||
|
||||
function inlineAmdImages(src: string, result: bundle.IBundleResult): bundle.IBundleResult {
|
||||
for (const outputFile of result.files) {
|
||||
for (const sourceFile of outputFile.sources) {
|
||||
if (sourceFile.path && /\.js$/.test(sourceFile.path)) {
|
||||
sourceFile.contents = sourceFile.contents.replace(/\([^.]+\.registerAndGetAmdImageURL\(([^)]+)\)\)/g, (_, m0) => {
|
||||
let imagePath = m0;
|
||||
// remove `` or ''
|
||||
if ((imagePath.charAt(0) === '`' && imagePath.charAt(imagePath.length - 1) === '`')
|
||||
|| (imagePath.charAt(0) === '\'' && imagePath.charAt(imagePath.length - 1) === '\'')) {
|
||||
imagePath = imagePath.substr(1, imagePath.length - 2);
|
||||
}
|
||||
if (!/\.(png|svg)$/.test(imagePath)) {
|
||||
console.log(`original: ${_}`);
|
||||
return _;
|
||||
}
|
||||
const repoLocation = path.join(src, imagePath);
|
||||
const absoluteLocation = path.join(REPO_ROOT_PATH, repoLocation);
|
||||
if (!fs.existsSync(absoluteLocation)) {
|
||||
const message = `Invalid amd image url in file ${sourceFile.path}: ${imagePath}`;
|
||||
console.log(message);
|
||||
throw new Error(message);
|
||||
}
|
||||
const fileContents = fs.readFileSync(absoluteLocation);
|
||||
const mime = /\.svg$/.test(imagePath) ? 'image/svg+xml' : 'image/png';
|
||||
|
||||
// Mark the file as inlined so we don't ship it by itself
|
||||
result.cssInlinedResources.push(repoLocation);
|
||||
|
||||
return `("data:${mime};base64,${fileContents.toString('base64')}")`;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
declare class FileWithCopyright extends VinylFile {
|
||||
public __hasOurCopyright: boolean;
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"service-downloader": "0.2.1",
|
||||
"terser": "4.3.8",
|
||||
"typescript": "^3.9.0-dev.20200316",
|
||||
"typescript": "^3.9.0-dev.20200327",
|
||||
"vsce": "1.48.0",
|
||||
"vscode-telemetry-extractor": "^1.5.4",
|
||||
"xml2js": "^0.4.17"
|
||||
|
||||
+4
-4
@@ -3600,10 +3600,10 @@ typescript@^3.0.1:
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
|
||||
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
|
||||
|
||||
typescript@^3.9.0-dev.20200316:
|
||||
version "3.9.0-dev.20200316"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200316.tgz#7cbb2fa2eedf58eea27b3250ab38674790ccf999"
|
||||
integrity sha512-MM67isAuvHM4hwfHR4K9NikB7MFD9RjISB5cXhtKmjkpMFO0QNzFmFq061VmsJqoRVpG9N2KE+cm6BJ9dIjrtQ==
|
||||
typescript@^3.9.0-dev.20200327:
|
||||
version "3.9.0-dev.20200327"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.0-dev.20200327.tgz#52179aae816587f772a0526e91143760f2bee42f"
|
||||
integrity sha512-/TWD/zPvhAcN2Toqx2NBQ+oDVGVj4iqupjWcUAwL45TfcODeHpzszneABR1b/EjHbtUObtLH40vy5Z6rdVvKzg==
|
||||
|
||||
typical@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
||||
@@ -24,6 +24,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
try {
|
||||
const session = await loginService.login(scopeList.join(' '));
|
||||
Logger.info('Login success!');
|
||||
onDidChangeSessions.fire({ added: [session.id], removed: [], changed: [] });
|
||||
return session;
|
||||
} catch (e) {
|
||||
vscode.window.showErrorMessage(`Sign in failed: ${e}`);
|
||||
@@ -32,7 +33,8 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
},
|
||||
logout: async (id: string) => {
|
||||
return loginService.logout(id);
|
||||
await loginService.logout(id);
|
||||
onDidChangeSessions.fire({ added: [], removed: [id], changed: [] });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -142,7 +142,9 @@ export class GitHubAuthenticationProvider {
|
||||
public async logout(id: string) {
|
||||
const sessionIndex = this._sessions.findIndex(session => session.id === id);
|
||||
if (sessionIndex > -1) {
|
||||
this._sessions.splice(sessionIndex, 1);
|
||||
const session = this._sessions.splice(sessionIndex, 1)[0];
|
||||
const token = await session.getAccessToken();
|
||||
await this._githubServer.revokeToken(token);
|
||||
}
|
||||
|
||||
this.storeSessions();
|
||||
|
||||
@@ -156,4 +156,46 @@ export class GitHubServer {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public async revokeToken(token: string): Promise<void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse(`${vscode.env.uriScheme}://vscode.github-authentication/did-authenticate`));
|
||||
const clientDetails = ClientRegistrar.getClientDetails(callbackUri);
|
||||
const detailsString = `${clientDetails.id}:${clientDetails.secret}`;
|
||||
|
||||
const payload = JSON.stringify({ access_token: token });
|
||||
|
||||
Logger.info('Revoking token...');
|
||||
const post = https.request({
|
||||
host: 'api.github.com',
|
||||
path: `/applications/${clientDetails.id}/token`,
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
Authorization: `Basic ${Buffer.from(detailsString).toString('base64')}`,
|
||||
'User-Agent': 'Visual-Studio-Code',
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(payload)
|
||||
}
|
||||
}, result => {
|
||||
const buffer: Buffer[] = [];
|
||||
result.on('data', (chunk: Buffer) => {
|
||||
buffer.push(chunk);
|
||||
});
|
||||
result.on('end', () => {
|
||||
if (result.statusCode === 204) {
|
||||
Logger.info('Revoked token!');
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error(result.statusMessage));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
post.write(payload);
|
||||
post.end();
|
||||
post.on('error', err => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class OriginDocumentMergeConflictTracker implements interfaces.IDocumentMergeCon
|
||||
|
||||
export default class DocumentMergeConflictTracker implements vscode.Disposable, interfaces.IDocumentMergeConflictTrackerService {
|
||||
private cache: Map<string, ScanTask> = new Map();
|
||||
private delayExpireTime: number = 250;
|
||||
private delayExpireTime: number = 0;
|
||||
|
||||
getConflicts(document: vscode.TextDocument, origin: string): PromiseLike<interfaces.IDocumentMergeConflict[]> {
|
||||
// Attempt from cache
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Support.constant",
|
||||
"scope": "support.constant",
|
||||
"scope": [ "support.constant", "support.variable"],
|
||||
"settings": {
|
||||
"fontStyle": "",
|
||||
"foreground": "#eb939aff"
|
||||
|
||||
@@ -182,7 +182,10 @@
|
||||
},
|
||||
{
|
||||
"name": "Library constant",
|
||||
"scope": "support.constant",
|
||||
"scope": [
|
||||
"support.constant",
|
||||
"support.variable"
|
||||
],
|
||||
"settings": {}
|
||||
},
|
||||
{
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@
|
||||
"style-loader": "^1.0.0",
|
||||
"ts-loader": "^4.4.2",
|
||||
"typemoq": "^0.3.2",
|
||||
"typescript": "^3.9.0-dev.20200316",
|
||||
"typescript": "^3.9.0-dev.20200327",
|
||||
"typescript-formatter": "7.1.0",
|
||||
"underscore": "^1.8.2",
|
||||
"vinyl": "^2.0.0",
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import { DeleteAction, OpenQueryAction, RunQueryAction, ClearHistoryAction, ToggleQueryHistoryCaptureAction } from 'sql/workbench/contrib/queryHistory/browser/queryHistoryActions';
|
||||
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||
import { ContributableActionProvider } from 'vs/workbench/browser/actions';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { QueryHistoryNode } from 'sql/workbench/contrib/queryHistory/browser/queryHistoryNode';
|
||||
@@ -13,7 +12,7 @@ import { QueryHistoryNode } from 'sql/workbench/contrib/queryHistory/browser/que
|
||||
/**
|
||||
* Provides query history actions
|
||||
*/
|
||||
export class QueryHistoryActionProvider extends ContributableActionProvider {
|
||||
export class QueryHistoryActionProvider {
|
||||
|
||||
private _actions: {
|
||||
openQueryAction: IAction,
|
||||
@@ -26,7 +25,6 @@ export class QueryHistoryActionProvider extends ContributableActionProvider {
|
||||
constructor(
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
this._actions = {
|
||||
openQueryAction: instantiationService.createInstance(OpenQueryAction, OpenQueryAction.ID, OpenQueryAction.LABEL),
|
||||
runQueryAction: instantiationService.createInstance(RunQueryAction, RunQueryAction.ID, RunQueryAction.LABEL),
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||
import { ContributableActionProvider } from 'vs/workbench/browser/actions';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { TaskNode, TaskStatus, TaskExecutionMode } from 'sql/workbench/services/tasks/common/tasksNode';
|
||||
@@ -13,12 +12,11 @@ import { CancelAction, ScriptAction } from 'sql/workbench/contrib/tasks/common/t
|
||||
/**
|
||||
* Provides actions for the history tasks
|
||||
*/
|
||||
export class TaskHistoryActionProvider extends ContributableActionProvider {
|
||||
export class TaskHistoryActionProvider {
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private _instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public hasActions(tree: ITree, element: any): boolean {
|
||||
|
||||
@@ -8,7 +8,6 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
|
||||
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { ClearSingleRecentConnectionAction } from 'sql/workbench/services/connection/browser/connectionActions';
|
||||
import { ContributableActionProvider } from 'vs/workbench/browser/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile';
|
||||
@@ -17,14 +16,13 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import mouse = require('vs/base/browser/mouseEvent');
|
||||
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
|
||||
|
||||
export class RecentConnectionActionsProvider extends ContributableActionProvider {
|
||||
export class RecentConnectionActionsProvider {
|
||||
private _onRecentConnectionRemoved = new Emitter<void>();
|
||||
public onRecentConnectionRemoved: Event<void> = this._onRecentConnectionRemoved.event;
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private _instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
private getRecentConnectionActions(tree: ITree, element: any): IAction[] {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||
import { ContributableActionProvider } from 'vs/workbench/browser/actions';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -31,7 +30,7 @@ import { firstIndex, find } from 'vs/base/common/arrays';
|
||||
/**
|
||||
* Provides actions for the server tree elements
|
||||
*/
|
||||
export class ServerTreeActionProvider extends ContributableActionProvider {
|
||||
export class ServerTreeActionProvider {
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@@ -40,7 +39,6 @@ export class ServerTreeActionProvider extends ContributableActionProvider {
|
||||
@IMenuService private menuService: IMenuService,
|
||||
@IContextKeyService private _contextKeyService: IContextKeyService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public hasActions(tree: ITree, element: any): boolean {
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
"vs/editor/*",
|
||||
"vs/base/common/*",
|
||||
"vs/base/browser/*",
|
||||
"vs/base/parts/tree/*",
|
||||
"vs/base/parts/quickopen/*",
|
||||
"vs/platform/*/common/*",
|
||||
"vs/platform/*/browser/*"
|
||||
],
|
||||
|
||||
@@ -134,6 +134,18 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem {
|
||||
}
|
||||
}));
|
||||
|
||||
if (platform.isMacintosh) {
|
||||
// macOS: allow to trigger the button when holding Ctrl+key and pressing the
|
||||
// main mouse button. This is for scenarios where e.g. some interaction forces
|
||||
// the Ctrl+key to be pressed and hold but the user still wants to interact
|
||||
// with the actions (for example quick access in quick navigation mode).
|
||||
this._register(DOM.addDisposableListener(element, DOM.EventType.CONTEXT_MENU, e => {
|
||||
if (e.button === 0 && e.ctrlKey === true) {
|
||||
this.onClick(e);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
this._register(DOM.addDisposableListener(element, DOM.EventType.CLICK, e => {
|
||||
DOM.EventHelper.stop(e, true);
|
||||
// See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard
|
||||
@@ -633,8 +645,7 @@ export class ActionBar extends Disposable implements IActionRunner {
|
||||
|
||||
// Prevent native context menu on actions
|
||||
this._register(DOM.addDisposableListener(actionViewItemElement, DOM.EventType.CONTEXT_MENU, (e: DOM.EventLike) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
DOM.EventHelper.stop(e, true);
|
||||
}));
|
||||
|
||||
let item: IActionViewItem | undefined;
|
||||
@@ -873,3 +884,51 @@ export class SelectActionViewItem extends BaseActionViewItem {
|
||||
this.selectBox.render(container);
|
||||
}
|
||||
}
|
||||
|
||||
export function prepareActions(actions: IAction[]): IAction[] {
|
||||
if (!actions.length) {
|
||||
return actions;
|
||||
}
|
||||
|
||||
// Clean up leading separators
|
||||
let firstIndexOfAction = -1;
|
||||
for (let i = 0; i < actions.length; i++) {
|
||||
if (actions[i].id === Separator.ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
firstIndexOfAction = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (firstIndexOfAction === -1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
actions = actions.slice(firstIndexOfAction);
|
||||
|
||||
// Clean up trailing separators
|
||||
for (let h = actions.length - 1; h >= 0; h--) {
|
||||
const isSeparator = actions[h].id === Separator.ID;
|
||||
if (isSeparator) {
|
||||
actions.splice(h, 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up separator duplicates
|
||||
let foundAction = false;
|
||||
for (let k = actions.length - 1; k >= 0; k--) {
|
||||
const isSeparator = actions[k].id === Separator.ID;
|
||||
if (isSeparator && !foundAction) {
|
||||
actions.splice(k, 1);
|
||||
} else if (!isSeparator) {
|
||||
foundAction = true;
|
||||
} else if (isSeparator) {
|
||||
foundAction = false;
|
||||
}
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,8 @@ export class BreadcrumbsWidget {
|
||||
private _dimension: dom.Dimension | undefined;
|
||||
|
||||
constructor(
|
||||
container: HTMLElement
|
||||
container: HTMLElement,
|
||||
horizontalScrollbarSize: number,
|
||||
) {
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.className = 'monaco-breadcrumbs';
|
||||
@@ -90,7 +91,7 @@ export class BreadcrumbsWidget {
|
||||
this._scrollable = new DomScrollableElement(this._domNode, {
|
||||
vertical: ScrollbarVisibility.Hidden,
|
||||
horizontal: ScrollbarVisibility.Auto,
|
||||
horizontalScrollbarSize: 3,
|
||||
horizontalScrollbarSize,
|
||||
useShadows: false,
|
||||
scrollYToX: true
|
||||
});
|
||||
@@ -106,6 +107,12 @@ export class BreadcrumbsWidget {
|
||||
this._disposables.add(focusTracker.onDidFocus(_ => this._onDidChangeFocus.fire(true)));
|
||||
}
|
||||
|
||||
setHorizontalScrollbarSize(size: number) {
|
||||
this._scrollable.updateOptions({
|
||||
horizontalScrollbarSize: size
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._disposables.dispose();
|
||||
dispose(this._pendingLayout);
|
||||
|
||||
@@ -202,7 +202,7 @@ class Label {
|
||||
const l = label[i];
|
||||
const id = options?.domId && `${options?.domId}_${i}`;
|
||||
|
||||
dom.append(this.container, dom.$('a.label-name', { id, 'data-icon-label-count': label.length, 'data-icon-label-index': i }, l));
|
||||
dom.append(this.container, dom.$('a.label-name', { id, 'data-icon-label-count': label.length, 'data-icon-label-index': i, 'role': 'treeitem' }, l));
|
||||
|
||||
if (i < label.length - 1) {
|
||||
dom.append(this.container, dom.$('span.label-separator', undefined, options?.separator || '/'));
|
||||
@@ -270,7 +270,7 @@ class LabelWithHighlights {
|
||||
const m = matches ? matches[i] : undefined;
|
||||
const id = options?.domId && `${options?.domId}_${i}`;
|
||||
|
||||
const name = dom.$('a.label-name', { id, 'data-icon-label-count': label.length, 'data-icon-label-index': i });
|
||||
const name = dom.$('a.label-name', { id, 'data-icon-label-count': label.length, 'data-icon-label-index': i, 'role': 'treeitem' });
|
||||
const highlightedLabel = new HighlightedLabel(dom.append(this.container, name), this.supportCodicons);
|
||||
highlightedLabel.set(l, m, options?.title, options?.labelEscapeNewLines);
|
||||
|
||||
|
||||
@@ -74,16 +74,12 @@
|
||||
}
|
||||
|
||||
/* make sure selection color wins when a label is being selected */
|
||||
.monaco-tree.focused .selected .monaco-icon-label, /* tree */
|
||||
.monaco-tree.focused .selected .monaco-icon-label::after,
|
||||
.monaco-list:focus .selected .monaco-icon-label, /* list */
|
||||
.monaco-list:focus .selected .monaco-icon-label::after
|
||||
{
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.monaco-tree-row.focused.selected .label-description,
|
||||
.monaco-tree-row.selected .label-description,
|
||||
.monaco-list-row.focused.selected .label-description,
|
||||
.monaco-list-row.selected .label-description {
|
||||
opacity: .8;
|
||||
|
||||
@@ -32,6 +32,7 @@ export interface IMenuBarOptions {
|
||||
getKeybinding?: (action: IAction) => ResolvedKeybinding | undefined;
|
||||
alwaysOnMnemonics?: boolean;
|
||||
compactMode?: Direction;
|
||||
getCompactMenuActions?: () => IAction[]
|
||||
}
|
||||
|
||||
export interface MenuBarMenu {
|
||||
@@ -91,7 +92,7 @@ export class MenuBar extends Disposable {
|
||||
private menuStyle: IMenuStyles | undefined;
|
||||
private overflowLayoutScheduled: IDisposable | undefined = undefined;
|
||||
|
||||
constructor(private container: HTMLElement, private options: IMenuBarOptions = {}, private compactMenuActions?: IAction[]) {
|
||||
constructor(private container: HTMLElement, private options: IMenuBarOptions = {}) {
|
||||
super();
|
||||
|
||||
this.container.setAttribute('role', 'menubar');
|
||||
@@ -492,9 +493,10 @@ export class MenuBar extends Disposable {
|
||||
this.overflowMenu.buttonElement.style.visibility = 'visible';
|
||||
}
|
||||
|
||||
if (this.compactMenuActions && this.compactMenuActions.length) {
|
||||
const compactMenuActions = this.options.getCompactMenuActions?.();
|
||||
if (compactMenuActions && compactMenuActions.length) {
|
||||
this.overflowMenu.actions.push(new Separator());
|
||||
this.overflowMenu.actions.push(...this.compactMenuActions);
|
||||
this.overflowMenu.actions.push(...compactMenuActions);
|
||||
}
|
||||
} else {
|
||||
DOM.removeNode(this.overflowMenu.buttonElement);
|
||||
|
||||
@@ -259,6 +259,15 @@ export abstract class AbstractScrollbar extends Widget {
|
||||
this._scrollable.setScrollPositionNow(desiredScrollPosition);
|
||||
}
|
||||
|
||||
public updateScrollbarSize(scrollbarSize: number): void {
|
||||
this._updateScrollbarSize(scrollbarSize);
|
||||
this._scrollbarState.setScrollbarSize(scrollbarSize);
|
||||
this._shouldRender = true;
|
||||
if (!this._lazyRender) {
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------- Overwrite these
|
||||
|
||||
protected abstract _renderDomNode(largeSize: number, smallSize: number): void;
|
||||
@@ -267,6 +276,7 @@ export abstract class AbstractScrollbar extends Widget {
|
||||
protected abstract _mouseDownRelativePosition(offsetX: number, offsetY: number): number;
|
||||
protected abstract _sliderMousePosition(e: ISimplifiedMouseEvent): number;
|
||||
protected abstract _sliderOrthogonalMousePosition(e: ISimplifiedMouseEvent): number;
|
||||
protected abstract _updateScrollbarSize(size: number): void;
|
||||
|
||||
public abstract writeScrollPosition(target: INewScrollPosition, scrollPosition: number): void;
|
||||
}
|
||||
|
||||
@@ -92,6 +92,10 @@ export class HorizontalScrollbar extends AbstractScrollbar {
|
||||
return e.posy;
|
||||
}
|
||||
|
||||
protected _updateScrollbarSize(size: number): void {
|
||||
this.slider.setHeight(size);
|
||||
}
|
||||
|
||||
public writeScrollPosition(target: INewScrollPosition, scrollPosition: number): void {
|
||||
target.scrollLeft = scrollPosition;
|
||||
}
|
||||
|
||||
@@ -287,12 +287,22 @@ export abstract class AbstractScrollableElement extends Widget {
|
||||
* depend on Editor.
|
||||
*/
|
||||
public updateOptions(newOptions: ScrollableElementChangeOptions): void {
|
||||
let massagedOptions = resolveOptions(newOptions);
|
||||
this._options.handleMouseWheel = massagedOptions.handleMouseWheel;
|
||||
this._options.mouseWheelScrollSensitivity = massagedOptions.mouseWheelScrollSensitivity;
|
||||
this._options.fastScrollSensitivity = massagedOptions.fastScrollSensitivity;
|
||||
this._options.scrollPredominantAxis = massagedOptions.scrollPredominantAxis;
|
||||
this._setListeningToMouseWheel(this._options.handleMouseWheel);
|
||||
if (typeof newOptions.handleMouseWheel !== 'undefined') {
|
||||
this._options.handleMouseWheel = newOptions.handleMouseWheel;
|
||||
this._setListeningToMouseWheel(this._options.handleMouseWheel);
|
||||
}
|
||||
if (typeof newOptions.mouseWheelScrollSensitivity !== 'undefined') {
|
||||
this._options.mouseWheelScrollSensitivity = newOptions.mouseWheelScrollSensitivity;
|
||||
}
|
||||
if (typeof newOptions.fastScrollSensitivity !== 'undefined') {
|
||||
this._options.fastScrollSensitivity = newOptions.fastScrollSensitivity;
|
||||
}
|
||||
if (typeof newOptions.scrollPredominantAxis !== 'undefined') {
|
||||
this._options.scrollPredominantAxis = newOptions.scrollPredominantAxis;
|
||||
}
|
||||
if (typeof newOptions.horizontalScrollbarSize !== 'undefined') {
|
||||
this._horizontalScrollbar.updateScrollbarSize(newOptions.horizontalScrollbarSize);
|
||||
}
|
||||
|
||||
if (!this._options.lazyRender) {
|
||||
this._render();
|
||||
|
||||
@@ -119,8 +119,9 @@ export interface ScrollableElementCreationOptions {
|
||||
export interface ScrollableElementChangeOptions {
|
||||
handleMouseWheel?: boolean;
|
||||
mouseWheelScrollSensitivity?: number;
|
||||
fastScrollSensitivity: number;
|
||||
scrollPredominantAxis: boolean;
|
||||
fastScrollSensitivity?: number;
|
||||
scrollPredominantAxis?: boolean;
|
||||
horizontalScrollbarSize?: number;
|
||||
}
|
||||
|
||||
export interface ScrollableElementResolvedOptions {
|
||||
|
||||
@@ -14,7 +14,7 @@ export class ScrollbarState {
|
||||
* For the vertical scrollbar: the width.
|
||||
* For the horizontal scrollbar: the height.
|
||||
*/
|
||||
private readonly _scrollbarSize: number;
|
||||
private _scrollbarSize: number;
|
||||
|
||||
/**
|
||||
* For the vertical scrollbar: the height of the pair horizontal scrollbar.
|
||||
@@ -114,6 +114,10 @@ export class ScrollbarState {
|
||||
return false;
|
||||
}
|
||||
|
||||
public setScrollbarSize(scrollbarSize: number): void {
|
||||
this._scrollbarSize = scrollbarSize;
|
||||
}
|
||||
|
||||
private static _computeValues(oppositeScrollbarSize: number, arrowSize: number, visibleSize: number, scrollSize: number, scrollPosition: number) {
|
||||
const computedAvailableSize = Math.max(0, visibleSize - oppositeScrollbarSize);
|
||||
const computedRepresentableSize = Math.max(0, computedAvailableSize - 2 * arrowSize);
|
||||
|
||||
@@ -93,6 +93,10 @@ export class VerticalScrollbar extends AbstractScrollbar {
|
||||
return e.posx;
|
||||
}
|
||||
|
||||
protected _updateScrollbarSize(size: number): void {
|
||||
this.slider.setWidth(size);
|
||||
}
|
||||
|
||||
public writeScrollPosition(target: INewScrollPosition, scrollPosition: number): void {
|
||||
target.scrollTop = scrollPosition;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,11 @@ export abstract class Pane extends Disposable implements IView {
|
||||
.event(() => this.setExpanded(true), null));
|
||||
|
||||
this._register(domEvent(this.header, 'click')
|
||||
(() => this.setExpanded(!this.isExpanded()), null));
|
||||
(e => {
|
||||
if (!e.defaultPrevented) {
|
||||
this.setExpanded(!this.isExpanded());
|
||||
}
|
||||
}, null));
|
||||
|
||||
this.body = append(this.element, $('.pane-body'));
|
||||
this.renderBody(this.body);
|
||||
|
||||
@@ -269,7 +269,7 @@ function asObjectTreeOptions<TInput, T, TFilterData>(options?: IAsyncDataTreeOpt
|
||||
return options.ariaProvider!.getRole!(el.element as T);
|
||||
} : () => 'treeitem',
|
||||
isChecked: options.ariaProvider!.isChecked ? (e) => {
|
||||
return options.ariaProvider?.isChecked!(e.element as T);
|
||||
return !!(options.ariaProvider?.isChecked!(e.element as T));
|
||||
} : undefined
|
||||
},
|
||||
ariaRole: ListAriaRootRole.TREE,
|
||||
|
||||
@@ -10,16 +10,14 @@ import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
export class CollapseAllAction<TInput, T, TFilterData = void> extends Action {
|
||||
|
||||
constructor(private viewer: AsyncDataTree<TInput, T, TFilterData>, enabled: boolean) {
|
||||
super('vs.tree.collapse', nls.localize('collapse all', "Collapse All"), 'monaco-tree-action collapse-all', enabled);
|
||||
super('vs.tree.collapse', nls.localize('collapse all', "Collapse All"), 'collapse-all', enabled);
|
||||
}
|
||||
|
||||
public run(context?: any): Promise<any> {
|
||||
async run(context?: any): Promise<any> {
|
||||
this.viewer.collapseAll();
|
||||
this.viewer.setSelection([]);
|
||||
this.viewer.setFocus([]);
|
||||
this.viewer.domFocus();
|
||||
this.viewer.focusFirst();
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,3 @@ export function getPathFromAmdModule(requirefn: typeof require, relativePath: st
|
||||
export function getUriFromAmdModule(requirefn: typeof require, relativePath: string): URI {
|
||||
return URI.parse(requirefn.toUrl(relativePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference a resource that might be inlined.
|
||||
* Do not inline icons that will be used by the native mac touchbar.
|
||||
* Do not rename this method unless you adopt the build scripts.
|
||||
*/
|
||||
export function registerAndGetAmdImageURL(absolutePath: string): string {
|
||||
return require.toUrl(absolutePath);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { matchesFuzzy, IMatch } from 'vs/base/common/filters';
|
||||
import { ltrim } from 'vs/base/common/strings';
|
||||
|
||||
const codiconStartMarker = '$(';
|
||||
export const codiconStartMarker = '$(';
|
||||
|
||||
export interface IParsedCodicons {
|
||||
readonly text: string;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { codiconStartMarker } from 'vs/base/common/codicon';
|
||||
|
||||
const escapeCodiconsRegex = /(\\)?\$\([a-z0-9\-]+?(?:~[a-z0-9\-]*?)?\)/gi;
|
||||
export function escapeCodicons(text: string): string {
|
||||
return text.replace(escapeCodiconsRegex, (match, escaped) => escaped ? match : `\\${match}`);
|
||||
@@ -30,5 +32,9 @@ export function renderCodicons(text: string): string {
|
||||
|
||||
const stripCodiconsRegex = /(\s)?(\\)?\$\([a-z0-9\-]+?(?:~[a-z0-9\-]*?)?\)(\s)?/gi;
|
||||
export function stripCodicons(text: string): string {
|
||||
if (text.indexOf(codiconStartMarker) === -1) {
|
||||
return text;
|
||||
}
|
||||
|
||||
return text.replace(stripCodiconsRegex, (match, preWhitespace, escaped, postWhitespace) => escaped ? match : preWhitespace || postWhitespace || '');
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ 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 };
|
||||
@@ -19,7 +20,40 @@ const NO_SCORE: Score = [NO_MATCH, []];
|
||||
// const DEBUG = false;
|
||||
// const DEBUG_MATRIX = false;
|
||||
|
||||
export function score(target: string, query: string, queryLower: string, fuzzy: boolean): Score {
|
||||
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.value, query.valueLowercase, fuzzy);
|
||||
}
|
||||
|
||||
function scoreMultiple(target: string, query: IPreparedQueryPiece[], fuzzy: boolean): Score {
|
||||
let totalScore = NO_MATCH;
|
||||
const totalPositions: number[] = [];
|
||||
|
||||
for (const { value, valueLowercase } of query) {
|
||||
const [scoreValue, positions] = scoreSingle(target, value, valueLowercase, 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 {
|
||||
if (!target || !query) {
|
||||
return NO_SCORE; // return early if target or query are undefined
|
||||
}
|
||||
@@ -303,21 +337,62 @@ const LABEL_PREFIX_SCORE = 1 << 17;
|
||||
const LABEL_CAMELCASE_SCORE = 1 << 16;
|
||||
const LABEL_SCORE_THRESHOLD = 1 << 15;
|
||||
|
||||
export interface IPreparedQuery {
|
||||
export interface IPreparedQueryPiece {
|
||||
original: string;
|
||||
originalLowercase: string;
|
||||
|
||||
value: string;
|
||||
lowercase: string;
|
||||
valueLowercase: 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.
|
||||
* 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 (!original) {
|
||||
if (typeof original !== 'string') {
|
||||
original = '';
|
||||
}
|
||||
|
||||
const originalLowercase = original.toLowerCase();
|
||||
const value = prepareQueryValue(original);
|
||||
const valueLowercase = value.toLowerCase();
|
||||
const containsPathSeparator = value.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 valuePiece = prepareQueryValue(originalPiece);
|
||||
if (valuePiece) {
|
||||
if (!values) {
|
||||
values = [];
|
||||
}
|
||||
|
||||
values.push({
|
||||
original: originalPiece,
|
||||
originalLowercase: originalPiece.toLowerCase(),
|
||||
value: valuePiece,
|
||||
valueLowercase: valuePiece.toLowerCase()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { original, originalLowercase, value, valueLowercase, values, containsPathSeparator };
|
||||
}
|
||||
|
||||
function prepareQueryValue(original: string): string {
|
||||
let value = stripWildcards(original).replace(/\s/g, ''); // get rid of all wildcards and whitespace
|
||||
if (isWindows) {
|
||||
value = value.replace(/\//g, sep); // Help Windows users to search for paths when using slash
|
||||
@@ -325,10 +400,7 @@ export function prepareQuery(original: string): IPreparedQuery {
|
||||
value = value.replace(/\\/g, sep); // Help macOS/Linux users to search for paths when using backslash
|
||||
}
|
||||
|
||||
const lowercase = value.toLowerCase();
|
||||
const containsPathSeparator = value.indexOf(sep) >= 0;
|
||||
|
||||
return { original, value, lowercase, containsPathSeparator };
|
||||
return value;
|
||||
}
|
||||
|
||||
export function scoreItem<T>(item: T, query: IPreparedQuery, fuzzy: boolean, accessor: IItemAccessor<T>, cache: ScorerCache): IItemScore {
|
||||
@@ -404,7 +476,7 @@ function doScoreItem(label: string, description: string | undefined, path: strin
|
||||
}
|
||||
|
||||
// 4.) prefer scores on the label if any
|
||||
const [labelScore, labelPositions] = score(label, query.value, query.lowercase, fuzzy);
|
||||
const [labelScore, labelPositions] = score(label, query, fuzzy);
|
||||
if (labelScore) {
|
||||
return { score: labelScore + LABEL_SCORE_THRESHOLD, labelMatch: createMatches(labelPositions) };
|
||||
}
|
||||
@@ -420,7 +492,7 @@ function doScoreItem(label: string, description: string | undefined, path: strin
|
||||
const descriptionPrefixLength = descriptionPrefix.length;
|
||||
const descriptionAndLabel = `${descriptionPrefix}${label}`;
|
||||
|
||||
const [labelDescriptionScore, labelDescriptionPositions] = score(descriptionAndLabel, query.value, query.lowercase, fuzzy);
|
||||
const [labelDescriptionScore, labelDescriptionPositions] = score(descriptionAndLabel, query, fuzzy);
|
||||
if (labelDescriptionScore) {
|
||||
const labelDescriptionMatches = createMatches(labelDescriptionPositions);
|
||||
const labelMatch: IMatch[] = [];
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="10px" height="16px" viewBox="0 0 10 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 40.3 (33839) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>arrow-left</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Octicons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="arrow-left" fill="#c5c5c5">
|
||||
<polygon id="Shape" points="6 3 0 8 6 13 6 10 10 10 10 6 6 6"></polygon>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 594 B |
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="10px" height="16px" viewBox="0 0 10 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 40.3 (33839) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>arrow-left</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Octicons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="arrow-left" fill="#424242">
|
||||
<polygon id="Shape" points="6 3 0 8 6 13 6 10 10 10 10 6 6 6"></polygon>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 594 B |
@@ -794,7 +794,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
||||
|
||||
if (firstPart.shiftKey && keyCode === KeyCode.Shift) {
|
||||
if (keyboardEvent.ctrlKey || keyboardEvent.altKey || keyboardEvent.metaKey) {
|
||||
return false; // this is an optimistic check for the shift key being used to navigate back in quick open
|
||||
return false; // this is an optimistic check for the shift key being used to navigate back in quick input
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1053,7 +1053,7 @@ class InputBox extends QuickInput implements IInputBox {
|
||||
}
|
||||
|
||||
export class QuickInputController extends Disposable {
|
||||
private static readonly MAX_WIDTH = 600; // Max total width of quick open widget
|
||||
private static readonly MAX_WIDTH = 600; // Max total width of quick input widget
|
||||
|
||||
private idPrefix: string;
|
||||
private ui: QuickInputUI | undefined;
|
||||
|
||||
@@ -106,6 +106,11 @@ class ListElementRenderer implements IListRenderer<ListElement, IListElementTemp
|
||||
|
||||
// Checkbox
|
||||
const label = dom.append(data.entry, $('label.quick-input-list-label'));
|
||||
data.toDisposeTemplate.push(dom.addStandardDisposableListener(label, dom.EventType.CLICK, e => {
|
||||
if (!data.checkbox.offsetParent) { // If checkbox not visible:
|
||||
e.preventDefault(); // Prevent toggle of checkbox when it is immediately shown afterwards. #91740
|
||||
}
|
||||
}));
|
||||
data.checkbox = <HTMLInputElement>dom.append(label, $('input.quick-input-list-checkbox'));
|
||||
data.checkbox.type = 'checkbox';
|
||||
data.toDisposeTemplate.push(dom.addStandardDisposableListener(data.checkbox, dom.EventType.CHANGE, e => {
|
||||
@@ -275,7 +280,13 @@ export class QuickInputList {
|
||||
setRowLineHeight: false,
|
||||
multipleSelectionSupport: false,
|
||||
horizontalScrolling: false,
|
||||
accessibilityProvider
|
||||
accessibilityProvider,
|
||||
ariaProvider: {
|
||||
getRole: () => 'option',
|
||||
getSetSize: (_: ListElement, _index: number, listLength: number) => listLength,
|
||||
getPosInSet: (_: ListElement, index: number) => index
|
||||
},
|
||||
ariaRole: 'listbox'
|
||||
} as IListOptions<ListElement>);
|
||||
this.list.getHTMLElement().id = id;
|
||||
this.disposables.push(this.list);
|
||||
@@ -317,6 +328,9 @@ export class QuickInputList {
|
||||
this._onLeave.fire();
|
||||
}
|
||||
}));
|
||||
this.disposables.push(this.list.onMouseMiddleClick(e => {
|
||||
this._onLeave.fire();
|
||||
}));
|
||||
this.disposables.push(this.list.onContextMenu(e => {
|
||||
if (typeof e.index === 'number') {
|
||||
e.browserEvent.preventDefault();
|
||||
|
||||
@@ -1,578 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ITree, IActionProvider } from 'vs/base/parts/tree/browser/tree';
|
||||
import { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { IQuickNavigateConfiguration, IModel, IDataSource, IFilter, IAccessiblityProvider, IRenderer, IRunner, Mode, IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
|
||||
import { IAction, IActionRunner } from 'vs/base/common/actions';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { IQuickOpenStyles } from 'vs/base/parts/quickopen/browser/quickOpenWidget';
|
||||
import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';
|
||||
import { OS } from 'vs/base/common/platform';
|
||||
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
||||
import { IItemAccessor } from 'vs/base/common/fuzzyScorer';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { IMatch } from 'vs/base/common/filters';
|
||||
|
||||
export interface IContext {
|
||||
event: any;
|
||||
quickNavigateConfiguration: IQuickNavigateConfiguration;
|
||||
}
|
||||
|
||||
export interface IHighlight extends IMatch {
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
let IDS = 0;
|
||||
|
||||
export class QuickOpenItemAccessorClass implements IItemAccessor<QuickOpenEntry> {
|
||||
|
||||
getItemLabel(entry: QuickOpenEntry): string | undefined {
|
||||
return entry.getLabel();
|
||||
}
|
||||
|
||||
getItemDescription(entry: QuickOpenEntry): string | undefined {
|
||||
return entry.getDescription();
|
||||
}
|
||||
|
||||
getItemPath(entry: QuickOpenEntry): string | undefined {
|
||||
const resource = entry.getResource();
|
||||
|
||||
return resource ? resource.fsPath : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export const QuickOpenItemAccessor = new QuickOpenItemAccessorClass();
|
||||
|
||||
export class QuickOpenEntry {
|
||||
private id: string;
|
||||
private labelHighlights?: IHighlight[];
|
||||
private descriptionHighlights?: IHighlight[];
|
||||
private detailHighlights?: IHighlight[];
|
||||
private hidden: boolean | undefined;
|
||||
|
||||
constructor(highlights: IHighlight[] = []) {
|
||||
this.id = (IDS++).toString();
|
||||
this.labelHighlights = highlights;
|
||||
this.descriptionHighlights = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* A unique identifier for the entry
|
||||
*/
|
||||
getId(): string {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* The label of the entry to identify it from others in the list
|
||||
*/
|
||||
getLabel(): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The options for the label to use for this entry
|
||||
*/
|
||||
getLabelOptions(): IIconLabelValueOptions | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The label of the entry to use when a screen reader wants to read about the entry
|
||||
*/
|
||||
getAriaLabel(): string {
|
||||
return coalesce([this.getLabel(), this.getDescription(), this.getDetail()])
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Detail information about the entry that is optional and can be shown below the label
|
||||
*/
|
||||
getDetail(): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The icon of the entry to identify it from others in the list
|
||||
*/
|
||||
getIcon(): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A secondary description that is optional and can be shown right to the label
|
||||
*/
|
||||
getDescription(): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A tooltip to show when hovering over the entry.
|
||||
*/
|
||||
getTooltip(): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A tooltip to show when hovering over the description portion of the entry.
|
||||
*/
|
||||
getDescriptionTooltip(): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional keybinding to show for an entry.
|
||||
*/
|
||||
getKeybinding(): ResolvedKeybinding | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A resource for this entry. Resource URIs can be used to compare different kinds of entries and group
|
||||
* them together.
|
||||
*/
|
||||
getResource(): URI | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to reuse the same model while filtering. Hidden entries will not show up in the viewer.
|
||||
*/
|
||||
isHidden(): boolean {
|
||||
return !!this.hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to reuse the same model while filtering. Hidden entries will not show up in the viewer.
|
||||
*/
|
||||
setHidden(hidden: boolean): void {
|
||||
this.hidden = hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to set highlight ranges that should show up for the entry label and optionally description if set.
|
||||
*/
|
||||
setHighlights(labelHighlights?: IHighlight[], descriptionHighlights?: IHighlight[], detailHighlights?: IHighlight[]): void {
|
||||
this.labelHighlights = labelHighlights;
|
||||
this.descriptionHighlights = descriptionHighlights;
|
||||
this.detailHighlights = detailHighlights;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to return highlight ranges that should show up for the entry label and description.
|
||||
*/
|
||||
getHighlights(): [IHighlight[] | undefined /* Label */, IHighlight[] | undefined /* Description */, IHighlight[] | undefined /* Detail */] {
|
||||
return [this.labelHighlights, this.descriptionHighlights, this.detailHighlights];
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the entry is selected for opening. Returns a boolean value indicating if an action was performed or not.
|
||||
* The mode parameter gives an indication if the element is previewed (using arrow keys) or opened.
|
||||
*
|
||||
* The context parameter provides additional context information how the run was triggered.
|
||||
*/
|
||||
run(mode: Mode, context: IEntryRunContext): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this quick open entry should merge with the editor history in quick open. If set to true
|
||||
* and the resource of this entry is the same as the resource for an editor history, it will not show up
|
||||
* because it is considered to be a duplicate of an editor history.
|
||||
*/
|
||||
mergeWithEditorHistory(): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class QuickOpenEntryGroup extends QuickOpenEntry {
|
||||
private entry?: QuickOpenEntry;
|
||||
private groupLabel?: string;
|
||||
private withBorder?: boolean;
|
||||
|
||||
constructor(entry?: QuickOpenEntry, groupLabel?: string, withBorder?: boolean) {
|
||||
super();
|
||||
|
||||
this.entry = entry;
|
||||
this.groupLabel = groupLabel;
|
||||
this.withBorder = withBorder;
|
||||
}
|
||||
|
||||
/**
|
||||
* The label of the group or null if none.
|
||||
*/
|
||||
getGroupLabel(): string | undefined {
|
||||
return this.groupLabel;
|
||||
}
|
||||
|
||||
setGroupLabel(groupLabel: string | undefined): void {
|
||||
this.groupLabel = groupLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to show a border on top of the group entry or not.
|
||||
*/
|
||||
showBorder(): boolean {
|
||||
return !!this.withBorder;
|
||||
}
|
||||
|
||||
setShowBorder(showBorder: boolean): void {
|
||||
this.withBorder = showBorder;
|
||||
}
|
||||
|
||||
getLabel(): string | undefined {
|
||||
return this.entry ? this.entry.getLabel() : super.getLabel();
|
||||
}
|
||||
|
||||
getLabelOptions(): IIconLabelValueOptions | undefined {
|
||||
return this.entry ? this.entry.getLabelOptions() : super.getLabelOptions();
|
||||
}
|
||||
|
||||
getAriaLabel(): string {
|
||||
return this.entry ? this.entry.getAriaLabel() : super.getAriaLabel();
|
||||
}
|
||||
|
||||
getDetail(): string | undefined {
|
||||
return this.entry ? this.entry.getDetail() : super.getDetail();
|
||||
}
|
||||
|
||||
getResource(): URI | undefined {
|
||||
return this.entry ? this.entry.getResource() : super.getResource();
|
||||
}
|
||||
|
||||
getIcon(): string | undefined {
|
||||
return this.entry ? this.entry.getIcon() : super.getIcon();
|
||||
}
|
||||
|
||||
getDescription(): string | undefined {
|
||||
return this.entry ? this.entry.getDescription() : super.getDescription();
|
||||
}
|
||||
|
||||
getEntry(): QuickOpenEntry | undefined {
|
||||
return this.entry;
|
||||
}
|
||||
|
||||
getHighlights(): [IHighlight[] | undefined, IHighlight[] | undefined, IHighlight[] | undefined] {
|
||||
return this.entry ? this.entry.getHighlights() : super.getHighlights();
|
||||
}
|
||||
|
||||
isHidden(): boolean {
|
||||
return this.entry ? this.entry.isHidden() : super.isHidden();
|
||||
}
|
||||
|
||||
setHighlights(labelHighlights?: IHighlight[], descriptionHighlights?: IHighlight[], detailHighlights?: IHighlight[]): void {
|
||||
this.entry ? this.entry.setHighlights(labelHighlights, descriptionHighlights, detailHighlights) : super.setHighlights(labelHighlights, descriptionHighlights, detailHighlights);
|
||||
}
|
||||
|
||||
setHidden(hidden: boolean): void {
|
||||
this.entry ? this.entry.setHidden(hidden) : super.setHidden(hidden);
|
||||
}
|
||||
|
||||
run(mode: Mode, context: IEntryRunContext): boolean {
|
||||
return this.entry ? this.entry.run(mode, context) : super.run(mode, context);
|
||||
}
|
||||
}
|
||||
|
||||
class NoActionProvider implements IActionProvider {
|
||||
|
||||
hasActions(tree: ITree, element: any): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
getActions(tree: ITree, element: any): IAction[] | null {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IQuickOpenEntryTemplateData {
|
||||
container: HTMLElement;
|
||||
entry: HTMLElement;
|
||||
icon: HTMLSpanElement;
|
||||
label: IconLabel;
|
||||
detail: HighlightedLabel;
|
||||
keybinding: KeybindingLabel;
|
||||
actionBar: ActionBar;
|
||||
}
|
||||
|
||||
export interface IQuickOpenEntryGroupTemplateData extends IQuickOpenEntryTemplateData {
|
||||
group?: HTMLDivElement;
|
||||
}
|
||||
|
||||
const templateEntry = 'quickOpenEntry';
|
||||
const templateEntryGroup = 'quickOpenEntryGroup';
|
||||
|
||||
class Renderer implements IRenderer<QuickOpenEntry> {
|
||||
|
||||
private actionProvider: IActionProvider;
|
||||
private actionRunner?: IActionRunner;
|
||||
|
||||
constructor(actionProvider: IActionProvider = new NoActionProvider(), actionRunner?: IActionRunner) {
|
||||
this.actionProvider = actionProvider;
|
||||
this.actionRunner = actionRunner;
|
||||
}
|
||||
|
||||
getHeight(entry: QuickOpenEntry): number {
|
||||
if (entry.getDetail()) {
|
||||
return 44;
|
||||
}
|
||||
|
||||
return 22;
|
||||
}
|
||||
|
||||
getTemplateId(entry: QuickOpenEntry): string {
|
||||
if (entry instanceof QuickOpenEntryGroup) {
|
||||
return templateEntryGroup;
|
||||
}
|
||||
|
||||
return templateEntry;
|
||||
}
|
||||
|
||||
renderTemplate(templateId: string, container: HTMLElement, styles: IQuickOpenStyles): IQuickOpenEntryGroupTemplateData {
|
||||
const entryContainer = document.createElement('div');
|
||||
DOM.addClass(entryContainer, 'sub-content');
|
||||
container.appendChild(entryContainer);
|
||||
|
||||
// Entry
|
||||
const row1 = DOM.$('.quick-open-row');
|
||||
const row2 = DOM.$('.quick-open-row');
|
||||
const entry = DOM.$('.quick-open-entry', undefined, row1, row2);
|
||||
entryContainer.appendChild(entry);
|
||||
|
||||
// Icon
|
||||
const icon = document.createElement('span');
|
||||
row1.appendChild(icon);
|
||||
|
||||
// Label
|
||||
const label = new IconLabel(row1, { supportHighlights: true, supportDescriptionHighlights: true, supportCodicons: true });
|
||||
|
||||
// Keybinding
|
||||
const keybindingContainer = document.createElement('span');
|
||||
row1.appendChild(keybindingContainer);
|
||||
DOM.addClass(keybindingContainer, 'quick-open-entry-keybinding');
|
||||
const keybinding = new KeybindingLabel(keybindingContainer, OS);
|
||||
|
||||
// Detail
|
||||
const detailContainer = document.createElement('div');
|
||||
row2.appendChild(detailContainer);
|
||||
DOM.addClass(detailContainer, 'quick-open-entry-meta');
|
||||
const detail = new HighlightedLabel(detailContainer, true);
|
||||
|
||||
// Entry Group
|
||||
let group: HTMLDivElement | undefined;
|
||||
if (templateId === templateEntryGroup) {
|
||||
group = document.createElement('div');
|
||||
DOM.addClass(group, 'results-group');
|
||||
container.appendChild(group);
|
||||
}
|
||||
|
||||
// Actions
|
||||
DOM.addClass(container, 'actions');
|
||||
|
||||
const actionBarContainer = document.createElement('div');
|
||||
DOM.addClass(actionBarContainer, 'primary-action-bar');
|
||||
container.appendChild(actionBarContainer);
|
||||
|
||||
const actionBar = new ActionBar(actionBarContainer, {
|
||||
actionRunner: this.actionRunner
|
||||
});
|
||||
|
||||
return {
|
||||
container,
|
||||
entry,
|
||||
icon,
|
||||
label,
|
||||
detail,
|
||||
keybinding,
|
||||
group,
|
||||
actionBar
|
||||
};
|
||||
}
|
||||
|
||||
renderElement(entry: QuickOpenEntry, templateId: string, data: IQuickOpenEntryGroupTemplateData, styles: IQuickOpenStyles): void {
|
||||
|
||||
// Action Bar
|
||||
if (this.actionProvider.hasActions(null, entry)) {
|
||||
DOM.addClass(data.container, 'has-actions');
|
||||
} else {
|
||||
DOM.removeClass(data.container, 'has-actions');
|
||||
}
|
||||
|
||||
data.actionBar.context = entry; // make sure the context is the current element
|
||||
|
||||
const actions = this.actionProvider.getActions(null, entry);
|
||||
if (data.actionBar.isEmpty() && actions && actions.length > 0) {
|
||||
data.actionBar.push(actions, { icon: true, label: false });
|
||||
} else if (!data.actionBar.isEmpty() && (!actions || actions.length === 0)) {
|
||||
data.actionBar.clear();
|
||||
}
|
||||
|
||||
// Entry group class
|
||||
if (entry instanceof QuickOpenEntryGroup && entry.getGroupLabel()) {
|
||||
DOM.addClass(data.container, 'has-group-label');
|
||||
} else {
|
||||
DOM.removeClass(data.container, 'has-group-label');
|
||||
}
|
||||
|
||||
// Entry group
|
||||
if (entry instanceof QuickOpenEntryGroup) {
|
||||
const group = <QuickOpenEntryGroup>entry;
|
||||
const groupData = data;
|
||||
|
||||
// Border
|
||||
if (group.showBorder()) {
|
||||
DOM.addClass(groupData.container, 'results-group-separator');
|
||||
if (styles.pickerGroupBorder) {
|
||||
groupData.container.style.borderTopColor = styles.pickerGroupBorder.toString();
|
||||
}
|
||||
} else {
|
||||
DOM.removeClass(groupData.container, 'results-group-separator');
|
||||
groupData.container.style.borderTopColor = '';
|
||||
}
|
||||
|
||||
// Group Label
|
||||
const groupLabel = group.getGroupLabel() || '';
|
||||
if (groupData.group) {
|
||||
groupData.group.textContent = groupLabel;
|
||||
if (styles.pickerGroupForeground) {
|
||||
groupData.group.style.color = styles.pickerGroupForeground.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normal Entry
|
||||
if (entry instanceof QuickOpenEntry) {
|
||||
const [labelHighlights, descriptionHighlights, detailHighlights] = entry.getHighlights();
|
||||
|
||||
// Icon
|
||||
const iconClass = entry.getIcon() ? ('quick-open-entry-icon ' + entry.getIcon()) : '';
|
||||
data.icon.className = iconClass;
|
||||
|
||||
// Label
|
||||
const options: IIconLabelValueOptions = entry.getLabelOptions() || Object.create(null);
|
||||
options.matches = labelHighlights || [];
|
||||
options.title = entry.getTooltip();
|
||||
options.descriptionTitle = entry.getDescriptionTooltip() || entry.getDescription(); // tooltip over description because it could overflow
|
||||
options.descriptionMatches = descriptionHighlights || [];
|
||||
data.label.setLabel(entry.getLabel() || '', entry.getDescription(), options);
|
||||
|
||||
// Meta
|
||||
data.detail.set(entry.getDetail(), detailHighlights);
|
||||
|
||||
// Keybinding
|
||||
data.keybinding.set(entry.getKeybinding()!);
|
||||
}
|
||||
}
|
||||
|
||||
disposeTemplate(templateId: string, templateData: IQuickOpenEntryGroupTemplateData): void {
|
||||
templateData.actionBar.dispose();
|
||||
templateData.actionBar = null!;
|
||||
templateData.container = null!;
|
||||
templateData.entry = null!;
|
||||
templateData.keybinding = null!;
|
||||
templateData.detail = null!;
|
||||
templateData.group = null!;
|
||||
templateData.icon = null!;
|
||||
templateData.label.dispose();
|
||||
templateData.label = null!;
|
||||
}
|
||||
}
|
||||
|
||||
export class QuickOpenModel implements
|
||||
IModel<QuickOpenEntry>,
|
||||
IDataSource<QuickOpenEntry>,
|
||||
IFilter<QuickOpenEntry>,
|
||||
IRunner<QuickOpenEntry>,
|
||||
IAccessiblityProvider<QuickOpenEntry>
|
||||
{
|
||||
private _entries: QuickOpenEntry[];
|
||||
private _dataSource: IDataSource<QuickOpenEntry>;
|
||||
private _renderer: IRenderer<QuickOpenEntry>;
|
||||
private _filter: IFilter<QuickOpenEntry>;
|
||||
private _runner: IRunner<QuickOpenEntry>;
|
||||
private _accessibilityProvider: IAccessiblityProvider<QuickOpenEntry>;
|
||||
|
||||
constructor(entries: QuickOpenEntry[] = [], actionProvider: IActionProvider = new NoActionProvider()) {
|
||||
this._entries = entries;
|
||||
this._dataSource = this;
|
||||
this._renderer = new Renderer(actionProvider);
|
||||
this._filter = this;
|
||||
this._runner = this;
|
||||
this._accessibilityProvider = this;
|
||||
}
|
||||
|
||||
get entries() { return this._entries; }
|
||||
get dataSource() { return this._dataSource; }
|
||||
get renderer() { return this._renderer; }
|
||||
get filter() { return this._filter; }
|
||||
get runner() { return this._runner; }
|
||||
get accessibilityProvider() { return this._accessibilityProvider; }
|
||||
|
||||
set entries(entries: QuickOpenEntry[]) {
|
||||
this._entries = entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds entries that should show up in the quick open viewer.
|
||||
*/
|
||||
addEntries(entries: QuickOpenEntry[]): void {
|
||||
if (types.isArray(entries)) {
|
||||
this._entries = this._entries.concat(entries);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the entries that should show up in the quick open viewer.
|
||||
*/
|
||||
setEntries(entries: QuickOpenEntry[]): void {
|
||||
if (types.isArray(entries)) {
|
||||
this._entries = entries;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entries that should show up in the quick open viewer.
|
||||
*
|
||||
* @visibleOnly optional parameter to only return visible entries
|
||||
*/
|
||||
getEntries(visibleOnly?: boolean): QuickOpenEntry[] {
|
||||
if (visibleOnly) {
|
||||
return this._entries.filter((e) => !e.isHidden());
|
||||
}
|
||||
|
||||
return this._entries;
|
||||
}
|
||||
|
||||
getId(entry: QuickOpenEntry): string {
|
||||
return entry.getId();
|
||||
}
|
||||
|
||||
getLabel(entry: QuickOpenEntry): string | null {
|
||||
return types.withUndefinedAsNull(entry.getLabel());
|
||||
}
|
||||
|
||||
getAriaLabel(entry: QuickOpenEntry): string {
|
||||
const ariaLabel = entry.getAriaLabel();
|
||||
if (ariaLabel) {
|
||||
return nls.localize('quickOpenAriaLabelEntry', "{0}, picker", entry.getAriaLabel());
|
||||
}
|
||||
|
||||
return nls.localize('quickOpenAriaLabel', "picker");
|
||||
}
|
||||
|
||||
isVisible(entry: QuickOpenEntry): boolean {
|
||||
return !entry.isHidden();
|
||||
}
|
||||
|
||||
run(entry: QuickOpenEntry, mode: Mode, context: IEntryRunContext): boolean {
|
||||
return entry.run(mode, context);
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { isFunction } from 'vs/base/common/types';
|
||||
import { ITree, IRenderer, IFilter, IDataSource, IAccessibilityProvider } from 'vs/base/parts/tree/browser/tree';
|
||||
import { IModel } from 'vs/base/parts/quickopen/common/quickOpen';
|
||||
import { IQuickOpenStyles } from 'vs/base/parts/quickopen/browser/quickOpenWidget';
|
||||
|
||||
export interface IModelProvider {
|
||||
getModel<T>(): IModel<T>;
|
||||
}
|
||||
|
||||
export class DataSource implements IDataSource {
|
||||
|
||||
private modelProvider: IModelProvider;
|
||||
|
||||
constructor(model: IModel<any>);
|
||||
constructor(modelProvider: IModelProvider);
|
||||
constructor(arg: any) {
|
||||
this.modelProvider = isFunction(arg.getModel) ? arg : { getModel: () => arg };
|
||||
}
|
||||
|
||||
getId(tree: ITree, element: any): string {
|
||||
if (!element) {
|
||||
return null!;
|
||||
}
|
||||
|
||||
const model = this.modelProvider.getModel();
|
||||
return model === element ? '__root__' : model.dataSource.getId(element);
|
||||
}
|
||||
|
||||
hasChildren(tree: ITree, element: any): boolean {
|
||||
const model = this.modelProvider.getModel();
|
||||
return !!(model && model === element && model.entries.length > 0);
|
||||
}
|
||||
|
||||
getChildren(tree: ITree, element: any): Promise<any[]> {
|
||||
const model = this.modelProvider.getModel();
|
||||
return Promise.resolve(model === element ? model.entries : []);
|
||||
}
|
||||
|
||||
getParent(tree: ITree, element: any): Promise<any> {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
export class AccessibilityProvider implements IAccessibilityProvider {
|
||||
constructor(private modelProvider: IModelProvider) { }
|
||||
|
||||
getAriaLabel(tree: ITree, element: any): string | null {
|
||||
const model = this.modelProvider.getModel();
|
||||
|
||||
return model.accessibilityProvider ? model.accessibilityProvider.getAriaLabel(element) : null;
|
||||
}
|
||||
|
||||
getPosInSet(tree: ITree, element: any): string {
|
||||
const model = this.modelProvider.getModel();
|
||||
let i = 0;
|
||||
if (model.filter) {
|
||||
for (const entry of model.entries) {
|
||||
if (model.filter.isVisible(entry)) {
|
||||
i++;
|
||||
}
|
||||
if (entry === element) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
i = model.entries.indexOf(element) + 1;
|
||||
}
|
||||
return String(i);
|
||||
}
|
||||
|
||||
getSetSize(): string {
|
||||
const model = this.modelProvider.getModel();
|
||||
let n = 0;
|
||||
if (model.filter) {
|
||||
for (const entry of model.entries) {
|
||||
if (model.filter.isVisible(entry)) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n = model.entries.length;
|
||||
}
|
||||
return String(n);
|
||||
}
|
||||
}
|
||||
|
||||
export class Filter implements IFilter {
|
||||
|
||||
constructor(private modelProvider: IModelProvider) { }
|
||||
|
||||
isVisible(tree: ITree, element: any): boolean {
|
||||
const model = this.modelProvider.getModel();
|
||||
|
||||
if (!model.filter) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return model.filter.isVisible(element);
|
||||
}
|
||||
}
|
||||
|
||||
export class Renderer implements IRenderer {
|
||||
private styles: IQuickOpenStyles;
|
||||
|
||||
constructor(private modelProvider: IModelProvider, styles: IQuickOpenStyles) {
|
||||
this.styles = styles;
|
||||
}
|
||||
|
||||
updateStyles(styles: IQuickOpenStyles): void {
|
||||
this.styles = styles;
|
||||
}
|
||||
|
||||
getHeight(tree: ITree, element: any): number {
|
||||
const model = this.modelProvider.getModel();
|
||||
return model.renderer.getHeight(element);
|
||||
}
|
||||
|
||||
getTemplateId(tree: ITree, element: any): string {
|
||||
const model = this.modelProvider.getModel();
|
||||
return model.renderer.getTemplateId(element);
|
||||
}
|
||||
|
||||
renderTemplate(tree: ITree, templateId: string, container: HTMLElement): any {
|
||||
const model = this.modelProvider.getModel();
|
||||
return model.renderer.renderTemplate(templateId, container, this.styles);
|
||||
}
|
||||
|
||||
renderElement(tree: ITree, element: any, templateId: string, templateData: any): void {
|
||||
const model = this.modelProvider.getModel();
|
||||
model.renderer.renderElement(element, templateId, templateData, this.styles);
|
||||
}
|
||||
|
||||
disposeTemplate(tree: ITree, templateId: string, templateData: any): void {
|
||||
const model = this.modelProvider.getModel();
|
||||
model.renderer.disposeTemplate(templateId, templateData);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,169 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-quick-open-widget {
|
||||
position: absolute;
|
||||
width: 600px;
|
||||
z-index: 2000;
|
||||
padding-bottom: 6px;
|
||||
left: 50%;
|
||||
margin-left: -300px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .monaco-progress-container {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 38px;
|
||||
z-index: 1;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .monaco-progress-container .progress-bit {
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-input {
|
||||
width: 588px;
|
||||
border: none;
|
||||
margin: 6px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-input .monaco-inputbox {
|
||||
width: 100%;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-result-count {
|
||||
position: absolute;
|
||||
left: -10000px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .monaco-tree-row > .content > .sub-content {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget.content-changing .quick-open-tree .monaco-scrollable-element .slider {
|
||||
display: none; /* scrollbar slider causes some hectic updates when input changes quickly, so hide it while quick open changes */
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .quick-open-entry {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .quick-open-entry > .quick-open-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon {
|
||||
overflow: hidden;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
vertical-align: middle;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .monaco-icon-label,
|
||||
.monaco-quick-open-widget .quick-open-tree .monaco-icon-label .monaco-icon-label-container > .monaco-icon-name-container {
|
||||
flex: 1; /* make sure the icon label grows within the row */
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .quick-open-entry .monaco-highlighted-label span {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .quick-open-entry .monaco-highlighted-label .codicon {
|
||||
vertical-align: sub; /* vertically align codicon */
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .quick-open-entry-meta {
|
||||
opacity: 0.7;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .content.has-group-label .quick-open-entry-keybinding {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .quick-open-entry-keybinding .monaco-keybinding-key {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .results-group {
|
||||
margin-right: 18px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .monaco-tree-row.focused > .content.has-actions > .results-group,
|
||||
.monaco-quick-open-widget .quick-open-tree .monaco-tree-row:hover:not(.highlighted) > .content.has-actions > .results-group,
|
||||
.monaco-quick-open-widget .quick-open-tree .focused .monaco-tree-row.focused > .content.has-actions > .results-group {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .results-group-separator {
|
||||
border-top-width: 1px;
|
||||
border-top-style: solid;
|
||||
box-sizing: border-box;
|
||||
margin-left: -11px;
|
||||
padding-left: 11px;
|
||||
}
|
||||
|
||||
/* Actions in Quick Open Items */
|
||||
|
||||
.monaco-tree .monaco-tree-row > .content.actions {
|
||||
position: relative;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-row > .content.actions > .sub-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-row > .content.actions .action-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-row > .content.actions > .primary-action-bar {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-row > .content.actions > .primary-action-bar {
|
||||
display: none;
|
||||
padding: 0 0.8em 0 0.4em;
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-row.focused > .content.has-actions > .primary-action-bar {
|
||||
width: 0; /* in order to support a11y with keyboard, we use width: 0 to hide the actions, which still allows to "Tab" into the actions */
|
||||
display: block;
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-row:hover:not(.highlighted) > .content.has-actions > .primary-action-bar,
|
||||
.monaco-tree.focused .monaco-tree-row.focused > .content.has-actions > .primary-action-bar,
|
||||
.monaco-tree .monaco-tree-row > .content.has-actions.more > .primary-action-bar {
|
||||
width: inherit;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-row > .content.actions > .primary-action-bar .action-label {
|
||||
margin-right: 0.4em;
|
||||
margin-top: 4px;
|
||||
background-repeat: no-repeat;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.monaco-quick-open-widget .quick-open-tree .monaco-highlighted-label .highlight {
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ResolvedKeybinding } from 'vs/base/common/keyCodes';
|
||||
|
||||
export interface IQuickNavigateConfiguration {
|
||||
keybindings: ResolvedKeybinding[];
|
||||
}
|
||||
|
||||
export interface IAutoFocus {
|
||||
|
||||
/**
|
||||
* The index of the element to focus in the result list.
|
||||
*/
|
||||
autoFocusIndex?: number;
|
||||
|
||||
/**
|
||||
* If set to true, will automatically select the first entry from the result list.
|
||||
*/
|
||||
autoFocusFirstEntry?: boolean;
|
||||
|
||||
/**
|
||||
* If set to true, will automatically select the second entry from the result list.
|
||||
*/
|
||||
autoFocusSecondEntry?: boolean;
|
||||
|
||||
/**
|
||||
* If set to true, will automatically select the last entry from the result list.
|
||||
*/
|
||||
autoFocusLastEntry?: boolean;
|
||||
|
||||
/**
|
||||
* If set to true, will automatically select any entry whose label starts with the search
|
||||
* value. Since some entries to the top might match the query but not on the prefix, this
|
||||
* allows to select the most accurate match (matching the prefix) while still showing other
|
||||
* elements.
|
||||
*/
|
||||
autoFocusPrefixMatch?: string;
|
||||
}
|
||||
|
||||
export const enum Mode {
|
||||
PREVIEW,
|
||||
OPEN,
|
||||
OPEN_IN_BACKGROUND
|
||||
}
|
||||
|
||||
export interface IEntryRunContext {
|
||||
event: any;
|
||||
keymods: IKeyMods;
|
||||
quickNavigateConfiguration: IQuickNavigateConfiguration | undefined;
|
||||
}
|
||||
|
||||
export interface IKeyMods {
|
||||
ctrlCmd: boolean;
|
||||
alt: boolean;
|
||||
}
|
||||
|
||||
export interface IDataSource<T> {
|
||||
getId(entry: T): string;
|
||||
getLabel(entry: T): string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* See vs/base/parts/tree/browser/tree.ts - IRenderer
|
||||
*/
|
||||
export interface IRenderer<T> {
|
||||
getHeight(entry: T): number;
|
||||
getTemplateId(entry: T): string;
|
||||
renderTemplate(templateId: string, container: any /* HTMLElement */, styles: any): any;
|
||||
renderElement(entry: T, templateId: string, templateData: any, styles: any): void;
|
||||
disposeTemplate(templateId: string, templateData: any): void;
|
||||
}
|
||||
|
||||
export interface IFilter<T> {
|
||||
isVisible(entry: T): boolean;
|
||||
}
|
||||
|
||||
export interface IAccessiblityProvider<T> {
|
||||
getAriaLabel(entry: T): string;
|
||||
}
|
||||
|
||||
export interface IRunner<T> {
|
||||
run(entry: T, mode: Mode, context: IEntryRunContext): boolean;
|
||||
}
|
||||
|
||||
export interface IModel<T> {
|
||||
entries: T[];
|
||||
dataSource: IDataSource<T>;
|
||||
renderer: IRenderer<T>;
|
||||
runner: IRunner<T>;
|
||||
filter?: IFilter<T>;
|
||||
accessibilityProvider?: IAccessiblityProvider<T>;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { QuickOpenModel, QuickOpenEntry, QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel';
|
||||
import { DataSource } from 'vs/base/parts/quickopen/browser/quickOpenViewer';
|
||||
|
||||
suite('QuickOpen', () => {
|
||||
test('QuickOpenModel', () => {
|
||||
const model = new QuickOpenModel();
|
||||
|
||||
const entry1 = new QuickOpenEntry();
|
||||
const entry2 = new QuickOpenEntry();
|
||||
const entry3 = new QuickOpenEntryGroup();
|
||||
|
||||
assert.notEqual(entry1.getId(), entry2.getId());
|
||||
assert.notEqual(entry2.getId(), entry3.getId());
|
||||
|
||||
model.addEntries([entry1, entry2, entry3]);
|
||||
assert.equal(3, model.getEntries().length);
|
||||
|
||||
model.setEntries([entry1, entry2]);
|
||||
assert.equal(2, model.getEntries().length);
|
||||
|
||||
entry1.setHidden(true);
|
||||
assert.equal(1, model.getEntries(true).length);
|
||||
assert.equal(entry2, model.getEntries(true)[0]);
|
||||
});
|
||||
|
||||
test('QuickOpenDataSource', async () => {
|
||||
const model = new QuickOpenModel();
|
||||
|
||||
const entry1 = new QuickOpenEntry();
|
||||
const entry2 = new QuickOpenEntry();
|
||||
const entry3 = new QuickOpenEntryGroup();
|
||||
|
||||
model.addEntries([entry1, entry2, entry3]);
|
||||
|
||||
const ds = new DataSource(model);
|
||||
assert.equal(entry1.getId(), ds.getId(null!, entry1));
|
||||
assert.equal(true, ds.hasChildren(null!, model));
|
||||
assert.equal(false, ds.hasChildren(null!, entry1));
|
||||
|
||||
const children = await ds.getChildren(null!, model);
|
||||
assert.equal(3, children.length);
|
||||
});
|
||||
});
|
||||
@@ -18,17 +18,17 @@ export enum StorageHint {
|
||||
}
|
||||
|
||||
export interface IStorageOptions {
|
||||
hint?: StorageHint;
|
||||
readonly hint?: StorageHint;
|
||||
}
|
||||
|
||||
export interface IUpdateRequest {
|
||||
insert?: Map<string, string>;
|
||||
delete?: Set<string>;
|
||||
readonly insert?: Map<string, string>;
|
||||
readonly delete?: Set<string>;
|
||||
}
|
||||
|
||||
export interface IStorageItemsChangeEvent {
|
||||
changed?: Map<string, string>;
|
||||
deleted?: Set<string>;
|
||||
readonly changed?: Map<string, string>;
|
||||
readonly deleted?: Set<string>;
|
||||
}
|
||||
|
||||
export interface IStorageDatabase {
|
||||
|
||||
@@ -14,7 +14,6 @@ import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/b
|
||||
|
||||
interface IDatabaseConnection {
|
||||
readonly db: Database;
|
||||
|
||||
readonly isInMemory: boolean;
|
||||
|
||||
isErroneous?: boolean;
|
||||
@@ -22,7 +21,7 @@ interface IDatabaseConnection {
|
||||
}
|
||||
|
||||
export interface ISQLiteStorageDatabaseOptions {
|
||||
logging?: ISQLiteStorageDatabaseLoggingOptions;
|
||||
readonly logging?: ISQLiteStorageDatabaseLoggingOptions;
|
||||
}
|
||||
|
||||
export interface ISQLiteStorageDatabaseLoggingOptions {
|
||||
@@ -45,7 +44,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
|
||||
|
||||
private readonly whenConnected = this.connect(this.path);
|
||||
|
||||
constructor(private path: string, private options: ISQLiteStorageDatabaseOptions = Object.create(null)) { }
|
||||
constructor(private readonly path: string, private readonly options: ISQLiteStorageDatabaseOptions = Object.create(null)) { }
|
||||
|
||||
async getItems(): Promise<Map<string, string>> {
|
||||
const connection = await this.whenConnected;
|
||||
|
||||
+3
-4
@@ -4,13 +4,12 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { prepareActions } from 'vs/workbench/browser/actions';
|
||||
import { Separator, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
|
||||
suite('Workbench action registry', () => {
|
||||
suite('Actionbar', () => {
|
||||
|
||||
test('Workbench Action Bar prepareActions()', function () {
|
||||
test('prepareActions()', function () {
|
||||
let a1 = new Separator();
|
||||
let a2 = new Separator();
|
||||
let a3 = new Action('a3');
|
||||
@@ -2,9 +2,11 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { IMatch } from 'vs/base/common/filters';
|
||||
import { matchesFuzzyCodiconAware, parseCodicons, IParsedCodicons } from 'vs/base/common/codicon';
|
||||
import { stripCodicons } from 'vs/base/common/codicons';
|
||||
|
||||
export interface ICodiconFilter {
|
||||
// Returns null if word doesn't match.
|
||||
@@ -64,3 +66,13 @@ suite('Codicon', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Codicons', () => {
|
||||
|
||||
test('stripCodicons', () => {
|
||||
assert.equal(stripCodicons('Hello World'), 'Hello World');
|
||||
assert.equal(stripCodicons('$(Hello World'), '$(Hello World');
|
||||
assert.equal(stripCodicons('$(Hello) World'), ' World');
|
||||
assert.equal(stripCodicons('$(Hello) W$(oi)rld'), ' Wrld');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,7 +43,7 @@ class NullAccessorClass implements scorer.IItemAccessor<URI> {
|
||||
}
|
||||
|
||||
function _doScore(target: string, query: string, fuzzy: boolean): scorer.Score {
|
||||
return scorer.score(target, query, query.toLowerCase(), fuzzy);
|
||||
return scorer.score(target, scorer.prepareQuery(query), fuzzy);
|
||||
}
|
||||
|
||||
function scoreItem<T>(item: T, query: string, fuzzy: boolean, accessor: scorer.IItemAccessor<T>, cache: scorer.ScorerCache): scorer.IItemScore {
|
||||
@@ -109,6 +109,42 @@ 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);
|
||||
@@ -820,11 +856,42 @@ suite('Fuzzy Scorer', () => {
|
||||
assert.equal(res[0], resourceB);
|
||||
});
|
||||
|
||||
test('prepareSearchForScoring', () => {
|
||||
test('prepareQuery', () => {
|
||||
assert.equal(scorer.prepareQuery(' f*a ').value, 'fa');
|
||||
assert.equal(scorer.prepareQuery('model Tester.ts').original, 'model Tester.ts');
|
||||
assert.equal(scorer.prepareQuery('model Tester.ts').originalLowercase, 'model Tester.ts'.toLowerCase());
|
||||
assert.equal(scorer.prepareQuery('model Tester.ts').value, 'modelTester.ts');
|
||||
assert.equal(scorer.prepareQuery('Model Tester.ts').lowercase, 'modeltester.ts');
|
||||
assert.equal(scorer.prepareQuery('Model Tester.ts').valueLowercase, 'modeltester.ts');
|
||||
assert.equal(scorer.prepareQuery('ModelTester.ts').containsPathSeparator, false);
|
||||
assert.equal(scorer.prepareQuery('Model' + sep + 'Tester.ts').containsPathSeparator, true);
|
||||
|
||||
// with spaces
|
||||
let query = scorer.prepareQuery('He*llo World');
|
||||
assert.equal(query.original, 'He*llo World');
|
||||
assert.equal(query.value, 'HelloWorld');
|
||||
assert.equal(query.valueLowercase, 'HelloWorld'.toLowerCase());
|
||||
assert.equal(query.values?.length, 2);
|
||||
assert.equal(query.values?.[0].original, 'He*llo');
|
||||
assert.equal(query.values?.[0].value, 'Hello');
|
||||
assert.equal(query.values?.[0].valueLowercase, 'Hello'.toLowerCase());
|
||||
assert.equal(query.values?.[1].original, 'World');
|
||||
assert.equal(query.values?.[1].value, 'World');
|
||||
assert.equal(query.values?.[1].valueLowercase, 'World'.toLowerCase());
|
||||
|
||||
// with spaces that are empty
|
||||
query = scorer.prepareQuery(' Hello World ');
|
||||
assert.equal(query.original, ' Hello World ');
|
||||
assert.equal(query.originalLowercase, ' Hello World '.toLowerCase());
|
||||
assert.equal(query.value, 'HelloWorld');
|
||||
assert.equal(query.valueLowercase, 'HelloWorld'.toLowerCase());
|
||||
assert.equal(query.values?.length, 2);
|
||||
assert.equal(query.values?.[0].original, 'Hello');
|
||||
assert.equal(query.values?.[0].originalLowercase, 'Hello'.toLowerCase());
|
||||
assert.equal(query.values?.[0].value, 'Hello');
|
||||
assert.equal(query.values?.[0].valueLowercase, 'Hello'.toLowerCase());
|
||||
assert.equal(query.values?.[1].original, 'World');
|
||||
assert.equal(query.values?.[1].originalLowercase, 'World'.toLowerCase());
|
||||
assert.equal(query.values?.[1].value, 'World');
|
||||
assert.equal(query.values?.[1].valueLowercase, 'World'.toLowerCase());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -171,7 +171,7 @@ export class CodeApplication extends Disposable {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (source === 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%09%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E') {
|
||||
if (source === 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%20role%3D%22document%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E') {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -457,6 +457,9 @@ export class TextAreaHandler extends ViewPart {
|
||||
this.textArea.setAttribute('aria-autocomplete', 'both');
|
||||
this.textArea.removeAttribute('aria-activedescendant');
|
||||
}
|
||||
if (options.role) {
|
||||
this.textArea.setAttribute('role', options.role);
|
||||
}
|
||||
}
|
||||
|
||||
// --- end view API
|
||||
|
||||
@@ -333,6 +333,7 @@ export interface IOverviewRuler {
|
||||
*/
|
||||
export interface IEditorAriaOptions {
|
||||
activeDescendant: string | undefined;
|
||||
role?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,17 +14,17 @@ import { IModelDecorationOptions, IModelDecorationOverviewRulerOptions, Overview
|
||||
import { IResourceEditorInput } from 'vs/platform/editor/common/editor';
|
||||
import { IColorTheme, IThemeService, ThemeColor } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
class RefCountedStyleSheet {
|
||||
export class RefCountedStyleSheet {
|
||||
|
||||
private readonly _parent: CodeEditorServiceImpl;
|
||||
private readonly _editorId: string;
|
||||
public readonly styleSheet: HTMLStyleElement;
|
||||
private readonly _styleSheet: HTMLStyleElement;
|
||||
private _refCount: number;
|
||||
|
||||
constructor(parent: CodeEditorServiceImpl, editorId: string, styleSheet: HTMLStyleElement) {
|
||||
this._parent = parent;
|
||||
this._editorId = editorId;
|
||||
this.styleSheet = styleSheet;
|
||||
this._styleSheet = styleSheet;
|
||||
this._refCount = 0;
|
||||
}
|
||||
|
||||
@@ -35,17 +35,26 @@ class RefCountedStyleSheet {
|
||||
public unref(): void {
|
||||
this._refCount--;
|
||||
if (this._refCount === 0) {
|
||||
this.styleSheet.parentNode?.removeChild(this.styleSheet);
|
||||
this._styleSheet.parentNode?.removeChild(this._styleSheet);
|
||||
this._parent._removeEditorStyleSheets(this._editorId);
|
||||
}
|
||||
}
|
||||
|
||||
public insertRule(rule: string, index?: number): void {
|
||||
const sheet = <CSSStyleSheet>this._styleSheet.sheet;
|
||||
sheet.insertRule(rule, index);
|
||||
}
|
||||
|
||||
public removeRulesContainingSelector(ruleName: string): void {
|
||||
dom.removeCSSRulesContainingSelector(ruleName, this._styleSheet);
|
||||
}
|
||||
}
|
||||
|
||||
class GlobalStyleSheet {
|
||||
public readonly styleSheet: HTMLStyleElement;
|
||||
export class GlobalStyleSheet {
|
||||
private readonly _styleSheet: HTMLStyleElement;
|
||||
|
||||
constructor(styleSheet: HTMLStyleElement) {
|
||||
this.styleSheet = styleSheet;
|
||||
this._styleSheet = styleSheet;
|
||||
}
|
||||
|
||||
public ref(): void {
|
||||
@@ -53,6 +62,15 @@ class GlobalStyleSheet {
|
||||
|
||||
public unref(): void {
|
||||
}
|
||||
|
||||
public insertRule(rule: string, index?: number): void {
|
||||
const sheet = <CSSStyleSheet>this._styleSheet.sheet;
|
||||
sheet.insertRule(rule, index);
|
||||
}
|
||||
|
||||
public removeRulesContainingSelector(ruleName: string): void {
|
||||
dom.removeCSSRulesContainingSelector(ruleName, this._styleSheet);
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService {
|
||||
@@ -62,9 +80,9 @@ export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService {
|
||||
private readonly _editorStyleSheets = new Map<string, RefCountedStyleSheet>();
|
||||
private readonly _themeService: IThemeService;
|
||||
|
||||
constructor(@IThemeService themeService: IThemeService, styleSheet: HTMLStyleElement | null = null) {
|
||||
constructor(@IThemeService themeService: IThemeService, styleSheet: GlobalStyleSheet | null = null) {
|
||||
super();
|
||||
this._globalStyleSheet = styleSheet ? new GlobalStyleSheet(styleSheet) : null;
|
||||
this._globalStyleSheet = styleSheet ? styleSheet : null;
|
||||
this._themeService = themeService;
|
||||
}
|
||||
|
||||
@@ -100,7 +118,7 @@ export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService {
|
||||
if (!provider) {
|
||||
const styleSheet = this._getOrCreateStyleSheet(editor);
|
||||
const providerArgs: ProviderArguments = {
|
||||
styleSheet: styleSheet.styleSheet,
|
||||
styleSheet: styleSheet,
|
||||
key: key,
|
||||
parentTypeKey: parentTypeKey,
|
||||
options: options || Object.create(null)
|
||||
@@ -188,7 +206,7 @@ class DecorationSubTypeOptionsProvider implements IModelDecorationOptionsProvide
|
||||
}
|
||||
|
||||
interface ProviderArguments {
|
||||
styleSheet: HTMLStyleElement;
|
||||
styleSheet: GlobalStyleSheet | RefCountedStyleSheet;
|
||||
key: string;
|
||||
parentTypeKey?: string;
|
||||
options: IDecorationRenderOptions;
|
||||
@@ -330,7 +348,7 @@ class DecorationCSSRules {
|
||||
private readonly _providerArgs: ProviderArguments;
|
||||
private _usesThemeColors: boolean;
|
||||
|
||||
public constructor(ruleType: ModelDecorationCSSRuleType, providerArgs: ProviderArguments, themeService: IThemeService) {
|
||||
constructor(ruleType: ModelDecorationCSSRuleType, providerArgs: ProviderArguments, themeService: IThemeService) {
|
||||
this._theme = themeService.getColorTheme();
|
||||
this._ruleType = ruleType;
|
||||
this._providerArgs = providerArgs;
|
||||
@@ -414,7 +432,7 @@ class DecorationCSSRules {
|
||||
default:
|
||||
throw new Error('Unknown rule type: ' + this._ruleType);
|
||||
}
|
||||
const sheet = <CSSStyleSheet>this._providerArgs.styleSheet.sheet;
|
||||
const sheet = this._providerArgs.styleSheet;
|
||||
|
||||
let hasContent = false;
|
||||
if (unthemedCSS.length > 0) {
|
||||
@@ -433,7 +451,7 @@ class DecorationCSSRules {
|
||||
}
|
||||
|
||||
private _removeCSS(): void {
|
||||
dom.removeCSSRulesContainingSelector(this._unThemedSelector, this._providerArgs.styleSheet);
|
||||
this._providerArgs.styleSheet.removeRulesContainingSelector(this._unThemedSelector);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,9 +40,9 @@ class SingleModelEditStackData {
|
||||
public changes: TextChange[]
|
||||
) { }
|
||||
|
||||
public append(model: ITextModel, operations: IValidEditOperation[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {
|
||||
if (operations.length > 0) {
|
||||
this.changes = compressConsecutiveTextChanges(this.changes, operations.map(op => op.textChange));
|
||||
public append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {
|
||||
if (textChanges.length > 0) {
|
||||
this.changes = compressConsecutiveTextChanges(this.changes, textChanges);
|
||||
}
|
||||
this.afterEOL = afterEOL;
|
||||
this.afterVersionId = afterVersionId;
|
||||
@@ -168,9 +168,9 @@ export class SingleModelEditStackElement implements IResourceUndoRedoElement {
|
||||
return (this.model === model && this._data instanceof SingleModelEditStackData);
|
||||
}
|
||||
|
||||
public append(model: ITextModel, operations: IValidEditOperation[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {
|
||||
public append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {
|
||||
if (this._data instanceof SingleModelEditStackData) {
|
||||
this._data.append(model, operations, afterEOL, afterVersionId, afterCursorState);
|
||||
this._data.append(model, textChanges, afterEOL, afterVersionId, afterCursorState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,10 +258,10 @@ export class MultiModelEditStackElement implements IWorkspaceUndoRedoElement {
|
||||
return false;
|
||||
}
|
||||
|
||||
public append(model: ITextModel, operations: IValidEditOperation[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {
|
||||
public append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {
|
||||
const key = uriGetComparisonKey(model.uri);
|
||||
const editStackElement = this._editStackElementsMap.get(key)!;
|
||||
editStackElement.append(model, operations, afterEOL, afterVersionId, afterCursorState);
|
||||
editStackElement.append(model, textChanges, afterEOL, afterVersionId, afterCursorState);
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
@@ -355,7 +355,14 @@ export class EditStack {
|
||||
const editStackElement = this._getOrCreateEditStackElement(beforeCursorState);
|
||||
const inverseEditOperations = this._model.applyEdits(editOperations, true);
|
||||
const afterCursorState = EditStack._computeCursorState(cursorStateComputer, inverseEditOperations);
|
||||
editStackElement.append(this._model, inverseEditOperations, getModelEOL(this._model), this._model.getAlternativeVersionId(), afterCursorState);
|
||||
const textChanges = inverseEditOperations.map((op, index) => ({ index: index, textChange: op.textChange }));
|
||||
textChanges.sort((a, b) => {
|
||||
if (a.textChange.oldPosition === b.textChange.oldPosition) {
|
||||
return a.index - b.index;
|
||||
}
|
||||
return a.textChange.oldPosition - b.textChange.oldPosition;
|
||||
});
|
||||
editStackElement.append(this._model, textChanges.map(op => op.textChange), getModelEOL(this._model), this._model.getAlternativeVersionId(), afterCursorState);
|
||||
return afterCursorState;
|
||||
}
|
||||
|
||||
|
||||
@@ -661,12 +661,14 @@ const enum Constants {
|
||||
class HashTableEntry {
|
||||
public readonly tokenTypeIndex: number;
|
||||
public readonly tokenModifierSet: number;
|
||||
public readonly languageId: number;
|
||||
public readonly metadata: number;
|
||||
public next: HashTableEntry | null;
|
||||
|
||||
constructor(tokenTypeIndex: number, tokenModifierSet: number, metadata: number) {
|
||||
constructor(tokenTypeIndex: number, tokenModifierSet: number, languageId: number, metadata: number) {
|
||||
this.tokenTypeIndex = tokenTypeIndex;
|
||||
this.tokenModifierSet = tokenModifierSet;
|
||||
this.languageId = languageId;
|
||||
this.metadata = metadata;
|
||||
this.next = null;
|
||||
}
|
||||
@@ -697,16 +699,17 @@ class HashTable {
|
||||
}
|
||||
}
|
||||
|
||||
private _hashFunc(tokenTypeIndex: number, tokenModifierSet: number): number {
|
||||
return ((((tokenTypeIndex << 5) - tokenTypeIndex) + tokenModifierSet) | 0) % this._currentLength; // tokenTypeIndex * 31 + tokenModifierSet, keep as int32
|
||||
private _hashFunc(tokenTypeIndex: number, tokenModifierSet: number, languageId: number): number {
|
||||
const hash = (n1: number, n2: number) => (((n1 << 5) - n1) + n2) | 0; // n1 * 31 + n2, keep as int32
|
||||
return hash(hash(tokenTypeIndex, tokenModifierSet), languageId) % this._currentLength;
|
||||
}
|
||||
|
||||
public get(tokenTypeIndex: number, tokenModifierSet: number): HashTableEntry | null {
|
||||
const hash = this._hashFunc(tokenTypeIndex, tokenModifierSet);
|
||||
public get(tokenTypeIndex: number, tokenModifierSet: number, languageId: number): HashTableEntry | null {
|
||||
const hash = this._hashFunc(tokenTypeIndex, tokenModifierSet, languageId);
|
||||
|
||||
let p = this._elements[hash];
|
||||
while (p) {
|
||||
if (p.tokenTypeIndex === tokenTypeIndex && p.tokenModifierSet === tokenModifierSet) {
|
||||
if (p.tokenTypeIndex === tokenTypeIndex && p.tokenModifierSet === tokenModifierSet && p.languageId === languageId) {
|
||||
return p;
|
||||
}
|
||||
p = p.next;
|
||||
@@ -715,7 +718,7 @@ class HashTable {
|
||||
return null;
|
||||
}
|
||||
|
||||
public add(tokenTypeIndex: number, tokenModifierSet: number, metadata: number): void {
|
||||
public add(tokenTypeIndex: number, tokenModifierSet: number, languageId: number, metadata: number): void {
|
||||
this._elementsCount++;
|
||||
if (this._growCount !== 0 && this._elementsCount >= this._growCount) {
|
||||
// expand!
|
||||
@@ -737,11 +740,11 @@ class HashTable {
|
||||
}
|
||||
}
|
||||
}
|
||||
this._add(new HashTableEntry(tokenTypeIndex, tokenModifierSet, metadata));
|
||||
this._add(new HashTableEntry(tokenTypeIndex, tokenModifierSet, languageId, metadata));
|
||||
}
|
||||
|
||||
private _add(element: HashTableEntry): void {
|
||||
const hash = this._hashFunc(element.tokenTypeIndex, element.tokenModifierSet);
|
||||
const hash = this._hashFunc(element.tokenTypeIndex, element.tokenModifierSet, element.languageId);
|
||||
element.next = this._elements[hash];
|
||||
this._elements[hash] = element;
|
||||
}
|
||||
@@ -759,8 +762,8 @@ class SemanticColoringProviderStyling {
|
||||
this._hashTable = new HashTable();
|
||||
}
|
||||
|
||||
public getMetadata(tokenTypeIndex: number, tokenModifierSet: number): number {
|
||||
const entry = this._hashTable.get(tokenTypeIndex, tokenModifierSet);
|
||||
public getMetadata(tokenTypeIndex: number, tokenModifierSet: number, languageId: LanguageIdentifier): number {
|
||||
const entry = this._hashTable.get(tokenTypeIndex, tokenModifierSet, languageId.id);
|
||||
let metadata: number;
|
||||
if (entry) {
|
||||
metadata = entry.metadata;
|
||||
@@ -775,7 +778,7 @@ class SemanticColoringProviderStyling {
|
||||
modifierSet = modifierSet >> 1;
|
||||
}
|
||||
|
||||
const tokenStyle = this._themeService.getColorTheme().getTokenStyleMetadata(tokenType, tokenModifiers);
|
||||
const tokenStyle = this._themeService.getColorTheme().getTokenStyleMetadata(tokenType, tokenModifiers, languageId.language);
|
||||
if (typeof tokenStyle === 'undefined') {
|
||||
metadata = Constants.NO_STYLING;
|
||||
} else {
|
||||
@@ -801,7 +804,7 @@ class SemanticColoringProviderStyling {
|
||||
metadata = Constants.NO_STYLING;
|
||||
}
|
||||
}
|
||||
this._hashTable.add(tokenTypeIndex, tokenModifierSet, metadata);
|
||||
this._hashTable.add(tokenTypeIndex, tokenModifierSet, languageId.id, metadata);
|
||||
}
|
||||
if (this._logService.getLevel() === LogLevel.Trace) {
|
||||
const type = this._legend.tokenTypes[tokenTypeIndex];
|
||||
@@ -1042,6 +1045,8 @@ class ModelSemanticColoring extends Disposable {
|
||||
|
||||
const result: MultilineTokens2[] = [];
|
||||
|
||||
const languageId = this._model.getLanguageIdentifier();
|
||||
|
||||
let tokenIndex = 0;
|
||||
let lastLineNumber = 1;
|
||||
let lastStartCharacter = 0;
|
||||
@@ -1081,7 +1086,7 @@ class ModelSemanticColoring extends Disposable {
|
||||
const length = srcData[srcOffset + 2];
|
||||
const tokenTypeIndex = srcData[srcOffset + 3];
|
||||
const tokenModifierSet = srcData[srcOffset + 4];
|
||||
const metadata = styling.getMetadata(tokenTypeIndex, tokenModifierSet);
|
||||
const metadata = styling.getMetadata(tokenTypeIndex, tokenModifierSet, languageId);
|
||||
|
||||
if (metadata !== Constants.NO_STYLING) {
|
||||
if (areaLine === 0) {
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
color: var(--outline-element-color);
|
||||
}
|
||||
|
||||
.monaco-tree .monaco-tree-row.focused .outline-element .outline-element-detail {
|
||||
visibility: inherit;
|
||||
}
|
||||
|
||||
.monaco-list .outline-element .outline-element-decoration {
|
||||
opacity: 0.75;
|
||||
font-size: 90%;
|
||||
|
||||
-1
@@ -62,7 +62,6 @@ function flatten(bucket: DocumentSymbol[], entries: DocumentSymbol[], overrideCo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CommandsRegistry.registerCommand('_executeDocumentSymbolProvider', async function (accessor, ...args) {
|
||||
const [resource] = args;
|
||||
assertType(URI.isUri(resource));
|
||||
@@ -241,7 +241,7 @@ export class ChangeIndentationSizeAction extends EditorAction {
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 50/* quick open is sensitive to being opened so soon after another */);
|
||||
}, 50/* quick input is sensitive to being opened so soon after another */);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ export abstract class AbstractEditorNavigationQuickAccessProvider implements IQu
|
||||
|
||||
// Remember view state and update it when the cursor position
|
||||
// changes even later because it could be that the user has
|
||||
// configured quick open to remain open when focus is lost and
|
||||
// configured quick access to remain open when focus is lost and
|
||||
// we always want to restore the current location.
|
||||
let lastKnownEditorViewState = withNullAsUndefined(editor.saveViewState());
|
||||
disposables.add(codeEditor.onDidChangeCursorPosition(() => {
|
||||
|
||||
@@ -17,6 +17,7 @@ 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';
|
||||
|
||||
export interface IGotoSymbolQuickPickItem extends IQuickPickItem {
|
||||
kind: SymbolKind,
|
||||
@@ -155,7 +156,7 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
// Collect symbol picks
|
||||
picker.busy = true;
|
||||
try {
|
||||
const items = await this.doGetSymbolPicks(symbolsPromise, picker.value.substr(AbstractGotoSymbolQuickAccessProvider.PREFIX.length).trim(), picksCts.token);
|
||||
const items = await this.doGetSymbolPicks(symbolsPromise, prepareQuery(picker.value.substr(AbstractGotoSymbolQuickAccessProvider.PREFIX.length).trim()), undefined, picksCts.token);
|
||||
if (token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
@@ -194,18 +195,24 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
return disposables;
|
||||
}
|
||||
|
||||
protected async doGetSymbolPicks(symbolsPromise: Promise<DocumentSymbol[]>, filter: string, token: CancellationToken): Promise<Array<IGotoSymbolQuickPickItem | IQuickPickSeparator>> {
|
||||
protected async doGetSymbolPicks(symbolsPromise: Promise<DocumentSymbol[]>, query: IPreparedQuery, options: { extraContainerLabel?: string } | undefined, token: CancellationToken): Promise<Array<IGotoSymbolQuickPickItem | IQuickPickSeparator>> {
|
||||
const symbols = await symbolsPromise;
|
||||
if (token.isCancellationRequested) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Normalize filter
|
||||
const filterBySymbolKind = filter.indexOf(AbstractGotoSymbolQuickAccessProvider.SCOPE_PREFIX) === 0;
|
||||
const filterBySymbolKind = query.original.indexOf(AbstractGotoSymbolQuickAccessProvider.SCOPE_PREFIX) === 0;
|
||||
const filterPos = filterBySymbolKind ? 1 : 0;
|
||||
const [symbolFilter, containerFilter] = filter.split(' ') as [string, string | undefined];
|
||||
const symbolFilterLow = symbolFilter.toLowerCase();
|
||||
const containerFilterLow = containerFilter?.toLowerCase();
|
||||
|
||||
// Split between symbol and container query if separated by space
|
||||
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);
|
||||
} else {
|
||||
symbolQuery = query;
|
||||
}
|
||||
|
||||
// Convert to symbol picks and apply filtering
|
||||
const filteredSymbolPicks: IGotoSymbolQuickPickItem[] = [];
|
||||
@@ -213,22 +220,28 @@ export abstract class AbstractGotoSymbolQuickAccessProvider extends AbstractEdit
|
||||
const symbol = symbols[index];
|
||||
|
||||
const symbolLabel = trim(symbol.name);
|
||||
const containerLabel = symbol.containerName;
|
||||
|
||||
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 (filter.length > filterPos) {
|
||||
if (query.original.length > filterPos) {
|
||||
|
||||
// Score by symbol
|
||||
symbolScore = fuzzyScore(symbolFilter, symbolFilterLow, filterPos, symbolLabel, symbolLabel.toLowerCase(), 0, true);
|
||||
symbolScore = fuzzyScore(symbolQuery.original, symbolQuery.originalLowercase, filterPos, symbolLabel, symbolLabel.toLowerCase(), 0, true);
|
||||
includeSymbol = !!symbolScore;
|
||||
|
||||
// Score by container if specified
|
||||
if (includeSymbol && containerFilter && containerFilterLow) {
|
||||
if (includeSymbol && containerQuery) {
|
||||
if (containerLabel) {
|
||||
containerScore = fuzzyScore(containerFilter, containerFilterLow, filterPos, containerLabel, containerLabel.toLowerCase(), 0, true);
|
||||
containerScore = fuzzyScore(containerQuery.original, containerQuery.originalLowercase, filterPos, containerLabel, containerLabel.toLowerCase(), 0, true);
|
||||
}
|
||||
|
||||
includeSymbol = !!containerScore;
|
||||
|
||||
@@ -401,12 +401,13 @@ class WordHighlighter {
|
||||
private renderDecorations(): void {
|
||||
this.renderDecorationsTimer = -1;
|
||||
let decorations: IModelDeltaDecoration[] = [];
|
||||
for (let i = 0, len = this.workerRequestValue.length; i < len; i++) {
|
||||
let info = this.workerRequestValue[i];
|
||||
decorations.push({
|
||||
range: info.range,
|
||||
options: WordHighlighter._getDecorationOptions(info.kind)
|
||||
});
|
||||
for (const info of this.workerRequestValue) {
|
||||
if (info.range) {
|
||||
decorations.push({
|
||||
range: info.range,
|
||||
options: WordHighlighter._getDecorationOptions(info.kind)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this._decorationIds = this.editor.deltaDecorations(this._decorationIds, decorations);
|
||||
|
||||
@@ -129,10 +129,6 @@ export class StandaloneQuickInputServiceImpl implements IQuickInputService {
|
||||
cancel(): Promise<void> {
|
||||
return this.activeService.cancel();
|
||||
}
|
||||
|
||||
hide(focusLost?: boolean | undefined): void {
|
||||
return this.activeService.hide(focusLost);
|
||||
}
|
||||
}
|
||||
|
||||
export class QuickInputEditorContribution implements IEditorContribution {
|
||||
|
||||
@@ -134,26 +134,6 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* tree */
|
||||
.monaco-editor.vs .monaco-tree .monaco-tree-row,
|
||||
.monaco-editor.vs-dark .monaco-tree .monaco-tree-row {
|
||||
-ms-high-contrast-adjust: none;
|
||||
color: windowtext !important;
|
||||
}
|
||||
.monaco-editor.vs .monaco-tree .monaco-tree-row.selected,
|
||||
.monaco-editor.vs-dark .monaco-tree .monaco-tree-row.selected,
|
||||
.monaco-editor.vs .monaco-tree .monaco-tree-row.focused,
|
||||
.monaco-editor.vs-dark .monaco-tree .monaco-tree-row.focused {
|
||||
color: highlighttext !important;
|
||||
background-color: highlight !important;
|
||||
}
|
||||
.monaco-editor.vs .monaco-tree .monaco-tree-row:hover,
|
||||
.monaco-editor.vs-dark .monaco-tree .monaco-tree-row:hover {
|
||||
background: transparent !important;
|
||||
border: 1px solid highlight;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* scrollbars */
|
||||
.monaco-editor.vs .monaco-scrollable-element > .scrollbar,
|
||||
.monaco-editor.vs-dark .monaco-scrollable-element > .scrollbar {
|
||||
|
||||
@@ -131,7 +131,7 @@ class StandaloneTheme implements IStandaloneTheme {
|
||||
return this._tokenTheme;
|
||||
}
|
||||
|
||||
public getTokenStyleMetadata(type: string, modifiers: string[]): ITokenStyle | undefined {
|
||||
public getTokenStyleMetadata(type: string, modifiers: string[], modelLanguage: string): ITokenStyle | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ suite('TokenizationSupport2Adapter', () => {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
|
||||
getTokenStyleMetadata: (type: string, modifiers: string[]): ITokenStyle | undefined => {
|
||||
getTokenStyleMetadata: (type: string, modifiers: string[], modelLanguage: string): ITokenStyle | undefined => {
|
||||
return undefined;
|
||||
},
|
||||
|
||||
|
||||
@@ -5616,4 +5616,24 @@ suite('Undo stops', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('issue #93585: Undo multi cursor edit corrupts document', () => {
|
||||
let model = createTextModel(
|
||||
[
|
||||
'hello world',
|
||||
'hello world',
|
||||
].join('\n')
|
||||
);
|
||||
|
||||
withTestCodeEditor(null, { model: model }, (editor, cursor) => {
|
||||
cursor.setSelections('test', [
|
||||
new Selection(2, 7, 2, 12),
|
||||
new Selection(1, 7, 1, 12),
|
||||
]);
|
||||
cursorCommand(cursor, H.Type, { text: 'no' }, 'keyboard');
|
||||
assert.equal(model.getValue(), 'hello no\nhello no');
|
||||
|
||||
CoreEditingCommands.Undo.runEditorCommand(null, editor, null);
|
||||
assert.equal(model.getValue(), 'hello world\nhello world');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,18 +4,17 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { CodeEditorServiceImpl } from 'vs/editor/browser/services/codeEditorServiceImpl';
|
||||
import { CodeEditorServiceImpl, GlobalStyleSheet } from 'vs/editor/browser/services/codeEditorServiceImpl';
|
||||
import { IDecorationRenderOptions } from 'vs/editor/common/editorCommon';
|
||||
import { IResourceEditorInput } from 'vs/platform/editor/common/editor';
|
||||
import { TestColorTheme, TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
|
||||
const themeServiceMock = new TestThemeService();
|
||||
|
||||
export class TestCodeEditorServiceImpl extends CodeEditorServiceImpl {
|
||||
class TestCodeEditorServiceImpl extends CodeEditorServiceImpl {
|
||||
getActiveCodeEditor(): ICodeEditor | null {
|
||||
return null;
|
||||
}
|
||||
@@ -25,6 +24,32 @@ export class TestCodeEditorServiceImpl extends CodeEditorServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
class TestGlobalStyleSheet extends GlobalStyleSheet {
|
||||
|
||||
public rules: string[] = [];
|
||||
|
||||
constructor() {
|
||||
super(null!);
|
||||
}
|
||||
|
||||
public insertRule(rule: string, index?: number): void {
|
||||
this.rules.unshift(rule);
|
||||
}
|
||||
|
||||
public removeRulesContainingSelector(ruleName: string): void {
|
||||
for (let i = 0; i < this.rules.length; i++) {
|
||||
if (this.rules[i].indexOf(ruleName) >= 0) {
|
||||
this.rules.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public read(): string {
|
||||
return this.rules.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
suite.skip('Decoration Render Options', () => { // {{SQL CARBON EDIT}} skip suite
|
||||
let options: IDecorationRenderOptions = {
|
||||
gutterIconPath: URI.parse('https://github.com/Microsoft/vscode/blob/master/resources/linux/code.png'),
|
||||
@@ -45,59 +70,45 @@ suite.skip('Decoration Render Options', () => { // {{SQL CARBON EDIT}} skip suit
|
||||
assert.throws(() => s.resolveDecorationOptions('example', false));
|
||||
});
|
||||
|
||||
function readStyleSheet(styleSheet: HTMLStyleElement): string {
|
||||
if ((<any>styleSheet.sheet).rules) {
|
||||
return Array.prototype.map.call((<any>styleSheet.sheet).rules, (r: { cssText: string }) => r.cssText).join('\n');
|
||||
}
|
||||
return styleSheet.sheet!.toString();
|
||||
function readStyleSheet(styleSheet: TestGlobalStyleSheet): string {
|
||||
return styleSheet.read();
|
||||
}
|
||||
|
||||
test('css properties', () => {
|
||||
let styleSheet = dom.createStyleSheet();
|
||||
let s = new TestCodeEditorServiceImpl(themeServiceMock, styleSheet);
|
||||
const styleSheet = new TestGlobalStyleSheet();
|
||||
const s = new TestCodeEditorServiceImpl(themeServiceMock, styleSheet);
|
||||
s.registerDecorationType('example', options);
|
||||
let sheet = readStyleSheet(styleSheet);
|
||||
assert(
|
||||
sheet.indexOf('background: url(\'https://github.com/Microsoft/vscode/blob/master/resources/linux/code.png\') center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background: url("https://github.com/Microsoft/vscode/blob/master/resources/linux/code.png") center center / contain no-repeat;') > 0
|
||||
|| sheet.indexOf('background-image: url("https://github.com/Microsoft/vscode/blob/master/resources/linux/code.png"); background-size: contain; background-position: center center; background-repeat: no-repeat no-repeat;') > 0
|
||||
);
|
||||
assert(sheet.indexOf('border-color: yellow;') > 0);
|
||||
assert(sheet.indexOf('background-color: red;') > 0);
|
||||
const sheet = readStyleSheet(styleSheet);
|
||||
assert(sheet.indexOf(`{background:url('https://github.com/Microsoft/vscode/blob/master/resources/linux/code.png') center center no-repeat;background-size:contain;}`) >= 0);
|
||||
assert(sheet.indexOf(`{background-color:red;border-color:yellow;box-sizing: border-box;}`) >= 0);
|
||||
});
|
||||
|
||||
test('theme color', () => {
|
||||
let options: IDecorationRenderOptions = {
|
||||
const options: IDecorationRenderOptions = {
|
||||
backgroundColor: { id: 'editorBackground' },
|
||||
borderColor: { id: 'editorBorder' },
|
||||
};
|
||||
let colors: { [key: string]: string } = {
|
||||
|
||||
const styleSheet = new TestGlobalStyleSheet();
|
||||
const themeService = new TestThemeService(new TestColorTheme({
|
||||
editorBackground: '#FF0000'
|
||||
};
|
||||
|
||||
let styleSheet = dom.createStyleSheet();
|
||||
let themeService = new TestThemeService(new TestColorTheme(colors));
|
||||
let s = new TestCodeEditorServiceImpl(themeService, styleSheet);
|
||||
}));
|
||||
const s = new TestCodeEditorServiceImpl(themeService, styleSheet);
|
||||
s.registerDecorationType('example', options);
|
||||
let sheet = readStyleSheet(styleSheet);
|
||||
assert.equal(sheet, '.monaco-editor .ced-example-0 { background-color: rgb(255, 0, 0); border-color: transparent; box-sizing: border-box; }');
|
||||
assert.equal(readStyleSheet(styleSheet), '.monaco-editor .ced-example-0 {background-color:#ff0000;border-color:transparent;box-sizing: border-box;}');
|
||||
|
||||
colors = {
|
||||
themeService.setTheme(new TestColorTheme({
|
||||
editorBackground: '#EE0000',
|
||||
editorBorder: '#00FFFF'
|
||||
};
|
||||
themeService.setTheme(new TestColorTheme(colors));
|
||||
sheet = readStyleSheet(styleSheet);
|
||||
assert.equal(sheet, '.monaco-editor .ced-example-0 { background-color: rgb(238, 0, 0); border-color: rgb(0, 255, 255); box-sizing: border-box; }');
|
||||
}));
|
||||
assert.equal(readStyleSheet(styleSheet), '.monaco-editor .ced-example-0 {background-color:#ee0000;border-color:#00ffff;box-sizing: border-box;}');
|
||||
|
||||
s.removeDecorationType('example');
|
||||
sheet = readStyleSheet(styleSheet);
|
||||
assert.equal(sheet, '');
|
||||
|
||||
assert.equal(readStyleSheet(styleSheet), '');
|
||||
});
|
||||
|
||||
test('theme overrides', () => {
|
||||
let options: IDecorationRenderOptions = {
|
||||
const options: IDecorationRenderOptions = {
|
||||
color: { id: 'editorBackground' },
|
||||
light: {
|
||||
color: '#FF00FF'
|
||||
@@ -109,86 +120,59 @@ suite.skip('Decoration Render Options', () => { // {{SQL CARBON EDIT}} skip suit
|
||||
}
|
||||
}
|
||||
};
|
||||
let colors: { [key: string]: string } = {
|
||||
|
||||
const styleSheet = new TestGlobalStyleSheet();
|
||||
const themeService = new TestThemeService(new TestColorTheme({
|
||||
editorBackground: '#FF0000',
|
||||
infoForeground: '#444444'
|
||||
};
|
||||
|
||||
let styleSheet = dom.createStyleSheet();
|
||||
let themeService = new TestThemeService(new TestColorTheme(colors));
|
||||
let s = new TestCodeEditorServiceImpl(themeService, styleSheet);
|
||||
}));
|
||||
const s = new TestCodeEditorServiceImpl(themeService, styleSheet);
|
||||
s.registerDecorationType('example', options);
|
||||
let sheet = readStyleSheet(styleSheet);
|
||||
let expected =
|
||||
'.vs-dark.monaco-editor .ced-example-4::after, .hc-black.monaco-editor .ced-example-4::after { color: rgb(68, 68, 68) !important; }\n' +
|
||||
'.vs-dark.monaco-editor .ced-example-1, .hc-black.monaco-editor .ced-example-1 { color: rgb(0, 0, 0) !important; }\n' +
|
||||
'.vs.monaco-editor .ced-example-1 { color: rgb(255, 0, 255) !important; }\n' +
|
||||
'.monaco-editor .ced-example-1 { color: rgb(255, 0, 0) !important; }';
|
||||
assert.equal(sheet, expected);
|
||||
const expected = [
|
||||
'.vs-dark.monaco-editor .ced-example-4::after, .hc-black.monaco-editor .ced-example-4::after {color:#444444 !important;}',
|
||||
'.vs-dark.monaco-editor .ced-example-1, .hc-black.monaco-editor .ced-example-1 {color:#000000 !important;}',
|
||||
'.vs.monaco-editor .ced-example-1 {color:#FF00FF !important;}',
|
||||
'.monaco-editor .ced-example-1 {color:#ff0000 !important;}'
|
||||
].join('\n');
|
||||
assert.equal(readStyleSheet(styleSheet), expected);
|
||||
|
||||
s.removeDecorationType('example');
|
||||
sheet = readStyleSheet(styleSheet);
|
||||
assert.equal(sheet, '');
|
||||
assert.equal(readStyleSheet(styleSheet), '');
|
||||
});
|
||||
|
||||
test('css properties, gutterIconPaths', () => {
|
||||
let styleSheet = dom.createStyleSheet();
|
||||
const styleSheet = new TestGlobalStyleSheet();
|
||||
const s = new TestCodeEditorServiceImpl(themeServiceMock, styleSheet);
|
||||
|
||||
// unix file path (used as string)
|
||||
let s = new TestCodeEditorServiceImpl(themeServiceMock, styleSheet);
|
||||
s.registerDecorationType('example', { gutterIconPath: URI.file('/Users/foo/bar.png') });
|
||||
let sheet = readStyleSheet(styleSheet);//.innerHTML || styleSheet.sheet.toString();
|
||||
assert(
|
||||
sheet.indexOf('background: url(\'file:///Users/foo/bar.png\') center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background: url("file:///Users/foo/bar.png") center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background-image: url("file:///Users/foo/bar.png"); background-position: center center; background-repeat: no-repeat no-repeat;') > 0
|
||||
);
|
||||
// URI, only minimal encoding
|
||||
s.registerDecorationType('example', { gutterIconPath: URI.parse('data:image/svg+xml;base64,PHN2ZyB4b+') });
|
||||
assert(readStyleSheet(styleSheet).indexOf(`{background:url('data:image/svg+xml;base64,PHN2ZyB4b+') center center no-repeat;}`) > 0);
|
||||
s.removeDecorationType('example');
|
||||
|
||||
// windows file path (used as string)
|
||||
if (platform.isWindows) {
|
||||
s = new TestCodeEditorServiceImpl(themeServiceMock, styleSheet);
|
||||
// windows file path (used as string)
|
||||
s.registerDecorationType('example', { gutterIconPath: URI.file('c:\\files\\miles\\more.png') });
|
||||
sheet = readStyleSheet(styleSheet);
|
||||
assert(
|
||||
sheet.indexOf('background: url(\'file:///c%3A/files/miles/more.png\') center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background: url("file:///c%3A/files/miles/more.png") center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background: url("file:///c:/files/miles/more.png") center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background-image: url("file:///c:/files/miles/more.png"); background-position: center center; background-repeat: no-repeat no-repeat;') > 0
|
||||
);
|
||||
assert(readStyleSheet(styleSheet).indexOf(`{background:url('file:///c:/files/miles/more.png') center center no-repeat;}`) > 0);
|
||||
s.removeDecorationType('example');
|
||||
|
||||
// single quote must always be escaped/encoded
|
||||
s.registerDecorationType('example', { gutterIconPath: URI.file('c:\\files\\foo\\b\'ar.png') });
|
||||
assert(readStyleSheet(styleSheet).indexOf(`{background:url('file:///c:/files/foo/b%27ar.png') center center no-repeat;}`) > 0);
|
||||
s.removeDecorationType('example');
|
||||
} else {
|
||||
// unix file path (used as string)
|
||||
s.registerDecorationType('example', { gutterIconPath: URI.file('/Users/foo/bar.png') });
|
||||
assert(readStyleSheet(styleSheet).indexOf(`{background:url('file:///Users/foo/bar.png') center center no-repeat;}`) > 0);
|
||||
s.removeDecorationType('example');
|
||||
|
||||
// single quote must always be escaped/encoded
|
||||
s.registerDecorationType('example', { gutterIconPath: URI.file('/Users/foo/b\'ar.png') });
|
||||
assert(readStyleSheet(styleSheet).indexOf(`{background:url('file:///Users/foo/b%27ar.png') center center no-repeat;}`) > 0);
|
||||
s.removeDecorationType('example');
|
||||
}
|
||||
|
||||
// URI, only minimal encoding
|
||||
s = new TestCodeEditorServiceImpl(themeServiceMock, styleSheet);
|
||||
s.registerDecorationType('example', { gutterIconPath: URI.parse('data:image/svg+xml;base64,PHN2ZyB4b+') });
|
||||
sheet = readStyleSheet(styleSheet);
|
||||
assert(
|
||||
sheet.indexOf('background: url(\'data:image/svg+xml;base64,PHN2ZyB4b+\') center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background: url("data:image/svg+xml;base64,PHN2ZyB4b+") center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background-image: url("data:image/svg+xml;base64,PHN2ZyB4b+"); background-position: center center; background-repeat: no-repeat no-repeat;') > 0
|
||||
);
|
||||
s.removeDecorationType('example');
|
||||
|
||||
// single quote must always be escaped/encoded
|
||||
s = new TestCodeEditorServiceImpl(themeServiceMock, styleSheet);
|
||||
s.registerDecorationType('example', { gutterIconPath: URI.file('/Users/foo/b\'ar.png') });
|
||||
sheet = readStyleSheet(styleSheet);
|
||||
assert(
|
||||
sheet.indexOf('background: url(\'file:///Users/foo/b%27ar.png\') center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background: url("file:///Users/foo/b%27ar.png") center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background-image: url("file:///Users/foo/b%27ar.png"); background-position: center center; background-repeat: no-repeat no-repeat;') > 0
|
||||
);
|
||||
s.removeDecorationType('example');
|
||||
|
||||
s = new TestCodeEditorServiceImpl(themeServiceMock, styleSheet);
|
||||
s.registerDecorationType('example', { gutterIconPath: URI.parse('http://test/pa\'th') });
|
||||
sheet = readStyleSheet(styleSheet);
|
||||
assert(
|
||||
sheet.indexOf('background: url(\'http://test/pa%27th\') center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background: url("http://test/pa%27th") center center no-repeat;') > 0
|
||||
|| sheet.indexOf('background-image: url("http://test/pa%27th"); background-position: center center; background-repeat: no-repeat no-repeat;') > 0
|
||||
);
|
||||
assert(readStyleSheet(styleSheet).indexOf(`{background:url('http://test/pa%27th') center center no-repeat;}`) > 0);
|
||||
s.removeDecorationType('example');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -92,6 +92,7 @@ export class MenuId {
|
||||
static readonly MenubarSwitchGroupMenu = new MenuId('MenubarSwitchGroupMenu');
|
||||
static readonly MenubarTerminalMenu = new MenuId('MenubarTerminalMenu');
|
||||
static readonly MenubarViewMenu = new MenuId('MenubarViewMenu');
|
||||
static readonly MenubarWebNavigationMenu = new MenuId('MenubarWebNavigationMenu');
|
||||
static readonly OpenEditorsContext = new MenuId('OpenEditorsContext');
|
||||
static readonly ProblemsPanelContext = new MenuId('ProblemsPanelContext');
|
||||
static readonly SCMChangeContext = new MenuId('SCMChangeContext');
|
||||
@@ -127,7 +128,6 @@ export class MenuId {
|
||||
static readonly TimelineTitle = new MenuId('TimelineTitle');
|
||||
static readonly TimelineTitleContext = new MenuId('TimelineTitleContext');
|
||||
static readonly AccountsContext = new MenuId('AccountsContext');
|
||||
static readonly WebMenuActions = new MenuId('MenubarWebMenu');
|
||||
|
||||
readonly id: number;
|
||||
readonly _debugName: string;
|
||||
|
||||
@@ -265,8 +265,12 @@ export function addToValueTree(settingsTreeRoot: any, key: string, value: any, c
|
||||
curr = obj;
|
||||
}
|
||||
|
||||
if (typeof curr === 'object') {
|
||||
curr[last] = value; // workaround https://github.com/Microsoft/vscode/issues/13606
|
||||
if (typeof curr === 'object' && curr !== null) {
|
||||
try {
|
||||
curr[last] = value; // workaround https://github.com/Microsoft/vscode/issues/13606
|
||||
} catch (e) {
|
||||
conflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`);
|
||||
}
|
||||
} else {
|
||||
conflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ export class ConfigurationService extends Disposable implements IConfigurationSe
|
||||
fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
this._register(fileService.watch(settingsResource));
|
||||
this.userConfiguration = this._register(new UserSettings(this.settingsResource, undefined, fileService));
|
||||
this.configuration = new Configuration(new DefaultConfigurationModel(), new ConfigurationModel());
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
suite('ConfigurationService - Node', () => {
|
||||
|
||||
@@ -110,10 +111,10 @@ suite('ConfigurationService - Node', () => {
|
||||
|
||||
test('trigger configuration change event when file does not exist', async () => {
|
||||
const res = await testFile('config', 'config.json');
|
||||
|
||||
const service = new ConfigurationService(URI.file(res.testFile), fileService);
|
||||
const settingsFile = URI.file(res.testFile);
|
||||
const service = new ConfigurationService(settingsFile, fileService);
|
||||
await service.initialize();
|
||||
return new Promise((c, e) => {
|
||||
return new Promise(async (c, e) => {
|
||||
const disposable = Event.filter(service.onDidChangeConfiguration, e => e.source === ConfigurationTarget.USER)(async (e) => {
|
||||
disposable.dispose();
|
||||
assert.equal(service.getValue('foo'), 'bar');
|
||||
@@ -121,7 +122,7 @@ suite('ConfigurationService - Node', () => {
|
||||
await res.cleanUp();
|
||||
c();
|
||||
});
|
||||
fs.writeFileSync(res.testFile, '{ "foo": "bar" }');
|
||||
await fileService.writeFile(settingsFile, VSBuffer.fromString('{ "foo": "bar" }'));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -56,7 +56,7 @@ export interface ParsedArgs {
|
||||
'open-url'?: boolean;
|
||||
'skip-getting-started'?: boolean;
|
||||
'skip-release-notes'?: boolean;
|
||||
'sticky-quickopen'?: boolean;
|
||||
'sticky-quickinput'?: boolean;
|
||||
'disable-restore-windows'?: boolean;
|
||||
'disable-telemetry'?: boolean;
|
||||
'export-default-configuration'?: string;
|
||||
|
||||
@@ -90,7 +90,7 @@ export const OPTIONS: OptionDescriptions<Required<ParsedArgs>> = {
|
||||
'logExtensionHostCommunication': { type: 'boolean' },
|
||||
'skip-getting-started': { type: 'boolean' },
|
||||
'skip-release-notes': { type: 'boolean' },
|
||||
'sticky-quickopen': { type: 'boolean' },
|
||||
'sticky-quickinput': { type: 'boolean' },
|
||||
'disable-restore-windows': { type: 'boolean' },
|
||||
'disable-telemetry': { type: 'boolean' },
|
||||
'disable-updates': { type: 'boolean' },
|
||||
|
||||
@@ -395,6 +395,8 @@ export function toFileOperationResult(error: Error): FileOperationResult {
|
||||
return FileOperationResult.FILE_NOT_FOUND;
|
||||
case FileSystemProviderErrorCode.FileIsADirectory:
|
||||
return FileOperationResult.FILE_IS_DIRECTORY;
|
||||
case FileSystemProviderErrorCode.FileNotADirectory:
|
||||
return FileOperationResult.FILE_NOT_DIRECTORY;
|
||||
case FileSystemProviderErrorCode.NoPermissions:
|
||||
return FileOperationResult.FILE_PERMISSION_DENIED;
|
||||
case FileSystemProviderErrorCode.FileExists:
|
||||
@@ -763,6 +765,7 @@ export const enum FileOperationResult {
|
||||
FILE_TOO_LARGE,
|
||||
FILE_INVALID_PATH,
|
||||
FILE_EXCEEDS_MEMORY_LIMIT,
|
||||
FILE_NOT_DIRECTORY,
|
||||
FILE_OTHER_ERROR
|
||||
}
|
||||
|
||||
|
||||
@@ -668,6 +668,9 @@ export class DiskFileSystemProvider extends Disposable implements
|
||||
case 'EISDIR':
|
||||
code = FileSystemProviderErrorCode.FileIsADirectory;
|
||||
break;
|
||||
case 'ENOTDIR':
|
||||
code = FileSystemProviderErrorCode.FileNotADirectory;
|
||||
break;
|
||||
case 'EEXIST':
|
||||
code = FileSystemProviderErrorCode.FileExists;
|
||||
break;
|
||||
|
||||
@@ -1409,6 +1409,24 @@ suite('Disk File Service', function () {
|
||||
assert.equal(error!.fileOperationResult, FileOperationResult.FILE_IS_DIRECTORY);
|
||||
});
|
||||
|
||||
test('readFile - FILE_NOT_DIRECTORY', async () => {
|
||||
if (isWindows) {
|
||||
return; // error code does not seem to be supported on windows
|
||||
}
|
||||
|
||||
const resource = URI.file(join(testDir, 'lorem.txt', 'file.txt'));
|
||||
|
||||
let error: FileOperationError | undefined = undefined;
|
||||
try {
|
||||
await service.readFile(resource);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error);
|
||||
assert.equal(error!.fileOperationResult, FileOperationResult.FILE_NOT_DIRECTORY);
|
||||
});
|
||||
|
||||
test('readFile - FILE_NOT_FOUND', async () => {
|
||||
const resource = URI.file(join(testDir, '404.html'));
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ if (isWeb) {
|
||||
// Running out of sources
|
||||
if (Object.keys(product).length === 0) {
|
||||
assign(product, {
|
||||
version: '1.16.0-dev',
|
||||
vscodeVersion: '1.43.0-dev',
|
||||
version: '1.17.0-dev',
|
||||
vscodeVersion: '1.44.0-dev',
|
||||
nameLong: 'Azure Data Studio Web Dev',
|
||||
nameShort: 'Azure Data Studio Web Dev',
|
||||
urlProtocol: 'azuredatastudio-oss'
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { IQuickNavigateConfiguration, IAutoFocus } from 'vs/base/parts/quickopen/common/quickOpen';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export interface IShowOptions {
|
||||
quickNavigateConfiguration?: IQuickNavigateConfiguration;
|
||||
inputSelection?: { start: number; end: number; };
|
||||
autoFocus?: IAutoFocus;
|
||||
}
|
||||
|
||||
export const IQuickOpenService = createDecorator<IQuickOpenService>('quickOpenService');
|
||||
|
||||
export interface IQuickOpenService {
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
/**
|
||||
* Asks the container to show the quick open control with the optional prefix set. If the optional parameter
|
||||
* is set for quick navigation mode, the quick open control will quickly navigate when the quick navigate
|
||||
* key is pressed and will run the selection after the ctrl key is released.
|
||||
*
|
||||
* The returned promise completes when quick open is closing.
|
||||
*/
|
||||
show(prefix?: string, options?: IShowOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Allows to navigate from the outside in an opened picker.
|
||||
*/
|
||||
navigate(next: boolean, quickNavigate?: IQuickNavigateConfiguration): void;
|
||||
|
||||
/**
|
||||
* Accepts the selected value in quick open if visible.
|
||||
*/
|
||||
accept(): void;
|
||||
|
||||
/**
|
||||
* Focus into the quick open if visible.
|
||||
*/
|
||||
focus(): void;
|
||||
|
||||
/**
|
||||
* Closes any opened quick open.
|
||||
*/
|
||||
close(): void;
|
||||
|
||||
/**
|
||||
* Allows to register on the event that quick open is showing
|
||||
*/
|
||||
onShow: Event<void>;
|
||||
|
||||
/**
|
||||
* Allows to register on the event that quick open is hiding
|
||||
*/
|
||||
onHide: Event<void>;
|
||||
}
|
||||
@@ -115,15 +115,27 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
|
||||
const picksToken = picksCts.token;
|
||||
const providedPicks = this.getPicks(picker.value.substr(this.prefix.length).trim(), picksDisposables, picksToken);
|
||||
|
||||
function applyPicks(picks: Picks<T>): void {
|
||||
function applyPicks(picks: Picks<T>, skipEmpty?: boolean): boolean {
|
||||
let items: ReadonlyArray<Pick<T>>;
|
||||
let activeItem: T | undefined = undefined;
|
||||
|
||||
if (isPicksWithActive(picks)) {
|
||||
picker.items = picks.items;
|
||||
if (picks.active) {
|
||||
picker.activeItems = [picks.active];
|
||||
}
|
||||
items = picks.items;
|
||||
activeItem = picks.active;
|
||||
} else {
|
||||
picker.items = picks;
|
||||
items = picks;
|
||||
}
|
||||
|
||||
if (items.length === 0 && skipEmpty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
picker.items = items;
|
||||
if (activeItem) {
|
||||
picker.activeItems = [activeItem];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// No Picks
|
||||
@@ -133,8 +145,8 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
|
||||
|
||||
// Fast and Slow Picks
|
||||
else if (isFastAndSlowPicks(providedPicks)) {
|
||||
let fastPicksHandlerDone = false;
|
||||
let slowPicksHandlerDone = false;
|
||||
let fastPicksApplied = false;
|
||||
let slowPicksApplied = false;
|
||||
|
||||
await Promise.all([
|
||||
|
||||
@@ -143,17 +155,13 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
|
||||
// If the slow picks are faster, we reduce the flicker by
|
||||
// only setting the items once.
|
||||
(async () => {
|
||||
try {
|
||||
await timeout(PickerQuickAccessProvider.FAST_PICKS_RACE_DELAY);
|
||||
if (picksToken.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
await timeout(PickerQuickAccessProvider.FAST_PICKS_RACE_DELAY);
|
||||
if (picksToken.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!slowPicksHandlerDone) {
|
||||
applyPicks(providedPicks.picks);
|
||||
}
|
||||
} finally {
|
||||
fastPicksHandlerDone = true;
|
||||
if (!slowPicksApplied) {
|
||||
fastPicksApplied = applyPicks(providedPicks.picks, true /* skip over empty to reduce flicker */);
|
||||
}
|
||||
})(),
|
||||
|
||||
@@ -186,7 +194,7 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
|
||||
additionalPicks = awaitedAdditionalPicks;
|
||||
}
|
||||
|
||||
if (additionalPicks.length > 0 || !fastPicksHandlerDone) {
|
||||
if (additionalPicks.length > 0 || !fastPicksApplied) {
|
||||
applyPicks({
|
||||
items: [...picks, ...additionalPicks],
|
||||
active: activePick as T || additionalActivePick as T // {{SQL CARBON EDIT}} strict-null-checks
|
||||
@@ -197,7 +205,7 @@ export abstract class PickerQuickAccessProvider<T extends IPickerQuickAccessItem
|
||||
picker.busy = false;
|
||||
}
|
||||
|
||||
slowPicksHandlerDone = true;
|
||||
slowPicksApplied = true;
|
||||
}
|
||||
})()
|
||||
]);
|
||||
|
||||
@@ -52,7 +52,7 @@ export class QuickInputService extends Themable implements IQuickInputService {
|
||||
|
||||
constructor(
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IContextKeyService protected readonly contextKeyService: IContextKeyService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
|
||||
@ILayoutService protected readonly layoutService: ILayoutService
|
||||
@@ -166,10 +166,6 @@ export class QuickInputService extends Themable implements IQuickInputService {
|
||||
return this.controller.cancel();
|
||||
}
|
||||
|
||||
hide(focusLost?: boolean): void {
|
||||
return this.controller.hide(focusLost);
|
||||
}
|
||||
|
||||
protected updateStyles() {
|
||||
this.controller.applyStyles(this.computeStyles());
|
||||
}
|
||||
|
||||
@@ -94,7 +94,4 @@ export interface IQuickInputService {
|
||||
* Cancels quick input and closes it.
|
||||
*/
|
||||
cancel(): Promise<void>;
|
||||
|
||||
// TODO@Ben remove once quick open is gone
|
||||
hide(focusLost?: boolean): void;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IWorkspaceStorageChangeEvent, IStorageService, StorageScope, IWillSaveStateEvent, WillSaveStateReason, logStorage } from 'vs/platform/storage/common/storage';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces';
|
||||
@@ -189,8 +189,8 @@ export class BrowserStorageService extends Disposable implements IStorageService
|
||||
|
||||
export class FileStorageDatabase extends Disposable implements IStorageDatabase {
|
||||
|
||||
private readonly _onDidChangeItemsExternal: Emitter<IStorageItemsChangeEvent> = this._register(new Emitter<IStorageItemsChangeEvent>());
|
||||
readonly onDidChangeItemsExternal: Event<IStorageItemsChangeEvent> = this._onDidChangeItemsExternal.event;
|
||||
private readonly _onDidChangeItemsExternal = this._register(new Emitter<IStorageItemsChangeEvent>());
|
||||
readonly onDidChangeItemsExternal = this._onDidChangeItemsExternal.event;
|
||||
|
||||
private cache: Map<string, string> | undefined;
|
||||
|
||||
|
||||
@@ -125,8 +125,8 @@ export const enum StorageScope {
|
||||
}
|
||||
|
||||
export interface IWorkspaceStorageChangeEvent {
|
||||
key: string;
|
||||
scope: StorageScope;
|
||||
readonly key: string;
|
||||
readonly scope: StorageScope;
|
||||
}
|
||||
|
||||
export class InMemoryStorageService extends Disposable implements IStorageService {
|
||||
@@ -139,8 +139,8 @@ export class InMemoryStorageService extends Disposable implements IStorageServic
|
||||
protected readonly _onWillSaveState = this._register(new Emitter<IWillSaveStateEvent>());
|
||||
readonly onWillSaveState = this._onWillSaveState.event;
|
||||
|
||||
private globalCache: Map<string, string> = new Map<string, string>();
|
||||
private workspaceCache: Map<string, string> = new Map<string, string>();
|
||||
private readonly globalCache = new Map<string, string>();
|
||||
private readonly workspaceCache = new Map<string, string>();
|
||||
|
||||
private getCache(scope: StorageScope): Map<string, string> {
|
||||
return scope === StorageScope.GLOBAL ? this.globalCache : this.workspaceCache;
|
||||
|
||||
@@ -23,8 +23,8 @@ interface ISerializableUpdateRequest {
|
||||
}
|
||||
|
||||
interface ISerializableItemsChangeEvent {
|
||||
changed?: Item[];
|
||||
deleted?: Key[];
|
||||
readonly changed?: Item[];
|
||||
readonly deleted?: Key[];
|
||||
}
|
||||
|
||||
export class GlobalStorageDatabaseChannel extends Disposable implements IServerChannel {
|
||||
@@ -34,15 +34,13 @@ export class GlobalStorageDatabaseChannel extends Disposable implements IServerC
|
||||
private readonly _onDidChangeItems = this._register(new Emitter<ISerializableItemsChangeEvent>());
|
||||
readonly onDidChangeItems = this._onDidChangeItems.event;
|
||||
|
||||
private whenReady: Promise<void>;
|
||||
private readonly whenReady = this.init();
|
||||
|
||||
constructor(
|
||||
private logService: ILogService,
|
||||
private storageMainService: IStorageMainService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.whenReady = this.init();
|
||||
}
|
||||
|
||||
private async init(): Promise<void> {
|
||||
@@ -166,8 +164,8 @@ export class GlobalStorageDatabaseChannelClient extends Disposable implements IS
|
||||
|
||||
_serviceBrand: undefined;
|
||||
|
||||
private readonly _onDidChangeItemsExternal: Emitter<IStorageItemsChangeEvent> = this._register(new Emitter<IStorageItemsChangeEvent>());
|
||||
readonly onDidChangeItemsExternal: Event<IStorageItemsChangeEvent> = this._onDidChangeItemsExternal.event;
|
||||
private readonly _onDidChangeItemsExternal = this._register(new Emitter<IStorageItemsChangeEvent>());
|
||||
readonly onDidChangeItemsExternal = this._onDidChangeItemsExternal.event;
|
||||
|
||||
private onDidChangeItemsOnMainListener: IDisposable | undefined;
|
||||
|
||||
|
||||
@@ -48,6 +48,11 @@ export class NativeStorageService extends Disposable implements IStorageService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
|
||||
// Global Storage change events
|
||||
this._register(this.globalStorage.onDidChangeStorage(key => this.handleDidChangeStorage(key, StorageScope.GLOBAL)));
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ export function attachFindReplaceInputBoxStyler(widget: IThemable, themeService:
|
||||
} as IInputBoxStyleOverrides, widget);
|
||||
}
|
||||
|
||||
export interface IQuickOpenStyleOverrides extends IListStyleOverrides, IInputBoxStyleOverrides, IProgressBarStyleOverrides {
|
||||
export interface IQuickInputStyleOverrides extends IListStyleOverrides, IInputBoxStyleOverrides, IProgressBarStyleOverrides {
|
||||
foreground?: ColorIdentifier;
|
||||
background?: ColorIdentifier;
|
||||
borderColor?: ColorIdentifier;
|
||||
@@ -163,7 +163,7 @@ export interface IQuickOpenStyleOverrides extends IListStyleOverrides, IInputBox
|
||||
pickerGroupBorder?: ColorIdentifier;
|
||||
}
|
||||
|
||||
export function attachQuickOpenStyler(widget: IThemable, themeService: IThemeService, style?: IQuickOpenStyleOverrides): IDisposable {
|
||||
export function attachQuickInputStyler(widget: IThemable, themeService: IThemeService, style?: IQuickInputStyleOverrides): IDisposable {
|
||||
return attachStyler(themeService, {
|
||||
foreground: (style && style.foreground) || foreground,
|
||||
background: (style && style.background) || editorBackground,
|
||||
@@ -199,7 +199,7 @@ export function attachQuickOpenStyler(widget: IThemable, themeService: IThemeSer
|
||||
listFocusOutline: (style && style.listFocusOutline) || activeContrastBorder,
|
||||
listSelectionOutline: (style && style.listSelectionOutline) || activeContrastBorder,
|
||||
listHoverOutline: (style && style.listHoverOutline) || activeContrastBorder
|
||||
} as IQuickOpenStyleOverrides, widget);
|
||||
} as IQuickInputStyleOverrides, widget);
|
||||
}
|
||||
|
||||
export interface IListStyleOverrides extends IStyleOverrides {
|
||||
|
||||
@@ -106,7 +106,7 @@ export interface IColorTheme {
|
||||
/**
|
||||
* Returns the token style for a given classification. The result uses the <code>MetadataConsts</code> format
|
||||
*/
|
||||
getTokenStyleMetadata(type: string, modifiers: string[]): ITokenStyle | undefined;
|
||||
getTokenStyleMetadata(type: string, modifiers: string[], modelLanguage: string): ITokenStyle | undefined;
|
||||
|
||||
/**
|
||||
* List of all colors used with tokens. <code>getTokenStyleMetadata</code> references the colors by index into this list.
|
||||
|
||||
@@ -13,15 +13,21 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';
|
||||
|
||||
export const TOKEN_TYPE_WILDCARD = '*';
|
||||
export const TOKEN_CLASSIFIER_LANGUAGE_SEPARATOR = ':';
|
||||
export const CLASSIFIER_MODIFIER_SEPARATOR = '.';
|
||||
|
||||
// qualified string [type|*](.modifier)*
|
||||
// qualified string [type|*](.modifier)*(/language)!
|
||||
export type TokenClassificationString = string;
|
||||
|
||||
export const typeAndModifierIdPattern = '^\\w+[-_\\w+]*$';
|
||||
export const idPattern = '\\w+[-_\\w+]*';
|
||||
export const typeAndModifierIdPattern = `^${idPattern}$`;
|
||||
|
||||
export const selectorPattern = `^(${idPattern}|\\*)(\\${CLASSIFIER_MODIFIER_SEPARATOR}${idPattern})*(\\${TOKEN_CLASSIFIER_LANGUAGE_SEPARATOR}${idPattern})?$`;
|
||||
|
||||
export const fontStylePattern = '^(\\s*(-?italic|-?bold|-?underline))*\\s*$';
|
||||
|
||||
export interface TokenSelector {
|
||||
match(type: string, modifiers: string[]): number;
|
||||
match(type: string, modifiers: string[], language: string): number;
|
||||
readonly selectorString: string;
|
||||
}
|
||||
|
||||
@@ -52,7 +58,36 @@ export class TokenStyle implements Readonly<TokenStyleData> {
|
||||
}
|
||||
|
||||
export namespace TokenStyle {
|
||||
export function fromData(data: { foreground?: Color, bold?: boolean, underline?: boolean, italic?: boolean }) {
|
||||
export function toJSONObject(style: TokenStyle): any {
|
||||
return {
|
||||
_foreground: style.foreground === undefined ? null : Color.Format.CSS.formatHexA(style.foreground, true),
|
||||
_bold: style.bold === undefined ? null : style.bold,
|
||||
_underline: style.underline === undefined ? null : style.underline,
|
||||
_italic: style.italic === undefined ? null : style.italic,
|
||||
};
|
||||
}
|
||||
export function fromJSONObject(obj: any): TokenStyle | undefined {
|
||||
if (obj) {
|
||||
const boolOrUndef = (b: any) => (typeof b === 'boolean') ? b : undefined;
|
||||
const colorOrUndef = (s: any) => (typeof s === 'string') ? Color.fromHex(s) : undefined;
|
||||
return new TokenStyle(colorOrUndef(obj._foreground), boolOrUndef(obj._bold), boolOrUndef(obj._underline), boolOrUndef(obj._italic));
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
export function equals(s1: any, s2: any): boolean {
|
||||
if (s1 === s2) {
|
||||
return true;
|
||||
}
|
||||
return s1 !== undefined && s2 !== undefined
|
||||
&& (s1.foreground instanceof Color ? s1.foreground.equals(s2.foreground) : s2.foreground === undefined)
|
||||
&& s1.bold === s2.bold
|
||||
&& s1.underline === s2.underline
|
||||
&& s1.italic === s2.italic;
|
||||
}
|
||||
export function is(s: any): s is TokenStyle {
|
||||
return s instanceof TokenStyle;
|
||||
}
|
||||
export function fromData(data: { foreground?: Color, bold?: boolean, underline?: boolean, italic?: boolean }): TokenStyle {
|
||||
return new TokenStyle(data.foreground, data.bold, data.underline, data.italic);
|
||||
}
|
||||
export function fromSettings(foreground: string | undefined, fontStyle: string | undefined): TokenStyle {
|
||||
@@ -105,6 +140,38 @@ export interface TokenStylingRule {
|
||||
selector: TokenSelector;
|
||||
}
|
||||
|
||||
export namespace TokenStylingRule {
|
||||
export function fromJSONObject(registry: ITokenClassificationRegistry, o: any): TokenStylingRule | undefined {
|
||||
if (o && typeof o._selector === 'string' && o._style) {
|
||||
const style = TokenStyle.fromJSONObject(o._style);
|
||||
if (style) {
|
||||
try {
|
||||
return { selector: registry.parseTokenSelector(o._selector), style };
|
||||
} catch (_ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
export function toJSONObject(rule: TokenStylingRule): any {
|
||||
return {
|
||||
_selector: rule.selector.selectorString,
|
||||
_style: TokenStyle.toJSONObject(rule.style)
|
||||
};
|
||||
}
|
||||
export function equals(r1: TokenStylingRule | undefined, r2: TokenStylingRule | undefined) {
|
||||
if (r1 === r2) {
|
||||
return true;
|
||||
}
|
||||
return r1 !== undefined && r2 !== undefined
|
||||
&& r1.selector && r2.selector && r1.selector.selectorString === r2.selector.selectorString
|
||||
&& TokenStyle.equals(r1.style, r2.style);
|
||||
}
|
||||
export function is(r: any): r is TokenStylingRule {
|
||||
return r && r.selector && typeof r.selector.selectorString === 'string' && TokenStyle.is(r.style);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A TokenStyle Value is either a token style literal, or a TokenClassificationString
|
||||
*/
|
||||
@@ -269,9 +336,9 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry {
|
||||
}
|
||||
|
||||
public parseTokenSelector(selectorString: string): TokenSelector {
|
||||
const [selectorType, ...selectorModifiers] = selectorString.split('.');
|
||||
const selector = parseClassifierString(selectorString);
|
||||
|
||||
if (!selectorType) {
|
||||
if (!selector.type) {
|
||||
return {
|
||||
match: () => -1,
|
||||
selectorString
|
||||
@@ -279,23 +346,29 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry {
|
||||
}
|
||||
|
||||
return {
|
||||
match: (type: string, modifiers: string[]) => {
|
||||
match: (type: string, modifiers: string[], language: string) => {
|
||||
let score = 0;
|
||||
if (selectorType !== TOKEN_TYPE_WILDCARD) {
|
||||
if (selector.language !== undefined) {
|
||||
if (selector.language !== language) {
|
||||
return -1;
|
||||
}
|
||||
score += 100;
|
||||
}
|
||||
if (selector.type !== TOKEN_TYPE_WILDCARD) {
|
||||
const hierarchy = this.getTypeHierarchy(type);
|
||||
const level = hierarchy.indexOf(selectorType);
|
||||
const level = hierarchy.indexOf(selector.type);
|
||||
if (level === -1) {
|
||||
return -1;
|
||||
}
|
||||
score = 100 - level;
|
||||
score += (100 - level);
|
||||
}
|
||||
// all selector modifiers must be present
|
||||
for (const selectorModifier of selectorModifiers) {
|
||||
for (const selectorModifier of selector.modifiers) {
|
||||
if (modifiers.indexOf(selectorModifier) === -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return score + selectorModifiers.length * 100;
|
||||
return score + selector.modifiers.length * 100;
|
||||
},
|
||||
selectorString
|
||||
};
|
||||
@@ -366,15 +439,41 @@ class TokenClassificationRegistry implements ITokenClassificationRegistry {
|
||||
|
||||
}
|
||||
|
||||
const CHAR_LANGUAGE = TOKEN_CLASSIFIER_LANGUAGE_SEPARATOR.charCodeAt(0);
|
||||
const CHAR_MODIFIER = CLASSIFIER_MODIFIER_SEPARATOR.charCodeAt(0);
|
||||
|
||||
const tokenClassificationRegistry = new TokenClassificationRegistry();
|
||||
export function parseClassifierString(s: string): { type: string, modifiers: string[], language: string | undefined; } {
|
||||
let k = s.length;
|
||||
let language: string | undefined = undefined;
|
||||
const modifiers = [];
|
||||
|
||||
for (let i = k - 1; i >= 0; i--) {
|
||||
const ch = s.charCodeAt(i);
|
||||
if (ch === CHAR_LANGUAGE || ch === CHAR_MODIFIER) {
|
||||
const segment = s.substring(i + 1, k);
|
||||
k = i;
|
||||
if (ch === CHAR_LANGUAGE) {
|
||||
language = segment;
|
||||
} else {
|
||||
modifiers.push(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
const type = s.substring(0, k);
|
||||
return { type, modifiers, language };
|
||||
}
|
||||
|
||||
|
||||
let tokenClassificationRegistry = createDefaultTokenClassificationRegistry();
|
||||
platform.Registry.add(Extensions.TokenClassificationContribution, tokenClassificationRegistry);
|
||||
|
||||
registerDefaultClassifications();
|
||||
|
||||
function registerDefaultClassifications(): void {
|
||||
function createDefaultTokenClassificationRegistry(): TokenClassificationRegistry {
|
||||
|
||||
const registry = new TokenClassificationRegistry();
|
||||
|
||||
function registerTokenType(id: string, description: string, scopesToProbe: ProbeScope[] = [], superType?: string, deprecationMessage?: string): string {
|
||||
tokenClassificationRegistry.registerTokenType(id, description, superType, deprecationMessage);
|
||||
registry.registerTokenType(id, description, superType, deprecationMessage);
|
||||
if (scopesToProbe) {
|
||||
registerTokenStyleDefault(id, scopesToProbe);
|
||||
}
|
||||
@@ -383,8 +482,8 @@ function registerDefaultClassifications(): void {
|
||||
|
||||
function registerTokenStyleDefault(selectorString: string, scopesToProbe: ProbeScope[]) {
|
||||
try {
|
||||
const selector = tokenClassificationRegistry.parseTokenSelector(selectorString);
|
||||
tokenClassificationRegistry.registerTokenStyleDefault(selector, { scopesToProbe });
|
||||
const selector = registry.parseTokenSelector(selectorString);
|
||||
registry.registerTokenStyleDefault(selector, { scopesToProbe });
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
@@ -422,18 +521,28 @@ function registerDefaultClassifications(): void {
|
||||
|
||||
// default token modifiers
|
||||
|
||||
tokenClassificationRegistry.registerTokenModifier('declaration', nls.localize('declaration', "Style for all symbol declarations."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('documentation', nls.localize('documentation', "Style to use for references in documentation."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('static', nls.localize('static', "Style to use for symbols that are static."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('abstract', nls.localize('abstract', "Style to use for symbols that are abstract."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('deprecated', nls.localize('deprecated', "Style to use for symbols that are deprecated."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('modification', nls.localize('modification', "Style to use for write accesses."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('async', nls.localize('async', "Style to use for symbols that are async."), undefined);
|
||||
tokenClassificationRegistry.registerTokenModifier('readonly', nls.localize('readonly', "Style to use for symbols that are readonly."), undefined);
|
||||
registry.registerTokenModifier('declaration', nls.localize('declaration', "Style for all symbol declarations."), undefined);
|
||||
registry.registerTokenModifier('documentation', nls.localize('documentation', "Style to use for references in documentation."), undefined);
|
||||
registry.registerTokenModifier('static', nls.localize('static', "Style to use for symbols that are static."), undefined);
|
||||
registry.registerTokenModifier('abstract', nls.localize('abstract', "Style to use for symbols that are abstract."), undefined);
|
||||
registry.registerTokenModifier('deprecated', nls.localize('deprecated', "Style to use for symbols that are deprecated."), undefined);
|
||||
registry.registerTokenModifier('modification', nls.localize('modification', "Style to use for write accesses."), undefined);
|
||||
registry.registerTokenModifier('async', nls.localize('async', "Style to use for symbols that are async."), undefined);
|
||||
registry.registerTokenModifier('readonly', nls.localize('readonly', "Style to use for symbols that are readonly."), undefined);
|
||||
|
||||
|
||||
registerTokenStyleDefault('variable.readonly', [['variable.other.constant']]);
|
||||
registerTokenStyleDefault('property.readonly', [['variable.other.constant.property']]);
|
||||
registerTokenStyleDefault('type.defaultLibrary', [['support.type']]);
|
||||
registerTokenStyleDefault('class.defaultLibrary', [['support.class']]);
|
||||
registerTokenStyleDefault('interface.defaultLibrary', [['support.class']]);
|
||||
registerTokenStyleDefault('variable.defaultLibrary', [['support.variable'], ['support.other.variable']]);
|
||||
registerTokenStyleDefault('variable.defaultLibrary.readonly', [['support.constant']]);
|
||||
registerTokenStyleDefault('property.defaultLibrary', [['support.variable.property']]);
|
||||
registerTokenStyleDefault('property.defaultLibrary.readonly', [['support.constant.property']]);
|
||||
registerTokenStyleDefault('function.defaultLibrary', [['support.function']]);
|
||||
registerTokenStyleDefault('member.defaultLibrary', [['support.function']]);
|
||||
return registry;
|
||||
}
|
||||
|
||||
export function getTokenClassificationRegistry(): ITokenClassificationRegistry {
|
||||
|
||||
@@ -24,7 +24,7 @@ export class TestColorTheme implements IColorTheme {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
getTokenStyleMetadata(type: string, modifiers: string[]): ITokenStyle | undefined {
|
||||
getTokenStyleMetadata(type: string, modifiers: string[], modelLanguage: string): ITokenStyle | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+166
-18
@@ -1093,7 +1093,7 @@ declare module 'vscode' {
|
||||
readonly dimensions: TerminalDimensions;
|
||||
}
|
||||
|
||||
namespace window {
|
||||
export namespace window {
|
||||
/**
|
||||
* An event which fires when the [dimensions](#Terminal.dimensions) of the terminal change.
|
||||
*/
|
||||
@@ -1114,19 +1114,125 @@ declare module 'vscode' {
|
||||
//#region Terminal link handlers https://github.com/microsoft/vscode/issues/91606
|
||||
|
||||
export namespace window {
|
||||
/**
|
||||
* Register a [TerminalLinkHandler](#TerminalLinkHandler) that can be used to intercept and
|
||||
* handle links that are activated within terminals.
|
||||
*/
|
||||
export function registerTerminalLinkHandler(handler: TerminalLinkHandler): Disposable;
|
||||
}
|
||||
|
||||
export interface TerminalLinkHandler {
|
||||
/**
|
||||
* @return true when the link was handled (and should not be considered by
|
||||
* other providers including the default), false when the link was not handled.
|
||||
* Handles a link that is activated within the terminal.
|
||||
*
|
||||
* @return Whether the link was handled, the link was handled this link will not be
|
||||
* considered by any other extension or by the default built-in link handler.
|
||||
*/
|
||||
handleLink(terminal: Terminal, link: string): ProviderResult<boolean>;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Contribute to terminal environment https://github.com/microsoft/vscode/issues/46696
|
||||
|
||||
export enum EnvironmentVariableMutatorType {
|
||||
/**
|
||||
* Replace the variable's existing value.
|
||||
*/
|
||||
Replace = 1,
|
||||
/**
|
||||
* Append to the end of the variable's existing value.
|
||||
*/
|
||||
Append = 2,
|
||||
/**
|
||||
* Prepend to the start of the variable's existing value.
|
||||
*/
|
||||
Prepend = 3
|
||||
}
|
||||
|
||||
export interface EnvironmentVariableMutator {
|
||||
/**
|
||||
* The type of mutation that will occur to the variable.
|
||||
*/
|
||||
readonly type: EnvironmentVariableMutatorType;
|
||||
|
||||
/**
|
||||
* The value to use for the variable.
|
||||
*/
|
||||
readonly value: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of mutations that an extension can apply to a process environment.
|
||||
*/
|
||||
export interface EnvironmentVariableCollection {
|
||||
/**
|
||||
* Replace an environment variable with a value.
|
||||
*
|
||||
* Note that an extension can only make a single change to any one variable, so this will
|
||||
* overwrite any previous calls to replace, append or prepend.
|
||||
*/
|
||||
replace(variable: string, value: string): void;
|
||||
|
||||
/**
|
||||
* Append a value to an environment variable.
|
||||
*
|
||||
* Note that an extension can only make a single change to any one variable, so this will
|
||||
* overwrite any previous calls to replace, append or prepend.
|
||||
*/
|
||||
append(variable: string, value: string): void;
|
||||
|
||||
/**
|
||||
* Prepend a value to an environment variable.
|
||||
*
|
||||
* Note that an extension can only make a single change to any one variable, so this will
|
||||
* overwrite any previous calls to replace, append or prepend.
|
||||
*/
|
||||
prepend(variable: string, value: string): void;
|
||||
|
||||
/**
|
||||
* Gets the mutator that this collection applies to a variable, if any.
|
||||
*/
|
||||
get(variable: string): EnvironmentVariableMutator | undefined;
|
||||
|
||||
/**
|
||||
* Iterate over each mutator in this collection.
|
||||
*/
|
||||
forEach(callback: (variable: string, mutator: EnvironmentVariableMutator, collection: EnvironmentVariableCollection) => any, thisArg?: any): void;
|
||||
|
||||
/**
|
||||
* Deletes this collection's mutator for a variable.
|
||||
*/
|
||||
delete(variable: string): void;
|
||||
|
||||
/**
|
||||
* Clears all mutators from this collection.
|
||||
*/
|
||||
clear(): void;
|
||||
|
||||
/**
|
||||
* Disposes the collection, if the collection was persisted it will no longer be retained
|
||||
* across reloads.
|
||||
*/
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
export namespace window {
|
||||
/**
|
||||
* Creates or returns the extension's environment variable collection for this workspace,
|
||||
* enabling changes to be applied to terminal environment variables.
|
||||
*
|
||||
* @param persistent Whether the collection should be cached for the workspace and applied
|
||||
* to the terminal across window reloads. When true the collection will be active
|
||||
* immediately such when the window reloads. Additionally, this API will return the cached
|
||||
* version if it exists. The collection will be invalidated when the extension is
|
||||
* uninstalled or when the collection is disposed. Defaults to false.
|
||||
*/
|
||||
export function getEnvironmentVariableCollection(persistent?: boolean): EnvironmentVariableCollection;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Joh -> exclusive document filters
|
||||
|
||||
export interface DocumentFilter {
|
||||
@@ -1449,9 +1555,20 @@ declare module 'vscode' {
|
||||
readonly uri: Uri;
|
||||
|
||||
/**
|
||||
* Event fired when there are no more references to the `CustomDocument`.
|
||||
* Is this document representing an untitled file which has never been saved yet.
|
||||
*/
|
||||
readonly onDidDispose: Event<void>;
|
||||
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.
|
||||
@@ -1465,6 +1582,17 @@ declare module 'vscode' {
|
||||
* or in front of the last entry in `appliedEdits` if the user saves and then hits undo.
|
||||
*/
|
||||
readonly savedEdits: ReadonlyArray<EditType>;
|
||||
|
||||
/**
|
||||
* `true` if the document has been closed. A closed document isn't synchronized anymore
|
||||
* and won't be re-used when the same resource is opened again.
|
||||
*/
|
||||
readonly isClosed: boolean;
|
||||
|
||||
/**
|
||||
* Event fired when there are no more references to the `CustomDocument`.
|
||||
*/
|
||||
readonly onDidDispose: Event<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1674,25 +1802,27 @@ declare module 'vscode' {
|
||||
/**
|
||||
* Controls if the content of a cell is editable or not.
|
||||
*/
|
||||
editable: boolean;
|
||||
editable?: boolean;
|
||||
|
||||
/**
|
||||
* Controls if the cell is executable.
|
||||
* This metadata is ignored for markdown cell.
|
||||
*/
|
||||
runnable: boolean;
|
||||
runnable?: boolean;
|
||||
|
||||
/**
|
||||
* Execution order information of the cell
|
||||
*/
|
||||
executionOrder?: number;
|
||||
}
|
||||
|
||||
export interface NotebookCell {
|
||||
readonly uri: Uri;
|
||||
handle: number;
|
||||
readonly cellKind: CellKind;
|
||||
readonly source: string;
|
||||
language: string;
|
||||
cellKind: CellKind;
|
||||
outputs: CellOutput[];
|
||||
getContent(): string;
|
||||
metadata?: NotebookCellMetadata;
|
||||
metadata: NotebookCellMetadata;
|
||||
}
|
||||
|
||||
export interface NotebookDocumentMetadata {
|
||||
@@ -1713,18 +1843,24 @@ declare module 'vscode' {
|
||||
* Default to true.
|
||||
*/
|
||||
cellRunnable: boolean;
|
||||
|
||||
}
|
||||
|
||||
export interface NotebookDocument {
|
||||
readonly uri: Uri;
|
||||
readonly fileName: string;
|
||||
readonly isDirty: boolean;
|
||||
readonly cells: NotebookCell[];
|
||||
languages: string[];
|
||||
cells: NotebookCell[];
|
||||
displayOrder?: GlobPattern[];
|
||||
metadata?: NotebookDocumentMetadata;
|
||||
}
|
||||
|
||||
export interface NotebookEditorCellEdit {
|
||||
insert(index: number, content: string, language: string, type: CellKind, outputs: CellOutput[], metadata: NotebookCellMetadata | undefined): void;
|
||||
delete(index: number): void;
|
||||
}
|
||||
|
||||
export interface NotebookEditor {
|
||||
readonly document: NotebookDocument;
|
||||
viewColumn?: ViewColumn;
|
||||
@@ -1741,10 +1877,7 @@ declare module 'vscode' {
|
||||
*/
|
||||
postMessage(message: any): Thenable<boolean>;
|
||||
|
||||
/**
|
||||
* Create a notebook cell. The cell is not inserted into current document when created. Extensions should insert the cell into the document by [TextDocument.cells](#TextDocument.cells)
|
||||
*/
|
||||
createCell(content: string, language: string, type: CellKind, outputs: CellOutput[], metadata: NotebookCellMetadata | undefined): NotebookCell;
|
||||
edit(callback: (editBuilder: NotebookEditorCellEdit) => void): Thenable<boolean>;
|
||||
}
|
||||
|
||||
export interface NotebookProvider {
|
||||
@@ -1764,11 +1897,24 @@ declare module 'vscode' {
|
||||
* @returns HTML fragment. We can probably return `CellOutput` instead of string ?
|
||||
*
|
||||
*/
|
||||
render(document: NotebookDocument, cell: NotebookCell, output: CellOutput, mimeType: string): string;
|
||||
render(document: NotebookDocument, output: CellOutput, mimeType: string): string;
|
||||
preloads?: Uri[];
|
||||
}
|
||||
|
||||
namespace window {
|
||||
export interface NotebookDocumentChangeEvent {
|
||||
|
||||
/**
|
||||
* The affected document.
|
||||
*/
|
||||
readonly document: NotebookDocument;
|
||||
|
||||
/**
|
||||
* An array of content changes.
|
||||
*/
|
||||
// readonly contentChanges: ReadonlyArray<TextDocumentContentChangeEvent>;
|
||||
}
|
||||
|
||||
export namespace notebook {
|
||||
export function registerNotebookProvider(
|
||||
notebookType: string,
|
||||
provider: NotebookProvider
|
||||
@@ -1777,6 +1923,8 @@ declare module 'vscode' {
|
||||
export function registerNotebookOutputRenderer(type: string, outputSelector: NotebookOutputSelector, renderer: NotebookOutputRenderer): Disposable;
|
||||
|
||||
export let activeNotebookDocument: NotebookDocument | undefined;
|
||||
|
||||
// export const onDidChangeNotebookDocument: Event<NotebookDocumentChangeEvent>;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -32,6 +32,23 @@ const BUILT_IN_AUTH_DEPENDENTS: AuthDependent[] = [
|
||||
}
|
||||
];
|
||||
|
||||
interface AllowedExtension {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
function readAllowedExtensions(storageService: IStorageService, providerId: string, accountName: string): AllowedExtension[] {
|
||||
let trustedExtensions: AllowedExtension[] = [];
|
||||
try {
|
||||
const trustedExtensionSrc = storageService.get(`${providerId}-${accountName}`, StorageScope.GLOBAL);
|
||||
if (trustedExtensionSrc) {
|
||||
trustedExtensions = JSON.parse(trustedExtensionSrc);
|
||||
}
|
||||
} catch (err) { }
|
||||
|
||||
return trustedExtensions;
|
||||
}
|
||||
|
||||
export class MainThreadAuthenticationProvider extends Disposable {
|
||||
private _sessionMenuItems = new Map<string, IDisposable[]>();
|
||||
private _accounts = new Map<string, string[]>(); // Map account name to session ids
|
||||
@@ -48,30 +65,25 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
this.registerCommandsAndContextMenuItems();
|
||||
}
|
||||
|
||||
private setPermissionsForAccount(quickInputService: IQuickInputService, doLogin?: boolean) {
|
||||
const quickPick = quickInputService.createQuickPick();
|
||||
private manageTrustedExtensions(quickInputService: IQuickInputService, storageService: IStorageService, accountName: string) {
|
||||
const quickPick = quickInputService.createQuickPick<{ label: string, extension: AllowedExtension }>();
|
||||
quickPick.canSelectMany = true;
|
||||
const items = this.dependents.map(dependent => {
|
||||
const allowedExtensions = readAllowedExtensions(storageService, this.id, accountName);
|
||||
const items = allowedExtensions.map(extension => {
|
||||
return {
|
||||
label: dependent.label,
|
||||
description: dependent.scopeDescriptions,
|
||||
picked: true,
|
||||
scopes: dependent.scopes
|
||||
label: extension.name,
|
||||
extension
|
||||
};
|
||||
});
|
||||
|
||||
quickPick.items = items;
|
||||
// TODO read from storage and filter is not doLogin
|
||||
quickPick.selectedItems = items;
|
||||
quickPick.title = nls.localize('signInTo', "Sign in to {0}", this.displayName);
|
||||
quickPick.placeholder = nls.localize('accountPermissions', "Choose what features and extensions to authorize to use this account");
|
||||
quickPick.title = nls.localize('manageTrustedExtensions', "Manage Trusted Extensions");
|
||||
quickPick.placeholder = nls.localize('manageExensions', "Choose which extensions can access this account");
|
||||
|
||||
quickPick.onDidAccept(() => {
|
||||
const scopes = quickPick.selectedItems.reduce((previous, current) => previous.concat((current as any).scopes), []);
|
||||
if (scopes.length && doLogin) {
|
||||
this.login(scopes);
|
||||
}
|
||||
|
||||
const updatedAllowedList = quickPick.selectedItems.map(item => item.extension);
|
||||
storageService.store(`${this.id}-${accountName}`, JSON.stringify(updatedAllowedList), StorageScope.GLOBAL);
|
||||
quickPick.dispose();
|
||||
});
|
||||
|
||||
@@ -87,7 +99,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
this._register(CommandsRegistry.registerCommand({
|
||||
id: `signIn${this.id}`,
|
||||
handler: (accessor, args) => {
|
||||
this.setPermissionsForAccount(accessor.get(IQuickInputService), true);
|
||||
this.login(this.dependents.reduce((previous: string[], current) => previous.concat(current.scopes), []));
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -130,19 +142,26 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
id: `configureSessions${session.id}`,
|
||||
handler: (accessor, args) => {
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
const storageService = accessor.get(IStorageService);
|
||||
|
||||
const quickPick = quickInputService.createQuickPick();
|
||||
const items = [{ label: 'Sign Out' }];
|
||||
const manage = nls.localize('manageTrustedExtensions', "Manage Trusted Extensions");
|
||||
const signOut = nls.localize('signOut', "Sign Out");
|
||||
const items = ([{ label: manage }, { label: signOut }]);
|
||||
|
||||
quickPick.items = items;
|
||||
|
||||
quickPick.onDidAccept(e => {
|
||||
const selected = quickPick.selectedItems[0];
|
||||
if (selected.label === 'Sign Out') {
|
||||
if (selected.label === signOut) {
|
||||
const sessionsForAccount = this._accounts.get(session.accountName);
|
||||
sessionsForAccount?.forEach(sessionId => this.logout(sessionId));
|
||||
}
|
||||
|
||||
if (selected.label === manage) {
|
||||
this.manageTrustedExtensions(quickInputService, storageService, session.accountName);
|
||||
}
|
||||
|
||||
quickPick.dispose();
|
||||
});
|
||||
|
||||
@@ -185,6 +204,7 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
disposeables.forEach(disposeable => disposeable.dispose());
|
||||
this._sessionMenuItems.delete(accountName);
|
||||
}
|
||||
this._accounts.delete(accountName);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -242,55 +262,45 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
this.authenticationService.sessionsUpdate(id, event);
|
||||
}
|
||||
|
||||
async $getSessionsPrompt(providerId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
|
||||
const alwaysAllow = this.storageService.get(`${extensionId}-${providerId}`, StorageScope.GLOBAL);
|
||||
if (alwaysAllow) {
|
||||
return alwaysAllow === 'true';
|
||||
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)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { choice, checkboxChecked } = await this.dialogService.show(
|
||||
const { choice } = await this.dialogService.show(
|
||||
Severity.Info,
|
||||
nls.localize('confirmAuthenticationAccess', "The extension '{0}' is trying to access authentication information from {1}.", extensionName, providerName),
|
||||
nls.localize('confirmAuthenticationAccess', "The extension '{0}' is trying to access authentication information for the {1} account '{2}'.", extensionName, providerName, accountName),
|
||||
[nls.localize('cancel', "Cancel"), nls.localize('allow', "Allow")],
|
||||
{
|
||||
cancelId: 0,
|
||||
checkbox: {
|
||||
label: nls.localize('neverAgain', "Don't Show Again")
|
||||
}
|
||||
cancelId: 0
|
||||
}
|
||||
);
|
||||
|
||||
const allow = choice === 1;
|
||||
if (checkboxChecked) {
|
||||
this.storageService.store(`${extensionId}-${providerId}`, allow ? 'true' : 'false', StorageScope.GLOBAL);
|
||||
if (allow) {
|
||||
allowList = allowList.concat({ id: extensionId, name: extensionName });
|
||||
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
return allow;
|
||||
}
|
||||
|
||||
async $loginPrompt(providerId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
|
||||
const alwaysAllow = this.storageService.get(`${extensionId}-${providerId}`, StorageScope.GLOBAL);
|
||||
if (alwaysAllow) {
|
||||
return alwaysAllow === 'true';
|
||||
}
|
||||
|
||||
const { choice, checkboxChecked } = await this.dialogService.show(
|
||||
async $loginPrompt(providerName: string, extensionName: string): Promise<boolean> {
|
||||
const { choice } = await this.dialogService.show(
|
||||
Severity.Info,
|
||||
nls.localize('confirmLogin', "The extension '{0}' wants to sign in using {1}.", extensionName, providerName),
|
||||
[nls.localize('cancel', "Cancel"), nls.localize('continue', "Continue")],
|
||||
[nls.localize('cancel', "Cancel"), nls.localize('allow', "Allow")],
|
||||
{
|
||||
cancelId: 0,
|
||||
checkbox: {
|
||||
label: nls.localize('neverAgain', "Don't Show Again")
|
||||
}
|
||||
cancelId: 0
|
||||
}
|
||||
);
|
||||
|
||||
const allow = choice === 1;
|
||||
if (checkboxChecked) {
|
||||
this.storageService.store(`${extensionId}-${providerId}`, allow ? 'true' : 'false', StorageScope.GLOBAL);
|
||||
}
|
||||
return choice === 1;
|
||||
}
|
||||
|
||||
return allow;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@ import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IEx
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/browser/notebookService';
|
||||
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellsSplice, NotebookCellOutputsSplice, CellKind, NotebookDocumentMetadata, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, CellKind, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
@@ -30,16 +29,17 @@ export class MainThreadNotebookDocument extends Disposable {
|
||||
) {
|
||||
super();
|
||||
this._textModel = new NotebookTextModel(handle, viewType, uri);
|
||||
this._register(this._textModel.onDidModelChange(e => {
|
||||
this._proxy.$acceptModelChanged(this.uri, e);
|
||||
}));
|
||||
}
|
||||
|
||||
async deleteCell(uri: URI, index: number): Promise<boolean> {
|
||||
let deleteExtHostCell = await this._proxy.$deleteCell(this.viewType, uri, index);
|
||||
if (deleteExtHostCell) {
|
||||
this._textModel.removeCell(index);
|
||||
return true;
|
||||
}
|
||||
applyEdit(modelVersionId: number, edits: ICellEditOperation[]): boolean {
|
||||
return this._textModel.applyEdit(modelVersionId, edits);
|
||||
}
|
||||
|
||||
return false;
|
||||
updateRenderers(renderers: number[]) {
|
||||
this._textModel.updateRenderers(renderers);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@@ -65,6 +65,16 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
async $tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
|
||||
if (controller) {
|
||||
return controller.tryApplyEdits(resource, modelVersionId, edits, renderers);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
registerListeners() {
|
||||
this._register(this._notebookService.onDidChangeActiveEditor(e => {
|
||||
this._proxy.$updateActiveEditor(e.viewType, e.uri);
|
||||
@@ -148,11 +158,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
return handle;
|
||||
}
|
||||
|
||||
async $spliceNotebookCells(viewType: string, resource: UriComponents, splices: NotebookCellsSplice[], renderers: number[]): Promise<void> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
controller?.spliceNotebookCells(resource, splices, renderers);
|
||||
}
|
||||
|
||||
async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
controller?.spliceNotebookCellOutputs(resource, cellHandle, splices, renderers);
|
||||
@@ -201,11 +206,8 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
|
||||
if (mainthreadNotebook && mainthreadNotebook.textModel.cells.length === 0) {
|
||||
// it's empty, we should create an empty template one
|
||||
const templateCell = await this._proxy.$createEmptyCell(this._viewType, uri, 0, mainthreadNotebook.textModel.languages.length ? mainthreadNotebook.textModel.languages[0] : '', CellKind.Code);
|
||||
if (templateCell) {
|
||||
let mainCell = new NotebookCellTextModel(URI.revive(templateCell.uri), templateCell.handle, templateCell.source, templateCell.language, templateCell.cellKind, templateCell.outputs, templateCell.metadata);
|
||||
mainthreadNotebook.textModel.insertTemplateCell(mainCell);
|
||||
}
|
||||
const mainCell = mainthreadNotebook.textModel.createCellTextModel([''], mainthreadNotebook.textModel.languages.length ? mainthreadNotebook.textModel.languages[0] : '', CellKind.Code, [], undefined);
|
||||
mainthreadNotebook.textModel.insertTemplateCell(mainCell);
|
||||
}
|
||||
return mainthreadNotebook?.textModel;
|
||||
}
|
||||
@@ -213,10 +215,15 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
spliceNotebookCells(resource: UriComponents, splices: NotebookCellsSplice[], renderers: number[]): void {
|
||||
async tryApplyEdits(resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean> {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(resource).toString());
|
||||
mainthreadNotebook?.textModel.updateRenderers(renderers);
|
||||
mainthreadNotebook?.textModel.$spliceNotebookCells(splices);
|
||||
|
||||
if (mainthreadNotebook) {
|
||||
mainthreadNotebook.updateRenderers(renderers);
|
||||
return mainthreadNotebook.applyEdit(modelVersionId, edits);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
spliceNotebookCellOutputs(resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): void {
|
||||
@@ -259,26 +266,6 @@ export class MainThreadNotebookController implements IMainNotebookController {
|
||||
document?.textModel.updateRenderers(renderers);
|
||||
}
|
||||
|
||||
async createRawCell(uri: URI, index: number, language: string, type: CellKind): Promise<NotebookCellTextModel | undefined> {
|
||||
let cell = await this._proxy.$createEmptyCell(this._viewType, uri, index, language, type);
|
||||
if (cell) {
|
||||
let mainCell = new NotebookCellTextModel(URI.revive(cell.uri), cell.handle, cell.source, cell.language, cell.cellKind, cell.outputs, cell.metadata);
|
||||
return mainCell;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async deleteCell(uri: URI, index: number): Promise<boolean> {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
|
||||
|
||||
if (mainthreadNotebook) {
|
||||
return mainthreadNotebook.deleteCell(uri, index);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async executeNotebookCell(uri: URI, handle: number): Promise<void> {
|
||||
return this._proxy.$executeNotebook(this._viewType, uri, handle);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { localize } from 'vs/nls';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProgressStep, IProgress } from 'vs/platform/progress/common/progress';
|
||||
import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { ITextFileSaveParticipant, IResolvedTextFileEditorModel, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ITextFileSaveParticipant, ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { SaveReason } from 'vs/workbench/common/editor';
|
||||
import { ExtHostContext, ExtHostDocumentSaveParticipantShape, IExtHostContext } from '../common/extHost.protocol';
|
||||
import { canceled } from 'vs/base/common/errors';
|
||||
@@ -23,9 +23,9 @@ class ExtHostSaveParticipant implements ITextFileSaveParticipant {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocumentSaveParticipant);
|
||||
}
|
||||
|
||||
async participate(editorModel: IResolvedTextFileEditorModel, env: { reason: SaveReason; }, _progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
|
||||
async participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason; }, _progress: IProgress<IProgressStep>, token: CancellationToken): Promise<void> {
|
||||
|
||||
if (!shouldSynchronizeModel(editorModel.textEditorModel)) {
|
||||
if (!editorModel.textEditorModel || !shouldSynchronizeModel(editorModel.textEditorModel)) {
|
||||
// the model never made it to the extension
|
||||
// host meaning we cannot participate in its save
|
||||
return undefined;
|
||||
|
||||
@@ -13,6 +13,8 @@ import { ITerminalInstanceService, ITerminalService, ITerminalInstance, ITermina
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
|
||||
import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
|
||||
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
|
||||
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
|
||||
@@ -29,8 +31,9 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
extHostContext: IExtHostContext,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@ITerminalInstanceService readonly terminalInstanceService: ITerminalInstanceService,
|
||||
@IRemoteAgentService readonly _remoteAgentService: IRemoteAgentService,
|
||||
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IEnvironmentVariableService private readonly _environmentVariableService: IEnvironmentVariableService,
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
|
||||
this._remoteAuthority = extHostContext.remoteAuthority;
|
||||
@@ -71,6 +74,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
if (activeInstance) {
|
||||
this._proxy.$acceptActiveTerminalChanged(activeInstance.id);
|
||||
}
|
||||
if (this._environmentVariableService.collections.size > 0) {
|
||||
const collectionAsArray = [...this._environmentVariableService.collections.entries()];
|
||||
const serializedCollections: [string, ISerializableEnvironmentVariableCollection][] = collectionAsArray.map(e => {
|
||||
return [e[0], serializeEnvironmentVariableCollection(e[1].map)];
|
||||
});
|
||||
this._proxy.$initEnvironmentVariableCollections(serializedCollections);
|
||||
}
|
||||
|
||||
this._terminalService.extHostReady(extHostContext.remoteAuthority);
|
||||
}
|
||||
@@ -346,6 +356,18 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
}
|
||||
return terminal;
|
||||
}
|
||||
|
||||
$setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void {
|
||||
if (collection) {
|
||||
const translatedCollection = {
|
||||
persistent,
|
||||
map: deserializeEnvironmentVariableCollection(collection)
|
||||
};
|
||||
this._environmentVariableService.set(extensionIdentifier, translatedCollection);
|
||||
} else {
|
||||
this._environmentVariableService.delete(extensionIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user