mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
Merge remote-tracking branch 'origin/master' into alex/extension-host
This commit is contained in:
+2
-1
@@ -519,7 +519,8 @@
|
||||
"**/vs/workbench/services/**/common/**",
|
||||
"**/vs/workbench/api/**/common/**",
|
||||
"vscode-textmate",
|
||||
"vscode-oniguruma"
|
||||
"vscode-oniguruma",
|
||||
"iconv-lite-umd"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -221,6 +221,19 @@
|
||||
"addLabel": "*caused-by-extension",
|
||||
"comment": "It looks like this is caused by the C++ extension. Please file it with the repository [here](https://github.com/Microsoft/vscode-cpptools). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "extCpp",
|
||||
"allowUsers": [
|
||||
"cleidigh",
|
||||
"usernamehw",
|
||||
"gjsjohnmurray",
|
||||
"IllusionMH"
|
||||
],
|
||||
"action": "close",
|
||||
"addLabel": "*caused-by-extension",
|
||||
"comment": "It looks like this is caused by the C++ extension. Please file it with the repository [here](https://github.com/Microsoft/vscode-cpptools). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!"
|
||||
},
|
||||
{
|
||||
"type": "comment",
|
||||
"name": "extTS",
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
path: ./actions
|
||||
- name: Install Actions
|
||||
run: npm install --production --prefix ./actions
|
||||
- name: "Run Classifier: Scraper"
|
||||
- name: "Run Classifier: Monitor"
|
||||
uses: ./actions/classifier-deep/monitor
|
||||
with:
|
||||
botName: vscode-triage-bot
|
||||
|
||||
@@ -45,5 +45,6 @@ jobs:
|
||||
uses: ./actions/classifier-deep/apply/apply-labels
|
||||
with:
|
||||
configPath: classifier
|
||||
allowLabels: "needs more info|new release"
|
||||
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
|
||||
token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}}
|
||||
|
||||
@@ -48,6 +48,14 @@ jobs:
|
||||
mustNotMatch: "^We have written the needed data into your clipboard because it was too large to send\\. Please paste\\.$"
|
||||
comment: "It looks like you're using the VS Code Issue Reporter but did not paste the text generated into the created issue. We've closed this issue, please open a new one containing the text we placed in your clipboard.\n\nHappy Coding!"
|
||||
|
||||
- name: Run Clipboard Labeler (Chinese)
|
||||
uses: ./actions/regex-labeler
|
||||
with:
|
||||
appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}}
|
||||
label: "invalid"
|
||||
mustNotMatch: "^所需的数据太大,无法直接发送。我们已经将其写入剪贴板,请粘贴。$"
|
||||
comment: "看起来您正在使用 VS Code 问题报告程序,但是没有将生成的文本粘贴到创建的问题中。我们将关闭这个问题,请使用剪贴板中的内容创建一个新的问题。\n\n祝您使用愉快!"
|
||||
|
||||
# source of truth in ./english-please.yml
|
||||
- name: Run English Please
|
||||
uses: ./actions/english-please
|
||||
|
||||
@@ -13,7 +13,11 @@ jobs:
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v1
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
run: yarn --frozen-lockfile
|
||||
env:
|
||||
CHILD_CONCURRENCY: 1
|
||||
- uses: microsoft/RichCodeNavIndexer@master
|
||||
with:
|
||||
languages: typescript
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
continue-on-error: true
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
disturl "https://atom.io/download/electron"
|
||||
target "7.3.1"
|
||||
target "8.3.3"
|
||||
runtime "electron"
|
||||
|
||||
+3
-2
@@ -16,7 +16,7 @@ const https = require("https");
|
||||
const gulp = require("gulp");
|
||||
const fancyLog = require("fancy-log");
|
||||
const ansiColors = require("ansi-colors");
|
||||
const iconv = require("iconv-lite");
|
||||
const iconv = require("iconv-lite-umd");
|
||||
const NUMBER_OF_CONCURRENT_DOWNLOADS = 4;
|
||||
function log(message, ...rest) {
|
||||
fancyLog(ansiColors.green('[i18n]'), message, ...rest);
|
||||
@@ -1175,9 +1175,10 @@ function createIslFile(originalFilePath, messages, language, innoSetup) {
|
||||
});
|
||||
const basename = path.basename(originalFilePath);
|
||||
const filePath = `${basename}.${language.id}.isl`;
|
||||
const encoded = iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage);
|
||||
return new File({
|
||||
path: filePath,
|
||||
contents: iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage)
|
||||
contents: Buffer.from(encoded),
|
||||
});
|
||||
}
|
||||
function encodeEntities(value) {
|
||||
|
||||
+3
-2
@@ -15,7 +15,7 @@ import * as https from 'https';
|
||||
import * as gulp from 'gulp';
|
||||
import * as fancyLog from 'fancy-log';
|
||||
import * as ansiColors from 'ansi-colors';
|
||||
import * as iconv from 'iconv-lite';
|
||||
import * as iconv from 'iconv-lite-umd';
|
||||
|
||||
const NUMBER_OF_CONCURRENT_DOWNLOADS = 4;
|
||||
|
||||
@@ -1339,10 +1339,11 @@ function createIslFile(originalFilePath: string, messages: Map<string>, language
|
||||
|
||||
const basename = path.basename(originalFilePath);
|
||||
const filePath = `${basename}.${language.id}.isl`;
|
||||
const encoded = iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage);
|
||||
|
||||
return new File({
|
||||
path: filePath,
|
||||
contents: iconv.encode(Buffer.from(content.join('\r\n'), 'utf8').toString(), innoSetup.codePage)
|
||||
contents: Buffer.from(encoded),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@
|
||||
"gulp-bom": "^1.0.0",
|
||||
"gulp-sourcemaps": "^1.11.0",
|
||||
"gulp-uglify": "^3.0.0",
|
||||
"iconv-lite": "0.6.0",
|
||||
"iconv-lite-umd": "0.6.3",
|
||||
"mime": "^1.3.4",
|
||||
"minimatch": "3.0.4",
|
||||
"minimist": "^1.2.3",
|
||||
|
||||
+4
-11
@@ -1415,12 +1415,10 @@ http-signature@~1.2.0:
|
||||
jsprim "^1.2.2"
|
||||
sshpk "^1.7.0"
|
||||
|
||||
iconv-lite@0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.0.tgz#66a93b80df0bd05d2a43a7426296b7f91073f125"
|
||||
integrity sha512-43ZpGYZ9QtuutX5l6WC1DSO8ane9N+Ct5qPLF2OV7vM9abM69gnAbVkh66ibaZd3aOGkoP1ZmringlKhLBkw2Q==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
iconv-lite-umd@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite-umd/-/iconv-lite-umd-0.6.3.tgz#61307cab8ac29939992d0724d3ab8799467f0e97"
|
||||
integrity sha512-fQ/8XE8reiCZ6t+SX4tX6/tQdV4tThJZv5qtMe5Sk+IWsExz0S2Zd+GiBS5IEPgDxnsmiJSpH67+qzN3FT4lKw==
|
||||
|
||||
ignore@^5.1.1:
|
||||
version "5.1.2"
|
||||
@@ -2228,11 +2226,6 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
sax@0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.2.tgz#735ffaa39a1cff8ffb9598f0223abdb03a9fb2ea"
|
||||
|
||||
+6
-6
@@ -6,7 +6,7 @@
|
||||
"git": {
|
||||
"name": "chromium",
|
||||
"repositoryUrl": "https://chromium.googlesource.com/chromium/src",
|
||||
"commitHash": "e4745133a1d3745f066e068b8033c6a269b59caf"
|
||||
"commitHash": "052d3b44972e6d94ef40054d46c150b7cdd7a5d8"
|
||||
}
|
||||
},
|
||||
"licenseDetail": [
|
||||
@@ -40,7 +40,7 @@
|
||||
"SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
],
|
||||
"isOnlyProductionDependency": true,
|
||||
"version": "78.0.3904.130"
|
||||
"version": "80.0.3987.165"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
@@ -48,11 +48,11 @@
|
||||
"git": {
|
||||
"name": "nodejs",
|
||||
"repositoryUrl": "https://github.com/nodejs/node",
|
||||
"commitHash": "787378879acfb212ed4ff824bf9f767a24a5cb43a"
|
||||
"commitHash": "42cce5a9d0fd905bf4ad7a2528c36572dfb8b5ad"
|
||||
}
|
||||
},
|
||||
"isOnlyProductionDependency": true,
|
||||
"version": "12.8.1"
|
||||
"version": "12.13.0"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
@@ -60,12 +60,12 @@
|
||||
"git": {
|
||||
"name": "electron",
|
||||
"repositoryUrl": "https://github.com/electron/electron",
|
||||
"commitHash": "bc8fc0d406d32e4c02f3ec9f161deaacbe4f5989"
|
||||
"commitHash": "87fd06bc96bce8f46ca05b8315657fd230bcac85"
|
||||
}
|
||||
},
|
||||
"isOnlyProductionDependency": true,
|
||||
"license": "MIT",
|
||||
"version": "7.3.1"
|
||||
"version": "8.3.3"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"git": {
|
||||
"name": "textmate/c.tmbundle",
|
||||
"repositoryUrl": "https://github.com/textmate/c.tmbundle",
|
||||
"commitHash": "9aa365882274ca52f01722f3dbb169b9539a20ee"
|
||||
"commitHash": "60daf83b9d45329524f7847a75e9298b3aae5805"
|
||||
}
|
||||
},
|
||||
"licenseDetail": [
|
||||
@@ -42,4 +42,4 @@
|
||||
}
|
||||
],
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -76,17 +76,13 @@ function getCustomDataPathsInAllWorkspaces(): string[] {
|
||||
|
||||
function getCustomDataPathsFromAllExtensions(): string[] {
|
||||
const dataPaths: string[] = [];
|
||||
|
||||
for (const extension of extensions.all) {
|
||||
const contributes = extension.packageJSON && extension.packageJSON.contributes;
|
||||
|
||||
if (contributes && contributes.css && contributes.css.customData && Array.isArray(contributes.css.customData)) {
|
||||
const relativePaths: string[] = contributes.css.customData;
|
||||
relativePaths.forEach(rp => {
|
||||
const customData = extension.packageJSON?.contributes?.css?.customData;
|
||||
if (Array.isArray(customData)) {
|
||||
for (const rp of customData) {
|
||||
dataPaths.push(joinPath(extension.extensionUri, rp).toString());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dataPaths;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ function parseCSSData(source: string): ICSSDataProvider {
|
||||
}
|
||||
|
||||
return newCSSDataProvider({
|
||||
version: 1,
|
||||
version: rawData.version || 1,
|
||||
properties: rawData.properties || [],
|
||||
atDirectives: rawData.atDirectives || [],
|
||||
pseudoClasses: rawData.pseudoClasses || [],
|
||||
|
||||
@@ -1878,7 +1878,7 @@
|
||||
"dependencies": {
|
||||
"byline": "^5.0.0",
|
||||
"file-type": "^7.2.0",
|
||||
"iconv-lite": "0.6.0",
|
||||
"iconv-lite-umd": "0.6.3",
|
||||
"jschardet": "2.1.1",
|
||||
"vscode-extension-telemetry": "0.1.1",
|
||||
"vscode-nls": "^4.0.0",
|
||||
|
||||
@@ -8,15 +8,15 @@ import * as path from 'path';
|
||||
import { Repository, GitResourceGroup } from './repository';
|
||||
import { Model } from './model';
|
||||
import { debounce } from './decorators';
|
||||
import { filterEvent, dispose, anyEvent, fireEvent } from './util';
|
||||
import { filterEvent, dispose, anyEvent, fireEvent, PromiseSource } from './util';
|
||||
import { GitErrorCodes, Status } from './api/git';
|
||||
|
||||
type Callback = { resolve: (status: boolean) => void, reject: (err: any) => void };
|
||||
|
||||
class GitIgnoreDecorationProvider implements DecorationProvider {
|
||||
|
||||
private static Decoration: Decoration = { priority: 3, color: new ThemeColor('gitDecoration.ignoredResourceForeground') };
|
||||
|
||||
readonly onDidChangeDecorations: Event<Uri[]>;
|
||||
private queue = new Map<string, { repository: Repository; queue: Map<string, Callback>; }>();
|
||||
private queue = new Map<string, { repository: Repository; queue: Map<string, PromiseSource<Decoration | undefined>>; }>();
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
constructor(private model: Model) {
|
||||
@@ -29,32 +29,29 @@ class GitIgnoreDecorationProvider implements DecorationProvider {
|
||||
this.disposables.push(window.registerDecorationProvider(this));
|
||||
}
|
||||
|
||||
provideDecoration(uri: Uri): Promise<Decoration | undefined> {
|
||||
async provideDecoration(uri: Uri): Promise<Decoration | undefined> {
|
||||
const repository = this.model.getRepository(uri);
|
||||
|
||||
if (!repository) {
|
||||
return Promise.resolve(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
let queueItem = this.queue.get(repository.root);
|
||||
|
||||
if (!queueItem) {
|
||||
queueItem = { repository, queue: new Map<string, Callback>() };
|
||||
queueItem = { repository, queue: new Map<string, PromiseSource<Decoration | undefined>>() };
|
||||
this.queue.set(repository.root, queueItem);
|
||||
}
|
||||
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
queueItem!.queue.set(uri.fsPath, { resolve, reject });
|
||||
let promiseSource = queueItem.queue.get(uri.fsPath);
|
||||
|
||||
if (!promiseSource) {
|
||||
promiseSource = new PromiseSource();
|
||||
queueItem!.queue.set(uri.fsPath, promiseSource);
|
||||
this.checkIgnoreSoon();
|
||||
}).then(ignored => {
|
||||
if (ignored) {
|
||||
return <Decoration>{
|
||||
priority: 3,
|
||||
color: new ThemeColor('gitDecoration.ignoredResourceForeground')
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
return await promiseSource.promise;
|
||||
}
|
||||
|
||||
@debounce(500)
|
||||
@@ -66,16 +63,16 @@ class GitIgnoreDecorationProvider implements DecorationProvider {
|
||||
const paths = [...item.queue.keys()];
|
||||
|
||||
item.repository.checkIgnore(paths).then(ignoreSet => {
|
||||
for (const [key, value] of item.queue.entries()) {
|
||||
value.resolve(ignoreSet.has(key));
|
||||
for (const [path, promiseSource] of item.queue.entries()) {
|
||||
promiseSource.resolve(ignoreSet.has(path) ? GitIgnoreDecorationProvider.Decoration : undefined);
|
||||
}
|
||||
}, err => {
|
||||
if (err.gitErrorCode !== GitErrorCodes.IsInSubmodule) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
for (const [, value] of item.queue.entries()) {
|
||||
value.reject(err);
|
||||
for (const [, promiseSource] of item.queue.entries()) {
|
||||
promiseSource.reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as os from 'os';
|
||||
import * as cp from 'child_process';
|
||||
import * as which from 'which';
|
||||
import { EventEmitter } from 'events';
|
||||
import iconv = require('iconv-lite');
|
||||
import * as iconv from 'iconv-lite-umd';
|
||||
import * as filetype from 'file-type';
|
||||
import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter } from './util';
|
||||
import { CancellationToken, Progress, Uri } from 'vscode';
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Disposable } from 'vscode';
|
||||
import { Event, Disposable, EventEmitter } from 'vscode';
|
||||
import { dirname, sep } from 'path';
|
||||
import { Readable } from 'stream';
|
||||
import { promises as fs, createReadStream } from 'fs';
|
||||
@@ -400,3 +400,39 @@ export class Limiter<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Completion<T> = { success: true, value: T } | { success: false, err: any };
|
||||
|
||||
export class PromiseSource<T> {
|
||||
|
||||
private _onDidComplete = new EventEmitter<Completion<T>>();
|
||||
|
||||
private _promise: Promise<T> | undefined;
|
||||
get promise(): Promise<T> {
|
||||
if (this._promise) {
|
||||
return this._promise;
|
||||
}
|
||||
|
||||
return eventToPromise(this._onDidComplete.event).then(completion => {
|
||||
if (completion.success) {
|
||||
return completion.value;
|
||||
} else {
|
||||
throw completion.err;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
resolve(value: T): void {
|
||||
if (!this._promise) {
|
||||
this._promise = Promise.resolve(value);
|
||||
this._onDidComplete.fire({ success: true, value });
|
||||
}
|
||||
}
|
||||
|
||||
reject(err: any): void {
|
||||
if (!this._promise) {
|
||||
this._promise = Promise.reject(err);
|
||||
this._onDidComplete.fire({ success: false, err });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,12 +425,10 @@ https-proxy-agent@^2.2.1:
|
||||
agent-base "^4.3.0"
|
||||
debug "^3.1.0"
|
||||
|
||||
iconv-lite@0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.0.tgz#66a93b80df0bd05d2a43a7426296b7f91073f125"
|
||||
integrity sha512-43ZpGYZ9QtuutX5l6WC1DSO8ane9N+Ct5qPLF2OV7vM9abM69gnAbVkh66ibaZd3aOGkoP1ZmringlKhLBkw2Q==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
iconv-lite-umd@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite-umd/-/iconv-lite-umd-0.6.3.tgz#61307cab8ac29939992d0724d3ab8799467f0e97"
|
||||
integrity sha512-fQ/8XE8reiCZ6t+SX4tX6/tQdV4tThJZv5qtMe5Sk+IWsExz0S2Zd+GiBS5IEPgDxnsmiJSpH67+qzN3FT4lKw==
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
@@ -748,7 +746,7 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.2:
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
|
||||
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"bin": {
|
||||
"vscode-json-languageserver": "./bin/vscode-json-languageserver"
|
||||
},
|
||||
"main": "./out/jsonServerMain",
|
||||
"main": "./out/node/jsonServerMain",
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^2.2.1",
|
||||
"request-light": "^0.3.0",
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
//@ts-check
|
||||
|
||||
'use strict';
|
||||
|
||||
const withDefaults = require('../shared.webpack.config');
|
||||
const path = require('path');
|
||||
|
||||
const clientConfig = withDefaults({
|
||||
target: 'webworker',
|
||||
context: __dirname,
|
||||
entry: {
|
||||
extension: './src/npmBrowserMain.ts'
|
||||
},
|
||||
output: {
|
||||
filename: 'npmBrowserMain.js'
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'vscode-nls': path.resolve(__dirname, '../../build/polyfills/vscode-nls.js')
|
||||
}
|
||||
},
|
||||
node: {
|
||||
'child_process': 'empty'
|
||||
}
|
||||
});
|
||||
clientConfig.module.rules[0].use.shift(); // remove nls loader
|
||||
|
||||
module.exports = clientConfig;
|
||||
@@ -14,12 +14,10 @@ const withDefaults = require('../shared.webpack.config');
|
||||
module.exports = withDefaults({
|
||||
context: __dirname,
|
||||
entry: {
|
||||
extension: './src/main.ts',
|
||||
extension: './src/npmMain.ts',
|
||||
},
|
||||
output: {
|
||||
filename: 'main.js',
|
||||
path: path.join(__dirname, 'dist'),
|
||||
libraryTarget: 'commonjs',
|
||||
filename: 'npmMain.js',
|
||||
},
|
||||
resolve: {
|
||||
mainFields: ['module', 'main'],
|
||||
|
||||
@@ -20,14 +20,15 @@
|
||||
"dependencies": {
|
||||
"jsonc-parser": "^2.2.1",
|
||||
"minimatch": "^3.0.4",
|
||||
"request-light": "^0.2.5",
|
||||
"request-light": "^0.4.0",
|
||||
"vscode-nls": "^4.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/minimatch": "^3.0.3",
|
||||
"@types/node": "^12.11.7"
|
||||
},
|
||||
"main": "./out/main",
|
||||
"main": "./out/npmMain",
|
||||
"browser": "./dist/npmBrowserMain",
|
||||
"activationEvents": [
|
||||
"onCommand:workbench.action.tasks.runTask",
|
||||
"onCommand:npm.runScriptFromFolder",
|
||||
@@ -181,12 +182,12 @@
|
||||
}
|
||||
],
|
||||
"explorer/context": [
|
||||
{
|
||||
"when": "config.npm.enableRunFromFolder && explorerViewletVisible && explorerResourceIsFolder",
|
||||
{
|
||||
"when": "config.npm.enableRunFromFolder && explorerViewletVisible && explorerResourceIsFolder",
|
||||
"command": "npm.runScriptFromFolder",
|
||||
"group": "2_workspace"
|
||||
}
|
||||
]
|
||||
"group": "2_workspace"
|
||||
}
|
||||
]
|
||||
},
|
||||
"configuration": {
|
||||
"id": "npm",
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { MarkedString, CompletionItemKind, CompletionItem, DocumentSelector, SnippetString, workspace } from 'vscode';
|
||||
import { MarkdownString, CompletionItemKind, CompletionItem, DocumentSelector, SnippetString, workspace } from 'vscode';
|
||||
import { IJSONContribution, ISuggestionsCollector } from './jsonContributions';
|
||||
import { XHRRequest } from 'request-light';
|
||||
import { Location } from 'jsonc-parser';
|
||||
import { textToMarkedString } from './markedTextUtil';
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
@@ -181,13 +180,15 @@ export class BowerJSONContribution implements IJSONContribution {
|
||||
});
|
||||
}
|
||||
|
||||
public getInfoContribution(_resource: string, location: Location): Thenable<MarkedString[] | null> | null {
|
||||
public getInfoContribution(_resource: string, location: Location): Thenable<MarkdownString[] | null> | null {
|
||||
if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']))) {
|
||||
const pack = location.path[location.path.length - 1];
|
||||
if (typeof pack === 'string') {
|
||||
return this.getInfo(pack).then(documentation => {
|
||||
if (documentation) {
|
||||
return [textToMarkedString(documentation)];
|
||||
const str = new MarkdownString();
|
||||
str.appendText(documentation);
|
||||
return [str];
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -30,8 +30,8 @@ export interface IJSONContribution {
|
||||
resolveSuggestion?(item: CompletionItem): Thenable<CompletionItem | null> | null;
|
||||
}
|
||||
|
||||
export function addJSONProviders(xhr: XHRRequest): Disposable {
|
||||
const contributions = [new PackageJSONContribution(xhr), new BowerJSONContribution(xhr)];
|
||||
export function addJSONProviders(xhr: XHRRequest, canRunNPM: boolean): Disposable {
|
||||
const contributions = [new PackageJSONContribution(xhr, canRunNPM), new BowerJSONContribution(xhr)];
|
||||
const subscriptions: Disposable[] = [];
|
||||
contributions.forEach(contribution => {
|
||||
const selector = contribution.getDocumentSelector();
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { MarkedString, CompletionItemKind, CompletionItem, DocumentSelector, SnippetString, workspace } from 'vscode';
|
||||
import { MarkedString, CompletionItemKind, CompletionItem, DocumentSelector, SnippetString, workspace, MarkdownString } from 'vscode';
|
||||
import { IJSONContribution, ISuggestionsCollector } from './jsonContributions';
|
||||
import { XHRRequest } from 'request-light';
|
||||
import { Location } from 'jsonc-parser';
|
||||
import { textToMarkedString } from './markedTextUtil';
|
||||
|
||||
import * as cp from 'child_process';
|
||||
import * as nls from 'vscode-nls';
|
||||
@@ -28,14 +27,12 @@ export class PackageJSONContribution implements IJSONContribution {
|
||||
'jsdom', 'stylus', 'when', 'readable-stream', 'aws-sdk', 'concat-stream', 'chai', 'Thenable', 'wrench'];
|
||||
|
||||
private knownScopes = ['@types', '@angular', '@babel', '@nuxtjs', '@vue', '@bazel'];
|
||||
private xhr: XHRRequest;
|
||||
|
||||
public getDocumentSelector(): DocumentSelector {
|
||||
return [{ language: 'json', scheme: '*', pattern: '**/package.json' }];
|
||||
}
|
||||
|
||||
public constructor(xhr: XHRRequest) {
|
||||
this.xhr = xhr;
|
||||
public constructor(private xhr: XHRRequest, private canRunNPM: boolean) {
|
||||
}
|
||||
|
||||
public collectDefaultSuggestions(_fileName: string, result: ISuggestionsCollector): Thenable<any> {
|
||||
@@ -191,23 +188,23 @@ export class PackageJSONContribution implements IJSONContribution {
|
||||
const currentKey = location.path[location.path.length - 1];
|
||||
if (typeof currentKey === 'string') {
|
||||
const info = await this.fetchPackageInfo(currentKey);
|
||||
if (info && info.distTagsLatest) {
|
||||
if (info && info.version) {
|
||||
|
||||
let name = JSON.stringify(info.distTagsLatest);
|
||||
let name = JSON.stringify(info.version);
|
||||
let proposal = new CompletionItem(name);
|
||||
proposal.kind = CompletionItemKind.Property;
|
||||
proposal.insertText = name;
|
||||
proposal.documentation = localize('json.npm.latestversion', 'The currently latest version of the package');
|
||||
result.add(proposal);
|
||||
|
||||
name = JSON.stringify('^' + info.distTagsLatest);
|
||||
name = JSON.stringify('^' + info.version);
|
||||
proposal = new CompletionItem(name);
|
||||
proposal.kind = CompletionItemKind.Property;
|
||||
proposal.insertText = name;
|
||||
proposal.documentation = localize('json.npm.majorversion', 'Matches the most recent major version (1.x.x)');
|
||||
result.add(proposal);
|
||||
|
||||
name = JSON.stringify('~' + info.distTagsLatest);
|
||||
name = JSON.stringify('~' + info.version);
|
||||
proposal = new CompletionItem(name);
|
||||
proposal.kind = CompletionItemKind.Property;
|
||||
proposal.insertText = name;
|
||||
@@ -219,14 +216,27 @@ export class PackageJSONContribution implements IJSONContribution {
|
||||
return null;
|
||||
}
|
||||
|
||||
private getDocumentation(description: string | undefined, version: string | undefined, homepage: string | undefined): MarkdownString {
|
||||
const str = new MarkdownString();
|
||||
if (description) {
|
||||
str.appendText(description);
|
||||
}
|
||||
if (version) {
|
||||
str.appendText('\n\n');
|
||||
str.appendText(localize('json.npm.version.hover', 'Latest version: {0}', version));
|
||||
}
|
||||
if (homepage) {
|
||||
str.appendText('\n\n');
|
||||
str.appendText(homepage);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public resolveSuggestion(item: CompletionItem): Thenable<CompletionItem | null> | null {
|
||||
if (item.kind === CompletionItemKind.Property && item.documentation === '') {
|
||||
return this.getInfo(item.label).then(infos => {
|
||||
if (infos.length > 0) {
|
||||
item.documentation = infos[0];
|
||||
if (infos.length > 1) {
|
||||
item.detail = infos[1];
|
||||
}
|
||||
if (item.kind === CompletionItemKind.Property && !item.documentation) {
|
||||
return this.fetchPackageInfo(item.label).then(info => {
|
||||
if (info) {
|
||||
item.documentation = this.getDocumentation(info.description, info.version, info.homepage);
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
@@ -235,21 +245,11 @@ export class PackageJSONContribution implements IJSONContribution {
|
||||
return null;
|
||||
}
|
||||
|
||||
private async getInfo(pack: string): Promise<string[]> {
|
||||
let info = await this.fetchPackageInfo(pack);
|
||||
if (info) {
|
||||
const result: string[] = [];
|
||||
result.push(info.description || '');
|
||||
result.push(info.distTagsLatest ? localize('json.npm.version.hover', 'Latest version: {0}', info.distTagsLatest) : '');
|
||||
result.push(info.homepage || '');
|
||||
return result;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private async fetchPackageInfo(pack: string): Promise<ViewPackageInfo | undefined> {
|
||||
let info = await this.npmView(pack);
|
||||
let info: ViewPackageInfo | undefined;
|
||||
if (this.canRunNPM) {
|
||||
info = await this.npmView(pack);
|
||||
}
|
||||
if (!info) {
|
||||
info = await this.npmjsView(pack);
|
||||
}
|
||||
@@ -259,14 +259,14 @@ export class PackageJSONContribution implements IJSONContribution {
|
||||
|
||||
private npmView(pack: string): Promise<ViewPackageInfo | undefined> {
|
||||
return new Promise((resolve, _reject) => {
|
||||
const command = 'npm view --json ' + pack + ' description dist-tags.latest homepage';
|
||||
const command = 'npm view --json ' + pack + ' description dist-tags.latest homepage version';
|
||||
cp.exec(command, (error, stdout) => {
|
||||
if (!error) {
|
||||
try {
|
||||
const content = JSON.parse(stdout);
|
||||
resolve({
|
||||
description: content['description'],
|
||||
distTagsLatest: content['dist-tags.latest'],
|
||||
version: content['dist-tags.latest'] || content['version'],
|
||||
homepage: content['homepage']
|
||||
});
|
||||
return;
|
||||
@@ -280,22 +280,20 @@ export class PackageJSONContribution implements IJSONContribution {
|
||||
}
|
||||
|
||||
private async npmjsView(pack: string): Promise<ViewPackageInfo | undefined> {
|
||||
const queryUrl = 'https://registry.npmjs.org/' + encodeURIComponent(pack).replace(/%40/g, '@');
|
||||
const queryUrl = 'https://api.npms.io/v2/package/' + encodeURIComponent(pack);
|
||||
try {
|
||||
const success = await this.xhr({
|
||||
url: queryUrl,
|
||||
agent: USER_AGENT
|
||||
});
|
||||
const obj = JSON.parse(success.responseText);
|
||||
if (obj) {
|
||||
const latest = obj && obj['dist-tags'] && obj['dist-tags']['latest'];
|
||||
if (latest) {
|
||||
return {
|
||||
description: obj.description || '',
|
||||
distTagsLatest: latest,
|
||||
homepage: obj.homepage || ''
|
||||
};
|
||||
}
|
||||
const metadata = obj?.collected?.metadata;
|
||||
if (metadata) {
|
||||
return {
|
||||
description: metadata.description || '',
|
||||
version: metadata.version,
|
||||
homepage: metadata.links?.homepage || ''
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
@@ -308,9 +306,9 @@ export class PackageJSONContribution implements IJSONContribution {
|
||||
if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) {
|
||||
const pack = location.path[location.path.length - 1];
|
||||
if (typeof pack === 'string') {
|
||||
return this.getInfo(pack).then(infos => {
|
||||
if (infos.length) {
|
||||
return [infos.map(textToMarkedString).join('\n\n')];
|
||||
return this.fetchPackageInfo(pack).then(info => {
|
||||
if (info) {
|
||||
return [this.getDocumentation(info.description, info.version, info.homepage)];
|
||||
}
|
||||
return null;
|
||||
});
|
||||
@@ -339,7 +337,7 @@ export class PackageJSONContribution implements IJSONContribution {
|
||||
proposal.kind = CompletionItemKind.Property;
|
||||
proposal.insertText = insertText;
|
||||
proposal.filterText = JSON.stringify(name);
|
||||
proposal.documentation = pack.description || '';
|
||||
proposal.documentation = this.getDocumentation(pack.description, pack.version, pack?.links?.homepage);
|
||||
collector.add(proposal);
|
||||
}
|
||||
}
|
||||
@@ -349,10 +347,11 @@ interface SearchPackageInfo {
|
||||
name: string;
|
||||
description?: string;
|
||||
version?: string;
|
||||
links?: { homepage?: string; };
|
||||
}
|
||||
|
||||
interface ViewPackageInfo {
|
||||
description: string;
|
||||
distTagsLatest?: string;
|
||||
version?: string;
|
||||
homepage?: string;
|
||||
}
|
||||
|
||||
+9
-4
@@ -3,8 +3,13 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { MarkedString } from 'vscode';
|
||||
import * as httpRequest from 'request-light';
|
||||
import * as vscode from 'vscode';
|
||||
import { addJSONProviders } from './features/jsonContributions';
|
||||
|
||||
export function textToMarkedString(text: string): MarkedString {
|
||||
return text.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&'); // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
|
||||
}
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<void> {
|
||||
context.subscriptions.push(addJSONProviders(httpRequest.xhr, false));
|
||||
}
|
||||
|
||||
export function deactivate(): void {
|
||||
}
|
||||
@@ -14,13 +14,19 @@ import { invalidateHoverScriptsCache, NpmScriptHoverProvider } from './scriptHov
|
||||
let treeDataProvider: NpmScriptsTreeDataProvider | undefined;
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<void> {
|
||||
registerTaskProvider(context);
|
||||
treeDataProvider = registerExplorer(context);
|
||||
registerHoverProvider(context);
|
||||
|
||||
configureHttpRequest();
|
||||
let d = vscode.workspace.onDidChangeConfiguration((e) => {
|
||||
configureHttpRequest();
|
||||
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('http.proxy') || e.affectsConfiguration('http.proxyStrictSSL')) {
|
||||
configureHttpRequest();
|
||||
}
|
||||
}));
|
||||
|
||||
const canRunNPM = canRunNpmInCurrentWorkspace();
|
||||
context.subscriptions.push(addJSONProviders(httpRequest.xhr, canRunNPM));
|
||||
|
||||
treeDataProvider = registerExplorer(context);
|
||||
|
||||
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration((e) => {
|
||||
if (e.affectsConfiguration('npm.exclude') || e.affectsConfiguration('npm.autoDetect')) {
|
||||
invalidateTasksCache();
|
||||
if (treeDataProvider) {
|
||||
@@ -32,15 +38,12 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
||||
treeDataProvider.refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
context.subscriptions.push(d);
|
||||
}));
|
||||
|
||||
registerTaskProvider(context);
|
||||
registerHoverProvider(context);
|
||||
|
||||
d = vscode.workspace.onDidChangeTextDocument((e) => {
|
||||
invalidateHoverScriptsCache(e.document);
|
||||
});
|
||||
context.subscriptions.push(d);
|
||||
context.subscriptions.push(vscode.commands.registerCommand('npm.runSelectedScript', runSelectedScript));
|
||||
context.subscriptions.push(addJSONProviders(httpRequest.xhr));
|
||||
|
||||
if (await hasPackageJson()) {
|
||||
vscode.commands.executeCommand('setContext', 'npm:showScriptExplorer', true);
|
||||
@@ -49,6 +52,13 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
||||
context.subscriptions.push(vscode.commands.registerCommand('npm.runScriptFromFolder', selectAndRunScriptFromFolder));
|
||||
}
|
||||
|
||||
function canRunNpmInCurrentWorkspace() {
|
||||
if (vscode.workspace.workspaceFolders) {
|
||||
return vscode.workspace.workspaceFolders.some(f => f.uri.scheme === 'file');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function registerTaskProvider(context: vscode.ExtensionContext): vscode.Disposable | undefined {
|
||||
|
||||
function invalidateScriptCaches() {
|
||||
@@ -32,6 +32,9 @@ export class NpmScriptHoverProvider implements HoverProvider {
|
||||
constructor(context: ExtensionContext) {
|
||||
context.subscriptions.push(commands.registerCommand('npm.runScriptFromHover', this.runScriptFromHover, this));
|
||||
context.subscriptions.push(commands.registerCommand('npm.debugScriptFromHover', this.debugScriptFromHover, this));
|
||||
context.subscriptions.push(workspace.onDidChangeTextDocument((e) => {
|
||||
invalidateHoverScriptsCache(e.document);
|
||||
}));
|
||||
}
|
||||
|
||||
public provideHover(document: TextDocument, position: Position, _token: CancellationToken): ProviderResult<Hover> {
|
||||
|
||||
@@ -71,7 +71,7 @@ http-proxy-agent@^2.1.0:
|
||||
agent-base "4"
|
||||
debug "3.1.0"
|
||||
|
||||
https-proxy-agent@^2.2.3:
|
||||
https-proxy-agent@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
|
||||
integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
|
||||
@@ -96,16 +96,21 @@ ms@2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
|
||||
|
||||
request-light@^0.2.5:
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.2.5.tgz#38a3da7b2e56f7af8cbba57e8a94930ee2380746"
|
||||
integrity sha512-eBEh+GzJAftUnex6tcL6eV2JCifY0+sZMIUpUPOVXbs2nV5hla4ZMmO3icYKGuGVuQ2zHE9evh4OrRcH4iyYYw==
|
||||
request-light@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.4.0.tgz#c6b91ef00b18cb0de75d2127e55b3a2c9f7f90f9"
|
||||
integrity sha512-fimzjIVw506FBZLspTAXHdpvgvQebyjpNyLRd0e6drPPRq7gcrROeGWRyF81wLqFg5ijPgnOQbmfck5wdTqpSA==
|
||||
dependencies:
|
||||
http-proxy-agent "^2.1.0"
|
||||
https-proxy-agent "^2.2.3"
|
||||
vscode-nls "^4.1.1"
|
||||
https-proxy-agent "^2.2.4"
|
||||
vscode-nls "^4.1.2"
|
||||
|
||||
vscode-nls@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c"
|
||||
integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A==
|
||||
|
||||
vscode-nls@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167"
|
||||
integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw==
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"git": {
|
||||
"name": "Microsoft/vscode-mssql",
|
||||
"repositoryUrl": "https://github.com/Microsoft/vscode-mssql",
|
||||
"commitHash": "37a22725186b5b481b2882a78c7b9fe024c13946"
|
||||
"commitHash": "750d30dc48c4c0317b63bb5f1ed3e71487bb84a1"
|
||||
}
|
||||
},
|
||||
"license": "MIT",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/Microsoft/vscode-mssql/commit/37a22725186b5b481b2882a78c7b9fe024c13946",
|
||||
"version": "https://github.com/Microsoft/vscode-mssql/commit/750d30dc48c4c0317b63bb5f1ed3e71487bb84a1",
|
||||
"name": "SQL",
|
||||
"scopeName": "source.sql",
|
||||
"patterns": [
|
||||
@@ -404,7 +404,7 @@
|
||||
}
|
||||
},
|
||||
"comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.",
|
||||
"match": "(N)?(')(?:[^'\\\\]|\\\\.)*(')",
|
||||
"match": "(N)?(')[^']*(')",
|
||||
"name": "string.quoted.single.sql"
|
||||
},
|
||||
{
|
||||
@@ -437,7 +437,7 @@
|
||||
}
|
||||
},
|
||||
"comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.",
|
||||
"match": "(`)(?:[^`\\\\]|\\\\.)*(`)",
|
||||
"match": "(`)[^`\\\\]*(`)",
|
||||
"name": "string.quoted.other.backtick.sql"
|
||||
},
|
||||
{
|
||||
@@ -470,7 +470,7 @@
|
||||
}
|
||||
},
|
||||
"comment": "this is faster than the next begin/end rule since sub-pattern will match till end-of-line and SQL files tend to have very long lines.",
|
||||
"match": "(\")(?:[^\"#\\\\]|\\\\.)*(\")",
|
||||
"match": "(\")[^\"#]*(\")",
|
||||
"name": "string.quoted.double.sql"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -569,7 +569,7 @@ suite('notebook undo redo', () => {
|
||||
await vscode.commands.executeCommand('workbench.action.closeActiveEditor');
|
||||
});
|
||||
|
||||
test('execute and then undo redo', async function () {
|
||||
test.skip('execute and then undo redo', async function () {
|
||||
const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb'));
|
||||
await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest');
|
||||
|
||||
|
||||
+4
-6
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.47.0",
|
||||
"distro": "9521a559bbdc4e0fb1de84f14deb16cf56e7fdfa",
|
||||
"distro": "6eb887883773e6b33879837bdf8dda3340a9fa75",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
@@ -41,7 +41,7 @@
|
||||
"graceful-fs": "4.2.3",
|
||||
"http-proxy-agent": "^2.1.0",
|
||||
"https-proxy-agent": "^2.2.3",
|
||||
"iconv-lite": "0.6.0",
|
||||
"iconv-lite-umd": "0.6.3",
|
||||
"jschardet": "2.1.1",
|
||||
"keytar": "^5.5.0",
|
||||
"minimist": "^1.2.5",
|
||||
@@ -49,7 +49,7 @@
|
||||
"native-keymap": "2.1.2",
|
||||
"native-watchdog": "1.3.0",
|
||||
"node-pty": "0.10.0-beta8",
|
||||
"semver-umd": "^5.5.6",
|
||||
"semver-umd": "^5.5.7",
|
||||
"spdlog": "^0.11.1",
|
||||
"sudo-prompt": "9.1.1",
|
||||
"v8-inspect-profiler": "^0.0.20",
|
||||
@@ -74,7 +74,6 @@
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/graceful-fs": "4.1.2",
|
||||
"@types/http-proxy-agent": "^2.0.1",
|
||||
"@types/iconv-lite": "0.0.1",
|
||||
"@types/keytar": "^4.4.0",
|
||||
"@types/minimist": "^1.2.0",
|
||||
"@types/mocha": "2.2.39",
|
||||
@@ -94,12 +93,11 @@
|
||||
"asar": "^0.14.0",
|
||||
"chromium-pickle-js": "^0.2.0",
|
||||
"copy-webpack-plugin": "^4.5.2",
|
||||
"coveralls": "^2.11.11",
|
||||
"cson-parser": "^1.3.3",
|
||||
"css-loader": "^3.2.0",
|
||||
"debounce": "^1.0.0",
|
||||
"deemon": "^1.4.0",
|
||||
"electron": "7.3.1",
|
||||
"electron": "8.3.3",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-plugin-jsdoc": "^19.1.0",
|
||||
"event-stream": "3.3.4",
|
||||
|
||||
+2
-2
@@ -8,12 +8,12 @@
|
||||
"graceful-fs": "4.2.3",
|
||||
"http-proxy-agent": "^2.1.0",
|
||||
"https-proxy-agent": "^2.2.3",
|
||||
"iconv-lite": "0.6.0",
|
||||
"iconv-lite-umd": "0.6.3",
|
||||
"jschardet": "2.1.1",
|
||||
"minimist": "^1.2.5",
|
||||
"native-watchdog": "1.3.0",
|
||||
"node-pty": "0.10.0-beta8",
|
||||
"semver-umd": "^5.5.6",
|
||||
"semver-umd": "^5.5.7",
|
||||
"spdlog": "^0.11.1",
|
||||
"vscode-nsfw": "1.2.8",
|
||||
"vscode-oniguruma": "1.3.1",
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
"name": "vscode-web",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"semver-umd": "^5.5.6",
|
||||
"semver-umd": "^5.5.7",
|
||||
"iconv-lite-umd": "0.6.3",
|
||||
"jschardet": "2.1.1",
|
||||
"vscode-oniguruma": "1.3.1",
|
||||
"vscode-textmate": "5.1.1",
|
||||
"xterm": "4.7.0-beta.3",
|
||||
|
||||
+14
-4
@@ -2,10 +2,20 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
semver-umd@^5.5.6:
|
||||
version "5.5.6"
|
||||
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.6.tgz#1d185bbd2caec825c564b54907cd09e14083f228"
|
||||
integrity sha512-6ARYXVi4Y4VO5HfyCjT/6xyykBtJwEXSGQ8ON4UPQSFOjZUDsbAE0J614QcBBsLTTyQMEqvsXN804vAqpydjzw==
|
||||
iconv-lite-umd@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite-umd/-/iconv-lite-umd-0.6.3.tgz#61307cab8ac29939992d0724d3ab8799467f0e97"
|
||||
integrity sha512-fQ/8XE8reiCZ6t+SX4tX6/tQdV4tThJZv5qtMe5Sk+IWsExz0S2Zd+GiBS5IEPgDxnsmiJSpH67+qzN3FT4lKw==
|
||||
|
||||
jschardet@2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184"
|
||||
integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q==
|
||||
|
||||
semver-umd@^5.5.7:
|
||||
version "5.5.7"
|
||||
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.7.tgz#966beb5e96c7da6fbf09c3da14c2872d6836c528"
|
||||
integrity sha512-XgjPNlD0J6aIc8xoTN6GQGwWc2Xg0kq8NzrqMVuKG/4Arl6ab1F8+Am5Y/XKKCR+FceFr2yN/Uv5ZJBhRyRqKg==
|
||||
|
||||
vscode-oniguruma@1.3.1:
|
||||
version "1.3.1"
|
||||
|
||||
+8
-15
@@ -176,12 +176,10 @@ https-proxy-agent@^2.2.3:
|
||||
agent-base "^4.3.0"
|
||||
debug "^3.1.0"
|
||||
|
||||
iconv-lite@0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.0.tgz#66a93b80df0bd05d2a43a7426296b7f91073f125"
|
||||
integrity sha512-43ZpGYZ9QtuutX5l6WC1DSO8ane9N+Ct5qPLF2OV7vM9abM69gnAbVkh66ibaZd3aOGkoP1ZmringlKhLBkw2Q==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3"
|
||||
iconv-lite-umd@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite-umd/-/iconv-lite-umd-0.6.3.tgz#61307cab8ac29939992d0724d3ab8799467f0e97"
|
||||
integrity sha512-fQ/8XE8reiCZ6t+SX4tX6/tQdV4tThJZv5qtMe5Sk+IWsExz0S2Zd+GiBS5IEPgDxnsmiJSpH67+qzN3FT4lKw==
|
||||
|
||||
ip@^1.1.5:
|
||||
version "1.1.5"
|
||||
@@ -300,15 +298,10 @@ readdirp@~3.2.0:
|
||||
dependencies:
|
||||
picomatch "^2.0.4"
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
semver-umd@^5.5.6:
|
||||
version "5.5.6"
|
||||
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.6.tgz#1d185bbd2caec825c564b54907cd09e14083f228"
|
||||
integrity sha512-6ARYXVi4Y4VO5HfyCjT/6xyykBtJwEXSGQ8ON4UPQSFOjZUDsbAE0J614QcBBsLTTyQMEqvsXN804vAqpydjzw==
|
||||
semver-umd@^5.5.7:
|
||||
version "5.5.7"
|
||||
resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.7.tgz#966beb5e96c7da6fbf09c3da14c2872d6836c528"
|
||||
integrity sha512-XgjPNlD0J6aIc8xoTN6GQGwWc2Xg0kq8NzrqMVuKG/4Arl6ab1F8+Am5Y/XKKCR+FceFr2yN/Uv5ZJBhRyRqKg==
|
||||
|
||||
semver@^5.3.0:
|
||||
version "5.6.0"
|
||||
|
||||
@@ -24,6 +24,7 @@ parts:
|
||||
plugin: dump
|
||||
source: .
|
||||
stage-packages:
|
||||
- ibus-gtk3
|
||||
- fcitx-frontend-gtk3
|
||||
- gvfs-libs
|
||||
- libasound2
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// @ts-check
|
||||
/** @typedef {import('../../src/vs/workbench/workbench.web.api').IWorkbenchConstructionOptions} WebConfiguration **/
|
||||
|
||||
const http = require('http');
|
||||
const url = require('url');
|
||||
@@ -62,15 +61,34 @@ const exists = (path) => util.promisify(fs.exists)(path);
|
||||
const readFile = (path) => util.promisify(fs.readFile)(path);
|
||||
const CharCode_PC = '%'.charCodeAt(0);
|
||||
|
||||
function toStaticExtensionUri(path) {
|
||||
return { scheme: SCHEME, authority: AUTHORITY, path: `/static-extension/${path}` };
|
||||
}
|
||||
|
||||
async function initialize() {
|
||||
const extensionFolders = await util.promisify(fs.readdir)(EXTENSIONS_ROOT);
|
||||
|
||||
const staticExtensions = [];
|
||||
|
||||
const builtinExtensions = [];
|
||||
const webpackConfigs = [];
|
||||
|
||||
await Promise.all(extensionFolders.map(async extensionFolder => {
|
||||
const packageJSONPath = path.join(EXTENSIONS_ROOT, extensionFolder, 'package.json');
|
||||
const children = await util.promisify(fs.readdir)(EXTENSIONS_ROOT, { withFileTypes: true });
|
||||
const folders = children.filter(c => !c.isFile());
|
||||
await Promise.all(folders.map(async folder => {
|
||||
const folderName = folder.name;
|
||||
const extensionPath = path.join(EXTENSIONS_ROOT, folderName);
|
||||
|
||||
let children = [];
|
||||
try {
|
||||
children = await util.promisify(fs.readdir)(extensionPath);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return;
|
||||
}
|
||||
|
||||
const readme = children.filter(child => /^readme(\.txt|\.md|)$/i.test(child))[0];
|
||||
const readmeUrl = readme ? toStaticExtensionUri(path.join(extensionPath, readme)) : undefined;
|
||||
const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0];
|
||||
const changelogUrl = changelog ? toStaticExtensionUri(path.join(extensionPath, changelog)) : undefined;
|
||||
|
||||
const packageJSONPath = path.join(EXTENSIONS_ROOT, folderName, 'package.json');
|
||||
if (await exists(packageJSONPath)) {
|
||||
try {
|
||||
const packageJSON = JSON.parse((await readFile(packageJSONPath)).toString());
|
||||
@@ -82,7 +100,7 @@ async function initialize() {
|
||||
packageJSON.main = packageJSON.browser;
|
||||
|
||||
const webpackConfigLocations = await util.promisify(glob)(
|
||||
path.join(EXTENSIONS_ROOT, extensionFolder, '**', 'extension-browser.webpack.config.js'),
|
||||
path.join(EXTENSIONS_ROOT, folderName, '**', 'extension-browser.webpack.config.js'),
|
||||
{ ignore: ['**/node_modules'] }
|
||||
);
|
||||
|
||||
@@ -99,31 +117,16 @@ async function initialize() {
|
||||
}
|
||||
}
|
||||
|
||||
const packageNlsPath = path.join(EXTENSIONS_ROOT, extensionFolder, 'package.nls.json');
|
||||
if (await exists(packageNlsPath)) {
|
||||
const packageNls = JSON.parse((await readFile(packageNlsPath)).toString());
|
||||
const translate = (obj) => {
|
||||
for (let key in obj) {
|
||||
const val = obj[key];
|
||||
if (Array.isArray(val)) {
|
||||
val.forEach(translate);
|
||||
} else if (val && typeof val === 'object') {
|
||||
translate(val);
|
||||
} else if (typeof val === 'string' && val.charCodeAt(0) === CharCode_PC && val.charCodeAt(val.length - 1) === CharCode_PC) {
|
||||
const translated = packageNls[val.substr(1, val.length - 2)];
|
||||
if (translated) {
|
||||
obj[key] = translated;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
translate(packageJSON);
|
||||
}
|
||||
packageJSON.extensionKind = ['web']; // enable for Web
|
||||
staticExtensions.push({
|
||||
|
||||
const packageNLSPath = path.join(folderName, 'package.nls.json');
|
||||
const packageNLSExists = await exists(path.join(EXTENSIONS_ROOT, packageNLSPath));
|
||||
builtinExtensions.push({
|
||||
packageJSON,
|
||||
extensionLocation: { scheme: SCHEME, authority: AUTHORITY, path: `/static-extension/${extensionFolder}` },
|
||||
isBuiltin: true
|
||||
location: toStaticExtensionUri(folderName),
|
||||
packageNLSUrl: packageNLSExists ? toStaticExtensionUri(packageNLSPath) : undefined,
|
||||
readmeUrl,
|
||||
changelogUrl
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
@@ -139,7 +142,7 @@ async function initialize() {
|
||||
reject();
|
||||
} else {
|
||||
console.log(stats.toString());
|
||||
resolve(staticExtensions);
|
||||
resolve(builtinExtensions);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -149,14 +152,14 @@ async function initialize() {
|
||||
reject();
|
||||
} else {
|
||||
console.log(stats.toString());
|
||||
resolve(staticExtensions);
|
||||
resolve(builtinExtensions);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const staticExtensionsPromise = initialize();
|
||||
const builtinExtensionsPromise = initialize();
|
||||
|
||||
const mapCallbackUriToRequestId = new Map();
|
||||
|
||||
@@ -262,14 +265,9 @@ async function handleRoot(req, res) {
|
||||
}
|
||||
}
|
||||
|
||||
const staticExtensions = await staticExtensionsPromise;
|
||||
/** @type {WebConfiguration} */
|
||||
const webConfig = {
|
||||
staticExtensions: staticExtensions,
|
||||
};
|
||||
const builtinExtensions = await builtinExtensionsPromise;
|
||||
|
||||
const webConfigJSON = escapeAttribute(JSON.stringify({
|
||||
...webConfig,
|
||||
folderUri: ghPath
|
||||
? { scheme: 'github', authority: 'HEAD', path: ghPath }
|
||||
: { scheme: 'memfs', path: `/sample-folder` },
|
||||
@@ -277,6 +275,7 @@ async function handleRoot(req, res) {
|
||||
|
||||
const data = (await util.promisify(fs.readFile)(WEB_MAIN)).toString()
|
||||
.replace('{{WORKBENCH_WEB_CONFIGURATION}}', () => webConfigJSON) // use a replace function to avoid that regexp replace patterns ($&, $0, ...) are applied
|
||||
.replace('{{WORKBENCH_BUILTIN_EXTENSIONS}}', () => escapeAttribute(JSON.stringify(builtinExtensions)))
|
||||
.replace('{{WEBVIEW_ENDPOINT}}', '')
|
||||
.replace('{{REMOTE_USER_DATA_URI}}', '');
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ VSCODE_PATH="$(dirname "$(dirname "$(realpath "$0")")")"
|
||||
ELECTRON="$VSCODE_PATH/$NAME.exe"
|
||||
if grep -qi Microsoft /proc/version; then
|
||||
# in a wsl shell
|
||||
WSL_BUILD=$(uname -r | sed -E 's/^[0-9.]+-([0-9]+)-Microsoft.*|([0-9]+).([0-9]+).([0-9]+)-microsoft-standard.*|.*/\1\2\3\4/')
|
||||
WSL_BUILD=$(uname -r | sed -E 's/^[0-9.]+-([0-9]+)-Microsoft.*|([0-9]+).([0-9]+).([0-9]+)-microsoft.*|.*/\1\2\3\4/')
|
||||
if [ -z "$WSL_BUILD" ]; then
|
||||
WSL_BUILD=0
|
||||
fi
|
||||
@@ -30,17 +30,9 @@ if grep -qi Microsoft /proc/version; then
|
||||
# use the Remote WSL extension if installed
|
||||
WSL_EXT_ID="ms-vscode-remote.remote-wsl"
|
||||
|
||||
if [ $WSL_BUILD -ge 41955 -a $WSL_BUILD -lt 41959 ]; then
|
||||
# WSL2 workaround for https://github.com/microsoft/WSL/issues/4337
|
||||
CWD="$(pwd)"
|
||||
cd "$VSCODE_PATH"
|
||||
cmd.exe /C ".\\bin\\$APP_NAME.cmd --locate-extension $WSL_EXT_ID >%TEMP%\\remote-wsl-loc.txt"
|
||||
WSL_EXT_WLOC=$(cmd.exe /C type %TEMP%\\remote-wsl-loc.txt)
|
||||
cd "$CWD"
|
||||
else
|
||||
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --locate-extension $WSL_EXT_ID >/tmp/remote-wsl-loc.txt 2>/dev/null
|
||||
WSL_EXT_WLOC=$(cat /tmp/remote-wsl-loc.txt)
|
||||
fi
|
||||
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --locate-extension $WSL_EXT_ID >/tmp/remote-wsl-loc.txt 2>/dev/null
|
||||
WSL_EXT_WLOC=$(cat /tmp/remote-wsl-loc.txt)
|
||||
|
||||
if [ -n "$WSL_EXT_WLOC" ]; then
|
||||
# replace \r\n with \n in WSL_EXT_WLOC
|
||||
WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh
|
||||
|
||||
@@ -43,8 +43,8 @@ if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
:: Tests in the extension host
|
||||
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-notebook-tests\test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-notebook-tests --extensionTestsPath=%~dp0\..\extensions\vscode-notebook-tests\out --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
:: call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-notebook-tests\test --enable-proposed-api=vscode.vscode-notebook-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-notebook-tests --extensionTestsPath=%~dp0\..\extensions\vscode-notebook-tests\out --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||
:: if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --crash-reporter-directory=%VSCODECRASHDIR% --no-cached-data --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR%
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
@@ -39,7 +39,6 @@ const JSCHARDET_TO_ICONV_ENCODINGS: { [name: string]: string } = {
|
||||
|
||||
const UTF8 = 'utf8';
|
||||
|
||||
|
||||
export async function resolveTerminalEncoding(verbose?: boolean): Promise<string> {
|
||||
let rawEncodingPromise: Promise<string>;
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@ import { ISerializableContextMenuItem, CONTEXT_MENU_CLOSE_CHANNEL, CONTEXT_MENU_
|
||||
export function registerContextMenuListener(): void {
|
||||
ipcMain.on(CONTEXT_MENU_CHANNEL, (event: IpcMainEvent, contextMenuId: number, items: ISerializableContextMenuItem[], onClickChannel: string, options?: IPopupOptions) => {
|
||||
const menu = createMenu(event, onClickChannel, items);
|
||||
const window = BrowserWindow.fromWebContents(event.sender);
|
||||
|
||||
menu.popup({
|
||||
window: BrowserWindow.fromWebContents(event.sender),
|
||||
window: window ? window : undefined,
|
||||
x: options ? options.x : undefined,
|
||||
y: options ? options.y : undefined,
|
||||
positioningItem: options ? options.positioningItem : undefined,
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
<!-- Workarounds/Hacks (remote user data uri) -->
|
||||
<meta id="vscode-remote-user-data-uri" data-settings="{{REMOTE_USER_DATA_URI}}">
|
||||
|
||||
<!-- Builtin Extensions (running out of sources) -->
|
||||
<meta id="vscode-workbench-builtin-extensions" data-settings="{{WORKBENCH_BUILTIN_EXTENSIONS}}">
|
||||
|
||||
<!-- Workbench Icon/Manifest/CSS -->
|
||||
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
@@ -34,6 +37,8 @@
|
||||
'xterm-addon-unicode11': `${window.location.origin}/static/remote/web/node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
||||
'xterm-addon-webgl': `${window.location.origin}/static/remote/web/node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
||||
'semver-umd': `${window.location.origin}/static/remote/web/node_modules/semver-umd/lib/semver-umd.js`,
|
||||
'iconv-lite-umd': `${window.location.origin}/static/remote/web/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
||||
'jschardet': `${window.location.origin}/static/remote/web/node_modules/jschardet/dist/jschardet.min.js`,
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
<!-- Workarounds/Hacks (remote user data uri) -->
|
||||
<meta id="vscode-remote-user-data-uri" data-settings="{{REMOTE_USER_DATA_URI}}">
|
||||
|
||||
<!-- Builtin Extensions (running out of sources) -->
|
||||
<meta id="vscode-workbench-builtin-extensions" data-settings="{{WORKBENCH_BUILTIN_EXTENSIONS}}">
|
||||
|
||||
<!-- Workbench Icon/Manifest/CSS -->
|
||||
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
@@ -20,6 +23,8 @@
|
||||
|
||||
<!-- Prefetch to avoid waterfall -->
|
||||
<link rel="prefetch" href="./static/node_modules/semver-umd/lib/semver-umd.js">
|
||||
<link rel="prefetch" href="./static/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js">
|
||||
<link rel="prefetch" href="./static/node_modules/jschardet/dist/jschardet.min.js">
|
||||
</head>
|
||||
|
||||
<body aria-label="">
|
||||
@@ -38,6 +43,8 @@
|
||||
'xterm-addon-unicode11': `${window.location.origin}/static/node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
||||
'xterm-addon-webgl': `${window.location.origin}/static/node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
||||
'semver-umd': `${window.location.origin}/static/node_modules/semver-umd/lib/semver-umd.js`,
|
||||
'iconv-lite-umd': `${window.location.origin}/static/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
||||
'jschardet': `${window.location.origin}/static/node_modules/jschardet/dist/jschardet.min.js`,
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { Command, EditorCommand, ICommandOptions, registerEditorCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { Command, EditorCommand, ICommandOptions, registerEditorCommand, MultiCommand, UndoCommand, RedoCommand, SelectAllCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { ColumnSelection, IColumnSelectResult } from 'vs/editor/common/controller/cursorColumnSelection';
|
||||
import { CursorState, EditOperationType, IColumnSelectData, PartialCursorState } from 'vs/editor/common/controller/cursorCommon';
|
||||
@@ -20,7 +20,6 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import { Handler, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { VerticalRevealType } from 'vs/editor/common/view/viewEvents';
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -276,6 +275,48 @@ export namespace RevealLine_ {
|
||||
};
|
||||
}
|
||||
|
||||
abstract class EditorOrNativeTextInputCommand {
|
||||
|
||||
constructor(target: MultiCommand) {
|
||||
// 1. handle case when focus is in editor.
|
||||
target.addImplementation(10000, (accessor: ServicesAccessor, args: any) => {
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
|
||||
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
||||
this.runEditorCommand(accessor, focusedEditor, args);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// 2. handle case when focus is in some other `input` / `textarea`.
|
||||
target.addImplementation(1000, (accessor: ServicesAccessor, args: any) => {
|
||||
// Only if focused on an element that allows for entering text
|
||||
const activeElement = <HTMLElement>document.activeElement;
|
||||
if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) {
|
||||
this.runDOMCommand();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// 3. (default) handle case when focus is somewhere else.
|
||||
target.addImplementation(0, (accessor: ServicesAccessor, args: any) => {
|
||||
// Redirecting to active editor
|
||||
const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor();
|
||||
if (activeEditor) {
|
||||
activeEditor.focus();
|
||||
this.runEditorCommand(accessor, activeEditor, args);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public abstract runDOMCommand(): void;
|
||||
public abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void;
|
||||
}
|
||||
|
||||
export namespace CoreNavigationCommands {
|
||||
|
||||
class BaseMoveToCommand extends CoreEditorCommand {
|
||||
@@ -1594,25 +1635,32 @@ export namespace CoreNavigationCommands {
|
||||
}
|
||||
});
|
||||
|
||||
export const SelectAll: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {
|
||||
export const SelectAll = new class extends EditorOrNativeTextInputCommand {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'selectAll',
|
||||
precondition: undefined
|
||||
});
|
||||
super(SelectAllCommand);
|
||||
}
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('selectAll');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
|
||||
const viewModel = editor._getViewModel();
|
||||
if (!viewModel) {
|
||||
// the editor has no view => has no cursors
|
||||
return;
|
||||
}
|
||||
this.runCoreEditorCommand(viewModel, args);
|
||||
}
|
||||
|
||||
public runCoreEditorCommand(viewModel: IViewModel, args: any): void {
|
||||
viewModel.model.pushStackElement();
|
||||
viewModel.setCursorStates(
|
||||
args.source,
|
||||
'keyboard',
|
||||
CursorChangeReason.Explicit,
|
||||
[
|
||||
CursorMoveCommands.selectAll(viewModel, viewModel.getPrimaryCursorState())
|
||||
]
|
||||
);
|
||||
}
|
||||
});
|
||||
}();
|
||||
|
||||
export const SetSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {
|
||||
constructor() {
|
||||
@@ -1655,97 +1703,6 @@ registerColumnSelection(CoreNavigationCommands.CursorColumnSelectPageUp.id, KeyM
|
||||
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectDown.id, KeyMod.Shift | KeyCode.DownArrow);
|
||||
registerColumnSelection(CoreNavigationCommands.CursorColumnSelectPageDown.id, KeyMod.Shift | KeyCode.PageDown);
|
||||
|
||||
/**
|
||||
* A command that will:
|
||||
* 1. invoke a command on the focused editor.
|
||||
* 2. otherwise, invoke a browser built-in command on the `activeElement`.
|
||||
* 3. otherwise, invoke a command on the workbench active editor.
|
||||
*/
|
||||
abstract class EditorOrNativeTextInputCommand extends Command {
|
||||
|
||||
public runCommand(accessor: ServicesAccessor, args: any): void {
|
||||
|
||||
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
||||
return this.runEditorCommand(accessor, focusedEditor, args);
|
||||
}
|
||||
|
||||
// Ignore this action when user is focused on an element that allows for entering text
|
||||
const activeElement = <HTMLElement>document.activeElement;
|
||||
if (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) {
|
||||
return this.runDOMCommand();
|
||||
}
|
||||
|
||||
// Redirecting to active editor
|
||||
const activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor();
|
||||
if (activeEditor) {
|
||||
activeEditor.focus();
|
||||
return this.runEditorCommand(accessor, activeEditor, args);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract runDOMCommand(): void;
|
||||
public abstract runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void;
|
||||
}
|
||||
|
||||
class SelectAllCommand extends EditorOrNativeTextInputCommand {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.action.selectAll',
|
||||
precondition: EditorContextKeys.textInputFocus,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: null,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_A
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarSelectionMenu,
|
||||
group: '1_basic',
|
||||
title: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"),
|
||||
order: 1
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('selectAll', "Select All"),
|
||||
order: 1
|
||||
}]
|
||||
});
|
||||
}
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('selectAll');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {
|
||||
args = args || {};
|
||||
args.source = 'keyboard';
|
||||
CoreNavigationCommands.SelectAll.runEditorCommand(accessor, editor, args);
|
||||
}
|
||||
}
|
||||
|
||||
class UndoCommand extends EditorOrNativeTextInputCommand {
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('undo');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
|
||||
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
|
||||
return;
|
||||
}
|
||||
editor.getModel().undo();
|
||||
}
|
||||
}
|
||||
|
||||
class RedoCommand extends EditorOrNativeTextInputCommand {
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('redo');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
|
||||
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
|
||||
return;
|
||||
}
|
||||
editor.getModel().redo();
|
||||
}
|
||||
}
|
||||
|
||||
function registerCommand<T extends Command>(command: T): T {
|
||||
command.register();
|
||||
return command;
|
||||
@@ -1881,53 +1838,35 @@ export namespace CoreEditingCommands {
|
||||
}
|
||||
});
|
||||
|
||||
export const Undo: UndoCommand = registerCommand(new UndoCommand({
|
||||
id: 'undo',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '1_do',
|
||||
title: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"),
|
||||
order: 1
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('undo', "Undo"),
|
||||
order: 1
|
||||
}]
|
||||
}));
|
||||
export const Undo = new class extends EditorOrNativeTextInputCommand {
|
||||
constructor() {
|
||||
super(UndoCommand);
|
||||
}
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('undo');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
|
||||
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
|
||||
return;
|
||||
}
|
||||
editor.getModel().undo();
|
||||
}
|
||||
}();
|
||||
|
||||
export const DefaultUndo: UndoCommand = registerCommand(new UndoCommand({ id: 'default:undo', precondition: EditorContextKeys.writable }));
|
||||
|
||||
export const Redo: RedoCommand = registerCommand(new RedoCommand({
|
||||
id: 'redo',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: {
|
||||
weight: CORE_WEIGHT,
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
|
||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '1_do',
|
||||
title: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"),
|
||||
order: 2
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('redo', "Redo"),
|
||||
order: 1
|
||||
}]
|
||||
}));
|
||||
|
||||
export const DefaultRedo: RedoCommand = registerCommand(new RedoCommand({ id: 'default:redo', precondition: EditorContextKeys.writable }));
|
||||
export const Redo = new class extends EditorOrNativeTextInputCommand {
|
||||
constructor() {
|
||||
super(RedoCommand);
|
||||
}
|
||||
public runDOMCommand(): void {
|
||||
document.execCommand('redo');
|
||||
}
|
||||
public runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void {
|
||||
if (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {
|
||||
return;
|
||||
}
|
||||
editor.getModel().redo();
|
||||
}
|
||||
}();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1956,8 +1895,6 @@ class EditorHandlerCommand extends Command {
|
||||
}
|
||||
}
|
||||
|
||||
registerCommand(new SelectAllCommand());
|
||||
|
||||
function registerOverwritableCommand(handlerId: string, description?: ICommandHandlerDescription): void {
|
||||
registerCommand(new EditorHandlerCommand('default:' + handlerId, handlerId));
|
||||
registerCommand(new EditorHandlerCommand(handlerId, handlerId, description));
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { IPosition } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { illegalArgument } from 'vs/base/common/errors';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -17,11 +18,13 @@ import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IConstructorSignature1, ServicesAccessor as InstantiationServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IKeybindings, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IKeybindings, KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { withNullAsUndefined, assertType } from 'vs/base/common/types';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
|
||||
|
||||
export type ServicesAccessor = InstantiationServicesAccessor;
|
||||
@@ -139,6 +142,66 @@ export abstract class Command {
|
||||
|
||||
//#endregion Command
|
||||
|
||||
//#region MultiplexingCommand
|
||||
|
||||
/**
|
||||
* Potential override for a command.
|
||||
*
|
||||
* @return `true` if the command was successfully run. This stops other overrides from being executed.
|
||||
*/
|
||||
export type CommandImplementation = (accessor: ServicesAccessor, args: unknown) => boolean;
|
||||
|
||||
export class MultiCommand extends Command {
|
||||
|
||||
private readonly _implementations: [number, CommandImplementation][] = [];
|
||||
|
||||
/**
|
||||
* A higher priority gets to be looked at first
|
||||
*/
|
||||
public addImplementation(priority: number, implementation: CommandImplementation): IDisposable {
|
||||
this._implementations.push([priority, implementation]);
|
||||
this._implementations.sort((a, b) => b[0] - a[0]);
|
||||
return {
|
||||
dispose: () => {
|
||||
for (let i = 0; i < this._implementations.length; i++) {
|
||||
if (this._implementations[i][1] === implementation) {
|
||||
this._implementations.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public runCommand(accessor: ServicesAccessor, args: any): void | Promise<void> {
|
||||
for (const impl of this._implementations) {
|
||||
if (impl[1](accessor, args)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
/**
|
||||
* A command that delegates to another command's implementation.
|
||||
*
|
||||
* This lets different commands be registered but share the same implementation
|
||||
*/
|
||||
export class ProxyCommand extends Command {
|
||||
constructor(
|
||||
private readonly command: Command,
|
||||
opts: ICommandOptions
|
||||
) {
|
||||
super(opts);
|
||||
}
|
||||
|
||||
public runCommand(accessor: ServicesAccessor, args: any): void | Promise<void> {
|
||||
return this.command.runCommand(accessor, args);
|
||||
}
|
||||
}
|
||||
|
||||
//#region EditorCommand
|
||||
|
||||
export interface IContributionCommandOptions<T> extends ICommandOptions {
|
||||
@@ -379,8 +442,10 @@ export function registerEditorCommand<T extends EditorCommand>(editorCommand: T)
|
||||
return editorCommand;
|
||||
}
|
||||
|
||||
export function registerEditorAction(ctor: { new(): EditorAction; }): void {
|
||||
EditorContributionRegistry.INSTANCE.registerEditorAction(new ctor());
|
||||
export function registerEditorAction<T extends EditorAction>(ctor: { new(): T; }): T {
|
||||
const action = new ctor();
|
||||
EditorContributionRegistry.INSTANCE.registerEditorAction(action);
|
||||
return action;
|
||||
}
|
||||
|
||||
export function registerInstantiatedEditorAction(editorAction: EditorAction): void {
|
||||
@@ -475,3 +540,75 @@ class EditorContributionRegistry {
|
||||
|
||||
}
|
||||
Registry.add(Extensions.EditorCommonContributions, EditorContributionRegistry.INSTANCE);
|
||||
|
||||
function registerCommand<T extends Command>(command: T): T {
|
||||
command.register();
|
||||
return command;
|
||||
}
|
||||
|
||||
export const UndoCommand = registerCommand(new MultiCommand({
|
||||
id: 'undo',
|
||||
precondition: undefined,
|
||||
kbOpts: {
|
||||
weight: KeybindingWeight.EditorCore,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Z
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '1_do',
|
||||
title: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, "&&Undo"),
|
||||
order: 1
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('undo', "Undo"),
|
||||
order: 1
|
||||
}]
|
||||
}));
|
||||
|
||||
registerCommand(new ProxyCommand(UndoCommand, { id: 'default:undo', precondition: undefined }));
|
||||
|
||||
export const RedoCommand = registerCommand(new MultiCommand({
|
||||
id: 'redo',
|
||||
precondition: undefined,
|
||||
kbOpts: {
|
||||
weight: KeybindingWeight.EditorCore,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_Y,
|
||||
secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z],
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '1_do',
|
||||
title: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, "&&Redo"),
|
||||
order: 2
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('redo', "Redo"),
|
||||
order: 1
|
||||
}]
|
||||
}));
|
||||
|
||||
registerCommand(new ProxyCommand(RedoCommand, { id: 'default:redo', precondition: undefined }));
|
||||
|
||||
export const SelectAllCommand = registerCommand(new MultiCommand({
|
||||
id: 'editor.action.selectAll',
|
||||
precondition: undefined,
|
||||
kbOpts: {
|
||||
weight: KeybindingWeight.EditorCore,
|
||||
kbExpr: null,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_A
|
||||
},
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarSelectionMenu,
|
||||
group: '1_basic',
|
||||
title: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, "&&Select All"),
|
||||
order: 1
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('selectAll', "Select All"),
|
||||
order: 1
|
||||
}]
|
||||
}));
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { CoreEditorCommand, CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommands';
|
||||
import { CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommands';
|
||||
import { IEditorMouseEvent, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser';
|
||||
import { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
@@ -35,8 +35,6 @@ export interface IMouseDispatchData {
|
||||
}
|
||||
|
||||
export interface ICommandDelegate {
|
||||
executeEditorCommand(editorCommand: CoreEditorCommand, args: any): void;
|
||||
|
||||
paste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void;
|
||||
type(text: string): void;
|
||||
replacePreviousChar(text: string, replaceCharCnt: number): void;
|
||||
@@ -64,11 +62,6 @@ export class ViewController {
|
||||
this.commandDelegate = commandDelegate;
|
||||
}
|
||||
|
||||
private _execMouseCommand(editorCommand: CoreEditorCommand, args: any): void {
|
||||
args.source = 'mouse';
|
||||
this.commandDelegate.executeEditorCommand(editorCommand, args);
|
||||
}
|
||||
|
||||
public paste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void {
|
||||
this.commandDelegate.paste(text, pasteOnNewLine, multicursorText, mode);
|
||||
}
|
||||
@@ -94,7 +87,7 @@ export class ViewController {
|
||||
}
|
||||
|
||||
public setSelection(modelSelection: Selection): void {
|
||||
this.commandDelegate.executeEditorCommand(CoreNavigationCommands.SetSelection, {
|
||||
CoreNavigationCommands.SetSelection.runCoreEditorCommand(this.viewModel, {
|
||||
source: 'keyboard',
|
||||
selection: modelSelection
|
||||
});
|
||||
@@ -214,22 +207,24 @@ export class ViewController {
|
||||
private _usualArgs(viewPosition: Position) {
|
||||
viewPosition = this._validateViewColumn(viewPosition);
|
||||
return {
|
||||
source: 'mouse',
|
||||
position: this._convertViewToModelPosition(viewPosition),
|
||||
viewPosition: viewPosition
|
||||
};
|
||||
}
|
||||
|
||||
public moveTo(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.MoveTo, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.MoveTo.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _moveToSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.MoveToSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.MoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _columnSelect(viewPosition: Position, mouseColumn: number, doColumnSelect: boolean): void {
|
||||
viewPosition = this._validateViewColumn(viewPosition);
|
||||
this._execMouseCommand(CoreNavigationCommands.ColumnSelect, {
|
||||
CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(this.viewModel, {
|
||||
source: 'mouse',
|
||||
position: this._convertViewToModelPosition(viewPosition),
|
||||
viewPosition: viewPosition,
|
||||
mouseColumn: mouseColumn,
|
||||
@@ -239,7 +234,8 @@ export class ViewController {
|
||||
|
||||
private _createCursor(viewPosition: Position, wholeLine: boolean): void {
|
||||
viewPosition = this._validateViewColumn(viewPosition);
|
||||
this._execMouseCommand(CoreNavigationCommands.CreateCursor, {
|
||||
CoreNavigationCommands.CreateCursor.runCoreEditorCommand(this.viewModel, {
|
||||
source: 'mouse',
|
||||
position: this._convertViewToModelPosition(viewPosition),
|
||||
viewPosition: viewPosition,
|
||||
wholeLine: wholeLine
|
||||
@@ -247,39 +243,39 @@ export class ViewController {
|
||||
}
|
||||
|
||||
private _lastCursorMoveToSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LastCursorMoveToSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LastCursorMoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _wordSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.WordSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.WordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _wordSelectDrag(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.WordSelectDrag, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.WordSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _lastCursorWordSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LastCursorWordSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LastCursorWordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _lineSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LineSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _lineSelectDrag(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LineSelectDrag, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _lastCursorLineSelect(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LastCursorLineSelect, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LastCursorLineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _lastCursorLineSelectDrag(viewPosition: Position): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.LastCursorLineSelectDrag, this._usualArgs(viewPosition));
|
||||
CoreNavigationCommands.LastCursorLineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition));
|
||||
}
|
||||
|
||||
private _selectAll(): void {
|
||||
this._execMouseCommand(CoreNavigationCommands.SelectAll, {});
|
||||
CoreNavigationCommands.SelectAll.runCoreEditorCommand(this.viewModel, { source: 'mouse' });
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
|
||||
@@ -15,7 +15,6 @@ import { hash } from 'vs/base/common/hash';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { Configuration } from 'vs/editor/browser/config/configuration';
|
||||
import { CoreEditorCommand } from 'vs/editor/browser/controller/coreCommands';
|
||||
import * as editorBrowser from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorExtensionsRegistry, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
@@ -1552,9 +1551,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
let commandDelegate: ICommandDelegate;
|
||||
if (this.isSimpleWidget) {
|
||||
commandDelegate = {
|
||||
executeEditorCommand: (editorCommand: CoreEditorCommand, args: any): void => {
|
||||
editorCommand.runCoreEditorCommand(viewModel, args);
|
||||
},
|
||||
paste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {
|
||||
this._paste('keyboard', text, pasteOnNewLine, multicursorText, mode);
|
||||
},
|
||||
@@ -1576,9 +1572,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
};
|
||||
} else {
|
||||
commandDelegate = {
|
||||
executeEditorCommand: (editorCommand: CoreEditorCommand, args: any): void => {
|
||||
editorCommand.runCoreEditorCommand(viewModel, args);
|
||||
},
|
||||
paste: (text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null) => {
|
||||
const payload: editorCommon.PastePayload = { text, pasteOnNewLine, multicursorText, mode };
|
||||
this._commandService.executeCommand(editorCommon.Handler.Paste, payload);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { CopyOptions } from 'vs/editor/browser/controller/textAreaInput';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorAction, IActionOptions, ICommandKeybindingsOptions, registerEditorAction } from 'vs/editor/browser/editorExtensions';
|
||||
import { EditorAction, registerEditorAction, Command, MultiCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
@@ -28,171 +28,111 @@ const supportsCopyWithSyntaxHighlighting = (supportsCopy && !browser.isEdge);
|
||||
// privileges to actually perform the action
|
||||
const supportsPaste = (platform.isNative || (!browser.isChrome && document.queryCommandSupported('paste')));
|
||||
|
||||
type ExecCommand = 'cut' | 'copy' | 'paste';
|
||||
|
||||
abstract class ExecCommandAction extends EditorAction {
|
||||
|
||||
private readonly browserCommand: ExecCommand;
|
||||
|
||||
constructor(browserCommand: ExecCommand, opts: IActionOptions) {
|
||||
super(opts);
|
||||
this.browserCommand = browserCommand;
|
||||
}
|
||||
|
||||
public runCommand(accessor: ServicesAccessor, args: any): void {
|
||||
let focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
||||
focusedEditor.trigger('keyboard', this.id, args);
|
||||
return;
|
||||
}
|
||||
|
||||
document.execCommand(this.browserCommand);
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
editor.focus();
|
||||
document.execCommand(this.browserCommand);
|
||||
}
|
||||
function registerCommand<T extends Command>(command: T): T {
|
||||
command.register();
|
||||
return command;
|
||||
}
|
||||
|
||||
class ExecCommandCutAction extends ExecCommandAction {
|
||||
|
||||
constructor() {
|
||||
let kbOpts: ICommandKeybindingsOptions | undefined = {
|
||||
export const CutAction = supportsCut ? registerCommand(new MultiCommand({
|
||||
id: 'editor.action.clipboardCutAction',
|
||||
precondition: undefined,
|
||||
kbOpts: (
|
||||
// Do not bind cut keybindings in the browser,
|
||||
// since browsers do that for us and it avoids security prompts
|
||||
platform.isNative ? {
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_X,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_X, secondary: [KeyMod.Shift | KeyCode.Delete] },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
};
|
||||
// Do not bind cut keybindings in the browser,
|
||||
} : undefined
|
||||
),
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "Cu&&t"),
|
||||
order: 1
|
||||
}, {
|
||||
menuId: MenuId.EditorContext,
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
title: nls.localize('actions.clipboard.cutLabel', "Cut"),
|
||||
when: EditorContextKeys.writable,
|
||||
order: 1,
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('actions.clipboard.cutLabel', "Cut"),
|
||||
order: 1
|
||||
}]
|
||||
})) : undefined;
|
||||
|
||||
export const CopyAction = supportsCopy ? registerCommand(new MultiCommand({
|
||||
id: 'editor.action.clipboardCopyAction',
|
||||
precondition: undefined,
|
||||
kbOpts: (
|
||||
// Do not bind copy keybindings in the browser,
|
||||
// since browsers do that for us and it avoids security prompts
|
||||
if (!platform.isNative) {
|
||||
kbOpts = undefined;
|
||||
}
|
||||
super('cut', {
|
||||
id: 'editor.action.clipboardCutAction',
|
||||
label: nls.localize('actions.clipboard.cutLabel', "Cut"),
|
||||
alias: 'Cut',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: kbOpts,
|
||||
contextMenuOpts: {
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
order: 1
|
||||
},
|
||||
menuOpts: {
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miCut', comment: ['&& denotes a mnemonic'] }, "Cu&&t"),
|
||||
order: 1
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
if (!editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard);
|
||||
|
||||
if (!emptySelectionClipboard && editor.getSelection().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.run(accessor, editor);
|
||||
}
|
||||
}
|
||||
|
||||
class ExecCommandCopyAction extends ExecCommandAction {
|
||||
|
||||
constructor() {
|
||||
let kbOpts: ICommandKeybindingsOptions | undefined = {
|
||||
platform.isNative ? {
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_C,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_C, secondary: [KeyMod.CtrlCmd | KeyCode.Insert] },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
};
|
||||
// Do not bind copy keybindings in the browser,
|
||||
} : undefined
|
||||
),
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "&&Copy"),
|
||||
order: 2
|
||||
}, {
|
||||
menuId: MenuId.EditorContext,
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
title: nls.localize('actions.clipboard.copyLabel', "Copy"),
|
||||
order: 2,
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('actions.clipboard.copyLabel', "Copy"),
|
||||
order: 1
|
||||
}]
|
||||
})) : undefined;
|
||||
|
||||
export const PasteAction = supportsPaste ? registerCommand(new MultiCommand({
|
||||
id: 'editor.action.clipboardPasteAction',
|
||||
precondition: undefined,
|
||||
kbOpts: (
|
||||
// Do not bind paste keybindings in the browser,
|
||||
// since browsers do that for us and it avoids security prompts
|
||||
if (!platform.isNative) {
|
||||
kbOpts = undefined;
|
||||
}
|
||||
|
||||
super('copy', {
|
||||
id: 'editor.action.clipboardCopyAction',
|
||||
label: nls.localize('actions.clipboard.copyLabel', "Copy"),
|
||||
alias: 'Copy',
|
||||
precondition: undefined,
|
||||
kbOpts: kbOpts,
|
||||
contextMenuOpts: {
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
order: 2
|
||||
},
|
||||
menuOpts: {
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miCopy', comment: ['&& denotes a mnemonic'] }, "&&Copy"),
|
||||
order: 2
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
if (!editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const emptySelectionClipboard = editor.getOption(EditorOption.emptySelectionClipboard);
|
||||
|
||||
if (!emptySelectionClipboard && editor.getSelection().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.run(accessor, editor);
|
||||
}
|
||||
}
|
||||
|
||||
class ExecCommandPasteAction extends ExecCommandAction {
|
||||
|
||||
constructor() {
|
||||
let kbOpts: ICommandKeybindingsOptions | undefined = {
|
||||
platform.isNative ? {
|
||||
kbExpr: EditorContextKeys.textInputFocus,
|
||||
primary: KeyMod.CtrlCmd | KeyCode.KEY_V,
|
||||
win: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.Shift | KeyCode.Insert] },
|
||||
linux: { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, secondary: [KeyMod.Shift | KeyCode.Insert] },
|
||||
weight: KeybindingWeight.EditorContrib
|
||||
};
|
||||
// Do not bind paste keybindings in the browser,
|
||||
// since browsers do that for us and it avoids security prompts
|
||||
if (!platform.isNative) {
|
||||
kbOpts = undefined;
|
||||
}
|
||||
} : undefined
|
||||
),
|
||||
menuOpts: [{
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"),
|
||||
order: 3
|
||||
}, {
|
||||
menuId: MenuId.EditorContext,
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
title: nls.localize('actions.clipboard.pasteLabel', "Paste"),
|
||||
when: EditorContextKeys.writable,
|
||||
order: 3,
|
||||
}, {
|
||||
menuId: MenuId.CommandPalette,
|
||||
group: '',
|
||||
title: nls.localize('actions.clipboard.pasteLabel', "Paste"),
|
||||
order: 1
|
||||
}]
|
||||
})) : undefined;
|
||||
|
||||
super('paste', {
|
||||
id: 'editor.action.clipboardPasteAction',
|
||||
label: nls.localize('actions.clipboard.pasteLabel', "Paste"),
|
||||
alias: 'Paste',
|
||||
precondition: EditorContextKeys.writable,
|
||||
kbOpts: kbOpts,
|
||||
contextMenuOpts: {
|
||||
group: CLIPBOARD_CONTEXT_MENU_GROUP,
|
||||
order: 3
|
||||
},
|
||||
menuOpts: {
|
||||
menuId: MenuId.MenubarEditMenu,
|
||||
group: '2_ccp',
|
||||
title: nls.localize({ key: 'miPaste', comment: ['&& denotes a mnemonic'] }, "&&Paste"),
|
||||
order: 3
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ExecCommandCopyWithSyntaxHighlightingAction extends ExecCommandAction {
|
||||
class ExecCommandCopyWithSyntaxHighlightingAction extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super('copy', {
|
||||
super({
|
||||
id: 'editor.action.clipboardCopyWithSyntaxHighlightingAction',
|
||||
label: nls.localize('actions.clipboard.copyWithSyntaxHighlightingLabel', "Copy With Syntax Highlighting"),
|
||||
alias: 'Copy With Syntax Highlighting',
|
||||
@@ -217,20 +157,48 @@ class ExecCommandCopyWithSyntaxHighlightingAction extends ExecCommandAction {
|
||||
}
|
||||
|
||||
CopyOptions.forceCopyWithSyntaxHighlighting = true;
|
||||
super.run(accessor, editor);
|
||||
editor.focus();
|
||||
document.execCommand('copy');
|
||||
CopyOptions.forceCopyWithSyntaxHighlighting = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (supportsCut) {
|
||||
registerEditorAction(ExecCommandCutAction);
|
||||
}
|
||||
if (supportsCopy) {
|
||||
registerEditorAction(ExecCommandCopyAction);
|
||||
}
|
||||
if (supportsPaste) {
|
||||
registerEditorAction(ExecCommandPasteAction);
|
||||
function registerExecCommandImpl(target: MultiCommand | undefined, browserCommand: 'cut' | 'copy' | 'paste'): void {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. handle case when focus is in editor.
|
||||
target.addImplementation(10000, (accessor: ServicesAccessor, args: any) => {
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
const focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();
|
||||
if (focusedEditor && focusedEditor.hasTextFocus()) {
|
||||
if (browserCommand === 'cut' || browserCommand === 'copy') {
|
||||
// Do not execute if there is no selection and empty selection clipboard is off
|
||||
const emptySelectionClipboard = focusedEditor.getOption(EditorOption.emptySelectionClipboard);
|
||||
const selection = focusedEditor.getSelection();
|
||||
if (selection && selection.isEmpty() && !emptySelectionClipboard) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
document.execCommand(browserCommand);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// 2. (default) handle case when focus is somewhere else.
|
||||
target.addImplementation(0, (accessor: ServicesAccessor, args: any) => {
|
||||
// Only if editor text focus (i.e. not if editor has widget focus).
|
||||
document.execCommand(browserCommand);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
registerExecCommandImpl(CutAction, 'cut');
|
||||
registerExecCommandImpl(CopyAction, 'copy');
|
||||
registerExecCommandImpl(PasteAction, 'paste');
|
||||
|
||||
if (supportsCopyWithSyntaxHighlighting) {
|
||||
registerEditorAction(ExecCommandCopyWithSyntaxHighlightingAction);
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
// overwritten in subclass
|
||||
}
|
||||
|
||||
protected _start(opts: IFindStartOptions): void {
|
||||
protected async _start(opts: IFindStartOptions): Promise<void> {
|
||||
this.disposeModel();
|
||||
|
||||
if (!this._editor.hasModel()) {
|
||||
@@ -279,7 +279,7 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
}
|
||||
|
||||
if (!stateChanges.searchString && opts.seedSearchStringFromGlobalClipboard) {
|
||||
let selectionSearchString = this.getGlobalBufferTerm();
|
||||
let selectionSearchString = await this.getGlobalBufferTerm();
|
||||
if (selectionSearchString) {
|
||||
stateChanges.searchString = selectionSearchString;
|
||||
}
|
||||
@@ -308,8 +308,8 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
}
|
||||
}
|
||||
|
||||
public start(opts: IFindStartOptions): void {
|
||||
this._start(opts);
|
||||
public start(opts: IFindStartOptions): Promise<void> {
|
||||
return this._start(opts);
|
||||
}
|
||||
|
||||
public moveToNextMatch(): boolean {
|
||||
@@ -353,24 +353,24 @@ export class CommonFindController extends Disposable implements IEditorContribut
|
||||
return false;
|
||||
}
|
||||
|
||||
public getGlobalBufferTerm(): string {
|
||||
public async getGlobalBufferTerm(): Promise<string> {
|
||||
if (this._editor.getOption(EditorOption.find).globalFindClipboard
|
||||
&& this._clipboardService
|
||||
&& this._editor.hasModel()
|
||||
&& !this._editor.getModel().isTooLargeForSyncing()
|
||||
) {
|
||||
return this._clipboardService.readFindTextSync();
|
||||
return this._clipboardService.readFindText();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public setGlobalBufferTerm(text: string) {
|
||||
public async setGlobalBufferTerm(text: string) {
|
||||
if (this._editor.getOption(EditorOption.find).globalFindClipboard
|
||||
&& this._clipboardService
|
||||
&& this._editor.hasModel()
|
||||
&& !this._editor.getModel().isTooLargeForSyncing()
|
||||
) {
|
||||
this._clipboardService.writeFindTextSync(text);
|
||||
await this._clipboardService.writeFindText(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,7 +396,7 @@ export class FindController extends CommonFindController implements IFindControl
|
||||
this._findOptionsWidget = null;
|
||||
}
|
||||
|
||||
protected _start(opts: IFindStartOptions): void {
|
||||
protected async _start(opts: IFindStartOptions): Promise<void> {
|
||||
if (!this._widget) {
|
||||
this._createFindWidget();
|
||||
}
|
||||
@@ -422,7 +422,7 @@ export class FindController extends CommonFindController implements IFindControl
|
||||
|
||||
opts.updateSearchScope = updateSearchScope;
|
||||
|
||||
super._start(opts);
|
||||
await super._start(opts);
|
||||
|
||||
if (opts.shouldFocus === FindStartFocusAction.FocusReplaceInput) {
|
||||
this._widget!.focusReplaceInput();
|
||||
@@ -505,7 +505,7 @@ export class StartFindWithSelectionAction extends EditorAction {
|
||||
});
|
||||
}
|
||||
|
||||
public run(accessor: ServicesAccessor, editor: ICodeEditor): void {
|
||||
public async run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
|
||||
let controller = CommonFindController.get(editor);
|
||||
if (controller) {
|
||||
controller.start({
|
||||
@@ -518,7 +518,7 @@ export class StartFindWithSelectionAction extends EditorAction {
|
||||
loop: editor.getOption(EditorOption.find).loop
|
||||
});
|
||||
|
||||
controller.setGlobalBufferTerm(controller.getState().searchString);
|
||||
return controller.setGlobalBufferTerm(controller.getState().searchString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ export const findNextMatchIcon = registerIcon('find-next-match', Codicon.arrowDo
|
||||
export interface IFindController {
|
||||
replace(): void;
|
||||
replaceAll(): void;
|
||||
getGlobalBufferTerm(): string;
|
||||
getGlobalBufferTerm(): Promise<string>;
|
||||
}
|
||||
|
||||
const NLS_FIND_INPUT_LABEL = nls.localize('label.find', "Find");
|
||||
@@ -224,9 +224,9 @@ export class FindWidget extends Widget implements IOverlayWidget, IVerticalSashL
|
||||
this._updateToggleSelectionFindButton();
|
||||
}
|
||||
}));
|
||||
this._register(this._codeEditor.onDidFocusEditorWidget(() => {
|
||||
this._register(this._codeEditor.onDidFocusEditorWidget(async () => {
|
||||
if (this._isVisible) {
|
||||
let globalBufferTerm = this._controller.getGlobalBufferTerm();
|
||||
let globalBufferTerm = await this._controller.getGlobalBufferTerm();
|
||||
if (globalBufferTerm && globalBufferTerm !== this._state.searchString) {
|
||||
this._state.change({ searchString: globalBufferTerm }, true);
|
||||
this._findInput.select();
|
||||
|
||||
@@ -39,8 +39,8 @@ export class TestFindController extends CommonFindController {
|
||||
this.hasFocus = false;
|
||||
}
|
||||
|
||||
protected _start(opts: IFindStartOptions): void {
|
||||
super._start(opts);
|
||||
protected async _start(opts: IFindStartOptions): Promise<void> {
|
||||
await super._start(opts);
|
||||
|
||||
if (opts.shouldFocus !== FindStartFocusAction.NoFocusChange) {
|
||||
this.hasFocus = true;
|
||||
|
||||
@@ -31,14 +31,14 @@ var RECORDED_EVENTS = [];
|
||||
|
||||
var input = document.getElementById('input');
|
||||
|
||||
var blackListedProps = [
|
||||
var blockedProperties = [
|
||||
'currentTarget',
|
||||
'path',
|
||||
'srcElement',
|
||||
'target',
|
||||
'view'
|
||||
];
|
||||
blackListedProps = blackListedProps.concat([
|
||||
blockedProperties = blockedProperties.concat([
|
||||
'AT_TARGET',
|
||||
'BLUR',
|
||||
'BUBBLING_PHASE',
|
||||
@@ -68,7 +68,7 @@ blackListedProps = blackListedProps.concat([
|
||||
function toSerializable(e) {
|
||||
var r = {};
|
||||
for (var k in e) {
|
||||
if (blackListedProps.indexOf(k) >= 0) {
|
||||
if (blockedProperties.indexOf(k) >= 0) {
|
||||
continue;
|
||||
}
|
||||
if (typeof e[k] === 'function') {
|
||||
@@ -112,4 +112,4 @@ document.getElementById('stop').onclick = function() {
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -97,14 +97,4 @@ export class BrowserClipboardService implements IClipboardService {
|
||||
async hasResources(): Promise<boolean> {
|
||||
return this.resources.length > 0;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
readFindTextSync(): string {
|
||||
return this.findText;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
writeFindTextSync(text: string): void {
|
||||
this.findText = text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,12 +46,4 @@ export interface IClipboardService {
|
||||
* Find out if resources are copied to the clipboard.
|
||||
*/
|
||||
hasResources(): Promise<boolean>;
|
||||
|
||||
|
||||
|
||||
/** @deprecated */
|
||||
readFindTextSync(): string;
|
||||
|
||||
/** @deprecated */
|
||||
writeFindTextSync(text: string): void;
|
||||
}
|
||||
|
||||
@@ -46,13 +46,19 @@ export async function readFromStdin(targetPath: string, verbose: boolean): Promi
|
||||
|
||||
let encoding = await resolveTerminalEncoding(verbose);
|
||||
|
||||
const iconv = await import('iconv-lite');
|
||||
const iconv = await import('iconv-lite-umd');
|
||||
if (!iconv.encodingExists(encoding)) {
|
||||
console.log(`Unsupported terminal encoding: ${encoding}, falling back to UTF-8.`);
|
||||
encoding = 'utf8';
|
||||
}
|
||||
|
||||
// Pipe into tmp file using terminals encoding
|
||||
const converterStream = iconv.decodeStream(encoding);
|
||||
process.stdin.pipe(converterStream).pipe(stdinFileStream);
|
||||
const decoder = iconv.getDecoder(encoding);
|
||||
process.stdin.on('data', chunk => stdinFileStream.write(decoder.write(chunk)));
|
||||
process.stdin.on('end', () => {
|
||||
stdinFileStream.write(decoder.end());
|
||||
stdinFileStream.end();
|
||||
});
|
||||
process.stdin.on('error', error => stdinFileStream.destroy(error));
|
||||
process.stdin.on('close', () => stdinFileStream.close());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IBuiltinExtensionsScannerService, IScannedExtension, ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
export class BuiltinExtensionsScannerService implements IBuiltinExtensionsScannerService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly builtinExtensions: IScannedExtension[] = [];
|
||||
|
||||
constructor(
|
||||
) {
|
||||
if (isWeb) {
|
||||
// Find builtin extensions by checking for DOM
|
||||
const builtinExtensionsElement = document.getElementById('vscode-workbench-builtin-extensions');
|
||||
const builtinExtensionsElementAttribute = builtinExtensionsElement ? builtinExtensionsElement.getAttribute('data-settings') : undefined;
|
||||
if (builtinExtensionsElementAttribute) {
|
||||
try {
|
||||
const builtinExtensions: IScannedExtension[] = JSON.parse(builtinExtensionsElementAttribute);
|
||||
this.builtinExtensions = builtinExtensions.map(e => <IScannedExtension>{
|
||||
location: URI.revive(e.location),
|
||||
type: ExtensionType.System,
|
||||
packageJSON: e.packageJSON,
|
||||
packageNLSUrl: URI.revive(e.packageNLSUrl),
|
||||
readmeUrl: URI.revive(e.readmeUrl),
|
||||
changelogUrl: URI.revive(e.changelogUrl),
|
||||
});
|
||||
} catch (error) { /* ignore error*/ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async scanBuiltinExtensions(): Promise<IScannedExtension[]> {
|
||||
if (isWeb) {
|
||||
return this.builtinExtensions;
|
||||
}
|
||||
throw new Error('not supported');
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { ILocalization } from 'vs/platform/localizations/common/localizations';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export const MANIFEST_CACHE_FOLDER = 'CachedExtensions';
|
||||
export const USER_MANIFEST_CACHE_FILE = 'user';
|
||||
@@ -246,3 +247,18 @@ export interface IExtensionDescription extends IExtensionManifest {
|
||||
export function isLanguagePackExtension(manifest: IExtensionManifest): boolean {
|
||||
return manifest.contributes && manifest.contributes.localizations ? manifest.contributes.localizations.length > 0 : false;
|
||||
}
|
||||
|
||||
export interface IScannedExtension {
|
||||
readonly location: URI;
|
||||
readonly type: ExtensionType;
|
||||
readonly packageJSON: IExtensionManifest
|
||||
readonly packageNLSUrl?: URI;
|
||||
readonly readmeUrl?: URI;
|
||||
readonly changelogUrl?: URI;
|
||||
}
|
||||
|
||||
export const IBuiltinExtensionsScannerService = createDecorator<IBuiltinExtensionsScannerService>('IBuiltinExtensionsScannerService');
|
||||
export interface IBuiltinExtensionsScannerService {
|
||||
readonly _serviceBrand: undefined;
|
||||
scanBuiltinExtensions(): Promise<IScannedExtension[]>;
|
||||
}
|
||||
|
||||
@@ -156,6 +156,8 @@ export class LaunchMainService implements ILaunchMainService {
|
||||
else {
|
||||
const lastActive = this.windowsMainService.getLastActiveWindow();
|
||||
if (lastActive) {
|
||||
// Force focus the app before requesting window focus
|
||||
app.focus({ steal: true });
|
||||
lastActive.focus();
|
||||
|
||||
usedWindows = [lastActive];
|
||||
|
||||
@@ -75,14 +75,14 @@ export class LoggerChannelClient {
|
||||
export class FollowerLogService extends DelegatedLogService implements ILogService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(private master: LoggerChannelClient, logService: ILogService) {
|
||||
constructor(private parent: LoggerChannelClient, logService: ILogService) {
|
||||
super(logService);
|
||||
this._register(master.onDidChangeLogLevel(level => logService.setLevel(level)));
|
||||
this._register(parent.onDidChangeLogLevel(level => logService.setLevel(level)));
|
||||
}
|
||||
|
||||
setLevel(level: LogLevel): void {
|
||||
super.setLevel(level);
|
||||
|
||||
this.master.setLevel(level);
|
||||
this.parent.setLevel(level);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,17 +63,11 @@ export class BrowserStorageService extends Disposable implements IStorageService
|
||||
|
||||
// Workspace Storage
|
||||
this.workspaceStorageFile = joinPath(stateRoot, `${payload.id}.json`);
|
||||
|
||||
this.workspaceStorageDatabase = this._register(new FileStorageDatabase(this.workspaceStorageFile, false /* do not watch for external changes */, this.fileService));
|
||||
this.workspaceStorage = this._register(new Storage(this.workspaceStorageDatabase));
|
||||
this._register(this.workspaceStorage.onDidChangeStorage(key => this._onDidChangeStorage.fire({ key, scope: StorageScope.WORKSPACE })));
|
||||
|
||||
const firstOpen = this.workspaceStorage.getBoolean(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN);
|
||||
if (firstOpen === undefined) {
|
||||
this.workspaceStorage.set(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN, !(await this.fileService.exists(this.workspaceStorageFile)));
|
||||
} else if (firstOpen) {
|
||||
this.workspaceStorage.set(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN, false);
|
||||
}
|
||||
|
||||
// Global Storage
|
||||
this.globalStorageFile = joinPath(stateRoot, 'global.json');
|
||||
this.globalStorageDatabase = this._register(new FileStorageDatabase(this.globalStorageFile, true /* watch for external changes */, this.fileService));
|
||||
@@ -86,6 +80,15 @@ export class BrowserStorageService extends Disposable implements IStorageService
|
||||
this.globalStorage.init()
|
||||
]);
|
||||
|
||||
// Check to see if this is the first time we are "opening" this workspace
|
||||
const firstOpen = this.workspaceStorage.getBoolean(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN);
|
||||
if (firstOpen === undefined) {
|
||||
// NOTE@eamodio We can't reliably check to see if a workspace was added before this setting was introduced, so just pretend it is the first time
|
||||
this.workspaceStorage.set(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN, true);
|
||||
} else if (firstOpen) {
|
||||
this.workspaceStorage.set(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN, false);
|
||||
}
|
||||
|
||||
// In the browser we do not have support for long running unload sequences. As such,
|
||||
// we cannot ask for saving state in that moment, because that would result in a
|
||||
// long running operation.
|
||||
|
||||
@@ -105,6 +105,7 @@ export class NativeStorageService extends Disposable implements IStorageService
|
||||
);
|
||||
await workspaceStorage.init();
|
||||
|
||||
// Check to see if this is the first time we are "opening" this workspace
|
||||
const firstOpen = workspaceStorage.getBoolean(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN);
|
||||
if (firstOpen === undefined) {
|
||||
workspaceStorage.set(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN, !result.wasCreated);
|
||||
|
||||
@@ -81,6 +81,12 @@ export class UserDataAutoSyncService extends UserDataAutoSyncEnablementService i
|
||||
private readonly _onError: Emitter<UserDataSyncError> = this._register(new Emitter<UserDataSyncError>());
|
||||
readonly onError: Event<UserDataSyncError> = this._onError.event;
|
||||
|
||||
private readonly _onTurnOnSync: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onTurnOnSync: Event<void> = this._onTurnOnSync.event;
|
||||
|
||||
private readonly _onDidTurnOnSync: Emitter<UserDataSyncError | undefined> = this._register(new Emitter<UserDataSyncError | undefined>());
|
||||
readonly onDidTurnOnSync: Event<UserDataSyncError | undefined> = this._onDidTurnOnSync.event;
|
||||
|
||||
constructor(
|
||||
@IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService,
|
||||
@IUserDataSyncResourceEnablementService private readonly userDataSyncResourceEnablementService: IUserDataSyncResourceEnablementService,
|
||||
@@ -140,15 +146,23 @@ export class UserDataAutoSyncService extends UserDataAutoSyncEnablementService i
|
||||
}
|
||||
|
||||
async turnOn(pullFirst: boolean): Promise<void> {
|
||||
this.stopDisableMachineEventually();
|
||||
this._onTurnOnSync.fire();
|
||||
|
||||
if (pullFirst) {
|
||||
await this.userDataSyncService.pull();
|
||||
} else {
|
||||
await this.userDataSyncService.sync();
|
||||
try {
|
||||
this.stopDisableMachineEventually();
|
||||
|
||||
if (pullFirst) {
|
||||
await this.userDataSyncService.pull();
|
||||
} else {
|
||||
await this.userDataSyncService.sync();
|
||||
}
|
||||
|
||||
this.setEnablement(true);
|
||||
this._onDidTurnOnSync.fire(undefined);
|
||||
} catch (error) {
|
||||
this._onDidTurnOnSync.fire(error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.setEnablement(true);
|
||||
}
|
||||
|
||||
async turnOff(everywhere: boolean, softTurnOffOnError?: boolean, donotRemoveMachine?: boolean): Promise<void> {
|
||||
|
||||
@@ -357,6 +357,7 @@ export interface IUserDataSyncService {
|
||||
|
||||
readonly status: SyncStatus;
|
||||
readonly onDidChangeStatus: Event<SyncStatus>;
|
||||
readonly onSynchronizeResource: Event<SyncResource>;
|
||||
|
||||
readonly conflicts: SyncResourceConflicts[];
|
||||
readonly onDidChangeConflicts: Event<SyncResourceConflicts[]>;
|
||||
@@ -390,6 +391,8 @@ export interface IUserDataSyncService {
|
||||
export const IUserDataAutoSyncService = createDecorator<IUserDataAutoSyncService>('IUserDataAutoSyncService');
|
||||
export interface IUserDataAutoSyncService {
|
||||
_serviceBrand: any;
|
||||
readonly onTurnOnSync: Event<void>
|
||||
readonly onDidTurnOnSync: Event<UserDataSyncError | undefined>
|
||||
readonly onError: Event<UserDataSyncError>;
|
||||
readonly onDidChangeEnablement: Event<boolean>;
|
||||
isEnabled(): boolean;
|
||||
|
||||
@@ -22,6 +22,7 @@ export class UserDataSyncChannel implements IServerChannel {
|
||||
listen(_: unknown, event: string): Event<any> {
|
||||
switch (event) {
|
||||
case 'onDidChangeStatus': return this.service.onDidChangeStatus;
|
||||
case 'onSynchronizeResource': return this.service.onSynchronizeResource;
|
||||
case 'onDidChangeConflicts': return this.service.onDidChangeConflicts;
|
||||
case 'onDidChangeLocal': return this.service.onDidChangeLocal;
|
||||
case 'onDidChangeLastSyncTime': return this.service.onDidChangeLastSyncTime;
|
||||
@@ -68,6 +69,8 @@ export class UserDataAutoSyncChannel implements IServerChannel {
|
||||
|
||||
listen(_: unknown, event: string): Event<any> {
|
||||
switch (event) {
|
||||
case 'onTurnOnSync': return this.service.onTurnOnSync;
|
||||
case 'onDidTurnOnSync': return this.service.onDidTurnOnSync;
|
||||
case 'onError': return this.service.onError;
|
||||
}
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
|
||||
@@ -39,6 +39,9 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
private _onDidChangeStatus: Emitter<SyncStatus> = this._register(new Emitter<SyncStatus>());
|
||||
readonly onDidChangeStatus: Event<SyncStatus> = this._onDidChangeStatus.event;
|
||||
|
||||
private _onSynchronizeResource: Emitter<SyncResource> = this._register(new Emitter<SyncResource>());
|
||||
readonly onSynchronizeResource: Event<SyncResource> = this._onSynchronizeResource.event;
|
||||
|
||||
readonly onDidChangeLocal: Event<SyncResource>;
|
||||
|
||||
private _conflicts: SyncResourceConflicts[] = [];
|
||||
@@ -91,6 +94,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
try {
|
||||
for (const synchroniser of this.synchronisers) {
|
||||
try {
|
||||
this._onSynchronizeResource.fire(synchroniser.resource);
|
||||
await synchroniser.pull();
|
||||
} catch (e) {
|
||||
this.handleSynchronizerError(e, synchroniser.resource);
|
||||
@@ -175,6 +179,7 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this._onSynchronizeResource.fire(synchroniser.resource);
|
||||
await synchroniser.sync(manifest, syncHeaders);
|
||||
} catch (e) {
|
||||
this.handleSynchronizerError(e, synchroniser.resource);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { VSBuffer, VSBufferReadableStream } from 'vs/base/common/buffer';
|
||||
import { VSBufferReadableStream } from 'vs/base/common/buffer';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { isUNC } from 'vs/base/common/extpath';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -11,14 +11,12 @@ import { sep } from 'vs/base/common/path';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { getWebviewContentMimeType } from 'vs/platform/webview/common/mimeTypes';
|
||||
|
||||
|
||||
export const webviewPartitionId = 'webview';
|
||||
|
||||
|
||||
export namespace WebviewResourceResponse {
|
||||
export enum Type { Success, Failed, AccessDenied }
|
||||
|
||||
@@ -31,73 +29,41 @@ export namespace WebviewResourceResponse {
|
||||
) { }
|
||||
}
|
||||
|
||||
export class BufferSuccess {
|
||||
readonly type = Type.Success;
|
||||
|
||||
constructor(
|
||||
public readonly buffer: VSBuffer,
|
||||
public readonly mimeType: string
|
||||
) { }
|
||||
}
|
||||
|
||||
export const Failed = { type: Type.Failed } as const;
|
||||
export const AccessDenied = { type: Type.AccessDenied } as const;
|
||||
|
||||
export type BufferResponse = BufferSuccess | typeof Failed | typeof AccessDenied;
|
||||
export type StreamResponse = StreamSuccess | typeof Failed | typeof AccessDenied;
|
||||
}
|
||||
|
||||
export async function loadLocalResource(
|
||||
requestUri: URI,
|
||||
fileService: IFileService,
|
||||
extensionLocation: URI | undefined,
|
||||
roots: ReadonlyArray<URI>
|
||||
): Promise<WebviewResourceResponse.BufferResponse> {
|
||||
const resourceToLoad = getResourceToLoad(requestUri, extensionLocation, roots);
|
||||
if (!resourceToLoad) {
|
||||
return WebviewResourceResponse.AccessDenied;
|
||||
}
|
||||
|
||||
try {
|
||||
const data = await fileService.readFile(resourceToLoad);
|
||||
const mime = getWebviewContentMimeType(requestUri); // Use the original path for the mime
|
||||
return new WebviewResourceResponse.BufferSuccess(data.value, mime);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return WebviewResourceResponse.Failed;
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadLocalResourceStream(
|
||||
requestUri: URI,
|
||||
options: {
|
||||
extensionLocation: URI | undefined;
|
||||
roots: ReadonlyArray<URI>;
|
||||
remoteConnectionData?: IRemoteConnectionData | null;
|
||||
rewriteUri?: (uri: URI) => URI,
|
||||
},
|
||||
fileService: IFileService,
|
||||
requestService: IRequestService,
|
||||
): Promise<WebviewResourceResponse.StreamResponse> {
|
||||
const resourceToLoad = getResourceToLoad(requestUri, options.extensionLocation, options.roots);
|
||||
let resourceToLoad = getResourceToLoad(requestUri, options.roots);
|
||||
if (!resourceToLoad) {
|
||||
return WebviewResourceResponse.AccessDenied;
|
||||
}
|
||||
|
||||
const mime = getWebviewContentMimeType(requestUri); // Use the original path for the mime
|
||||
|
||||
if (options.remoteConnectionData) {
|
||||
// Remote uris must go to the resolved server.
|
||||
if (resourceToLoad.scheme === Schemas.vscodeRemote || (options.extensionLocation?.scheme === REMOTE_HOST_SCHEME)) {
|
||||
const uri = URI.parse(`http://${options.remoteConnectionData.host}:${options.remoteConnectionData.port}`).with({
|
||||
path: '/vscode-remote-resource',
|
||||
query: `tkn=${options.remoteConnectionData.connectionToken}&path=${encodeURIComponent(resourceToLoad.path)}`,
|
||||
});
|
||||
// Perform extra normalization if needed
|
||||
if (options.rewriteUri) {
|
||||
resourceToLoad = options.rewriteUri(resourceToLoad);
|
||||
}
|
||||
|
||||
const response = await requestService.request({ url: uri.toString(true) }, CancellationToken.None);
|
||||
if (response.res.statusCode === 200) {
|
||||
return new WebviewResourceResponse.StreamSuccess(response.stream, mime);
|
||||
}
|
||||
return WebviewResourceResponse.Failed;
|
||||
if (resourceToLoad.scheme === Schemas.http || resourceToLoad.scheme === Schemas.https) {
|
||||
const response = await requestService.request({ url: resourceToLoad.toString(true) }, CancellationToken.None);
|
||||
if (response.res.statusCode === 200) {
|
||||
return new WebviewResourceResponse.StreamSuccess(response.stream, mime);
|
||||
}
|
||||
return WebviewResourceResponse.Failed;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -111,7 +77,6 @@ export async function loadLocalResourceStream(
|
||||
|
||||
function getResourceToLoad(
|
||||
requestUri: URI,
|
||||
extensionLocation: URI | undefined,
|
||||
roots: ReadonlyArray<URI>
|
||||
): URI | undefined {
|
||||
const normalizedPath = normalizeRequestPath(requestUri);
|
||||
|
||||
@@ -12,7 +12,8 @@ import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { loadLocalResourceStream, webviewPartitionId, WebviewResourceResponse } from 'vs/platform/webview/common/resourceLoader';
|
||||
import { loadLocalResource, webviewPartitionId, WebviewResourceResponse } from 'vs/platform/webview/common/resourceLoader';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
||||
interface WebviewMetadata {
|
||||
readonly extensionLocation: URI | undefined;
|
||||
@@ -39,11 +40,31 @@ export class WebviewProtocolProvider extends Disposable {
|
||||
const id = uri.authority;
|
||||
const metadata = this.webviewMetadata.get(id);
|
||||
if (metadata) {
|
||||
const result = await loadLocalResourceStream(uri, {
|
||||
|
||||
// Try to further rewrite remote uris so that they go to the resolved server on the main thread
|
||||
let rewriteUri: undefined | ((uri: URI) => URI);
|
||||
if (metadata.remoteConnectionData) {
|
||||
rewriteUri = (uri) => {
|
||||
if (metadata.remoteConnectionData) {
|
||||
if (uri.scheme === Schemas.vscodeRemote || (metadata.extensionLocation?.scheme === REMOTE_HOST_SCHEME)) {
|
||||
const scheme = metadata.remoteConnectionData.host === 'localhost' || metadata.remoteConnectionData.host === '127.0.0.1' ? 'http' : 'https';
|
||||
return URI.parse(`${scheme}://${metadata.remoteConnectionData.host}:${metadata.remoteConnectionData.port}`).with({
|
||||
path: '/vscode-remote-resource',
|
||||
query: `tkn=${metadata.remoteConnectionData.connectionToken}&path=${encodeURIComponent(uri.path)}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
};
|
||||
}
|
||||
|
||||
const result = await loadLocalResource(uri, {
|
||||
extensionLocation: metadata.extensionLocation,
|
||||
roots: metadata.localResourceRoots,
|
||||
remoteConnectionData: metadata.remoteConnectionData,
|
||||
rewriteUri,
|
||||
}, this.fileService, this.requestService);
|
||||
|
||||
if (result.type === WebviewResourceResponse.Type.Success) {
|
||||
return callback({
|
||||
statusCode: 200,
|
||||
|
||||
@@ -252,13 +252,13 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
|
||||
// Note that onBeforeShutdown() and onBeforeWindowClose() are fired in different order depending on the OS:
|
||||
// - macOS: since the app will not quit when closing the last window, you will always first get
|
||||
// the onBeforeShutdown() event followed by N onbeforeWindowClose() events for each window
|
||||
// the onBeforeShutdown() event followed by N onBeforeWindowClose() events for each window
|
||||
// - other: on other OS, closing the last window will quit the app so the order depends on the
|
||||
// user interaction: closing the last window will first trigger onBeforeWindowClose()
|
||||
// and then onBeforeShutdown(). Using the quit action however will first issue onBeforeShutdown()
|
||||
// and then onBeforeWindowClose().
|
||||
//
|
||||
// Here is the behaviour on different OS dependig on action taken (Electron 1.7.x):
|
||||
// Here is the behavior on different OS depending on action taken (Electron 1.7.x):
|
||||
//
|
||||
// Legend
|
||||
// - quit(N): quit application with N windows opened
|
||||
@@ -320,7 +320,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
|
||||
|
||||
// 3.) All windows (except extension host) for N >= 2 to support restoreWindows: all or for auto update
|
||||
//
|
||||
// Carefull here: asking a window for its window state after it has been closed returns bogus values (width: 0, height: 0)
|
||||
// Careful here: asking a window for its window state after it has been closed returns bogus values (width: 0, height: 0)
|
||||
// so if we ever want to persist the UI state of the last closed window (window count === 1), it has
|
||||
// to come from the stored lastClosedWindowState on Win/Linux at least
|
||||
if (this.getWindowCount() > 1) {
|
||||
|
||||
Vendored
+58
@@ -1054,6 +1054,64 @@ declare module 'vscode' {
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Terminal link provider https://github.com/microsoft/vscode/issues/91606
|
||||
|
||||
export namespace window {
|
||||
export function registerTerminalLinkProvider(provider: TerminalLinkProvider): Disposable;
|
||||
}
|
||||
|
||||
export interface TerminalLinkContext {
|
||||
/**
|
||||
* This is the text from the unwrapped line in the terminal.
|
||||
*/
|
||||
line: string;
|
||||
|
||||
/**
|
||||
* The terminal the link belongs to.
|
||||
*/
|
||||
terminal: Terminal;
|
||||
}
|
||||
|
||||
export interface TerminalLinkProvider<T = TerminalLink> {
|
||||
provideTerminalLinks(context: TerminalLinkContext): ProviderResult<T[]>
|
||||
|
||||
/**
|
||||
* Handle an activated terminal link.
|
||||
*
|
||||
* @returns Whether the link was handled, if not VS Code will attempt to open it.
|
||||
*/
|
||||
handleTerminalLink(link: T): ProviderResult<boolean>;
|
||||
}
|
||||
|
||||
export interface TerminalLink {
|
||||
/**
|
||||
* The start index of the link on [TerminalLinkContext.line](#TerminalLinkContext.line].
|
||||
*/
|
||||
startIndex: number;
|
||||
|
||||
/**
|
||||
* The length of the link on [TerminalLinkContext.line](#TerminalLinkContext.line]
|
||||
*/
|
||||
length: number;
|
||||
|
||||
/**
|
||||
* The uri this link points to. If set, and {@link TerminalLinkProvider.handlerTerminalLink}
|
||||
* is not implemented or returns false, then VS Code will try to open the Uri.
|
||||
*/
|
||||
target?: Uri;
|
||||
|
||||
/**
|
||||
* The tooltip text when you hover over this link.
|
||||
*
|
||||
* If a tooltip is provided, is will be displayed in a string that includes instructions on
|
||||
* how to trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary
|
||||
* depending on OS, user settings, and localization.
|
||||
*/
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region @jrieken -> exclusive document filters
|
||||
|
||||
export interface DocumentFilter {
|
||||
|
||||
@@ -24,9 +24,9 @@ import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, IExtHostContex
|
||||
import { EditorViewColumn, editorGroupToViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { openEditorWith } from 'vs/workbench/contrib/files/common/openWith';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith';
|
||||
|
||||
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceS
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { ITerminalInstanceService, ITerminalService, ITerminalInstance, ITerminalBeforeHandleLinkEvent } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { ITerminalInstanceService, ITerminalService, ITerminalInstance, ITerminalBeforeHandleLinkEvent, ITerminalExternalLinkProvider, ITerminalLink } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
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';
|
||||
@@ -25,6 +25,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
private readonly _terminalProcessProxies = new Map<number, ITerminalProcessExtHostProxy>();
|
||||
private _dataEventTracker: TerminalDataEventTracker | undefined;
|
||||
private _linkHandler: IDisposable | undefined;
|
||||
/**
|
||||
* A single shared terminal link provider for the exthost. When an ext registers a link
|
||||
* provider, this is registered with the terminal on the renderer side and all links are
|
||||
* provided through this, even from multiple ext link providers. Xterm should remove lower
|
||||
* priority intersecting links itself.
|
||||
*/
|
||||
private _linkProvider: IDisposable | undefined;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@@ -86,6 +93,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
|
||||
public dispose(): void {
|
||||
this._toDispose.dispose();
|
||||
this._linkHandler?.dispose();
|
||||
this._linkProvider?.dispose();
|
||||
|
||||
// TODO@Daniel: Should all the previously created terminals be disposed
|
||||
// when the extension host process goes down ?
|
||||
@@ -162,6 +171,17 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
|
||||
public $stopHandlingLinks(): void {
|
||||
this._linkHandler?.dispose();
|
||||
this._linkHandler = undefined;
|
||||
}
|
||||
|
||||
public $startLinkProvider(): void {
|
||||
this._linkProvider?.dispose();
|
||||
this._linkProvider = this._terminalService.registerLinkProvider(new ExtensionTerminalLinkProvider(this._proxy));
|
||||
}
|
||||
|
||||
public $stopLinkProvider(): void {
|
||||
this._linkProvider?.dispose();
|
||||
this._linkProvider = undefined;
|
||||
}
|
||||
|
||||
private async _handleLink(e: ITerminalBeforeHandleLinkEvent): Promise<boolean> {
|
||||
@@ -395,3 +415,22 @@ class TerminalDataEventTracker extends Disposable {
|
||||
this._register(this._bufferer.startBuffering(instance.id, instance.onData));
|
||||
}
|
||||
}
|
||||
|
||||
class ExtensionTerminalLinkProvider implements ITerminalExternalLinkProvider {
|
||||
constructor(
|
||||
private readonly _proxy: ExtHostTerminalServiceShape
|
||||
) {
|
||||
}
|
||||
|
||||
async provideLinks(instance: ITerminalInstance, line: string): Promise<ITerminalLink[] | undefined> {
|
||||
const proxy = this._proxy;
|
||||
const extHostLinks = await proxy.$provideLinks(instance.id, line);
|
||||
return extHostLinks.map(dto => ({
|
||||
id: dto.id,
|
||||
startIndex: dto.startIndex,
|
||||
length: dto.length,
|
||||
label: dto.label,
|
||||
activate: () => proxy.$activateLink(instance.id, dto.id)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
|
||||
this._register(_editorService.onDidActiveEditorChange(() => {
|
||||
const activeInput = this._editorService.activeEditor;
|
||||
if (activeInput instanceof DiffEditorInput && activeInput.master instanceof WebviewInput && activeInput.details instanceof WebviewInput) {
|
||||
if (activeInput instanceof DiffEditorInput && activeInput.primary instanceof WebviewInput && activeInput.secondary instanceof WebviewInput) {
|
||||
this.registerWebviewFromDiffEditorListeners(activeInput);
|
||||
}
|
||||
|
||||
@@ -468,22 +468,22 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
}
|
||||
|
||||
private registerWebviewFromDiffEditorListeners(diffEditorInput: DiffEditorInput): void {
|
||||
const master = diffEditorInput.master as WebviewInput;
|
||||
const details = diffEditorInput.details as WebviewInput;
|
||||
const primary = diffEditorInput.primary as WebviewInput;
|
||||
const secondary = diffEditorInput.secondary as WebviewInput;
|
||||
|
||||
if (this._webviewFromDiffEditorHandles.has(master.id) || this._webviewFromDiffEditorHandles.has(details.id)) {
|
||||
if (this._webviewFromDiffEditorHandles.has(primary.id) || this._webviewFromDiffEditorHandles.has(secondary.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._webviewFromDiffEditorHandles.add(master.id);
|
||||
this._webviewFromDiffEditorHandles.add(details.id);
|
||||
this._webviewFromDiffEditorHandles.add(primary.id);
|
||||
this._webviewFromDiffEditorHandles.add(secondary.id);
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
disposables.add(master.webview.onDidFocus(() => this.updateWebviewViewStates(master)));
|
||||
disposables.add(details.webview.onDidFocus(() => this.updateWebviewViewStates(details)));
|
||||
disposables.add(primary.webview.onDidFocus(() => this.updateWebviewViewStates(primary)));
|
||||
disposables.add(secondary.webview.onDidFocus(() => this.updateWebviewViewStates(secondary)));
|
||||
disposables.add(diffEditorInput.onDispose(() => {
|
||||
this._webviewFromDiffEditorHandles.delete(master.id);
|
||||
this._webviewFromDiffEditorHandles.delete(details.id);
|
||||
this._webviewFromDiffEditorHandles.delete(primary.id);
|
||||
this._webviewFromDiffEditorHandles.delete(secondary.id);
|
||||
dispose(disposables);
|
||||
}));
|
||||
}
|
||||
@@ -515,8 +515,8 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
for (const group of this._editorGroupService.groups) {
|
||||
for (const input of group.editors) {
|
||||
if (input instanceof DiffEditorInput) {
|
||||
updateViewStatesForInput(group, input, input.master);
|
||||
updateViewStatesForInput(group, input, input.details);
|
||||
updateViewStatesForInput(group, input, input.primary);
|
||||
updateViewStatesForInput(group, input, input.secondary);
|
||||
} else {
|
||||
updateViewStatesForInput(group, input, input);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls';
|
||||
import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
|
||||
import { ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
|
||||
import { IExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
|
||||
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { throwProposedApiError, checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
@@ -97,6 +97,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const extHostLogService = accessor.get(ILogService);
|
||||
const extHostTunnelService = accessor.get(IExtHostTunnelService);
|
||||
const extHostApiDeprecation = accessor.get(IExtHostApiDeprecationService);
|
||||
const extHostWindow = accessor.get(IExtHostWindow);
|
||||
|
||||
// register addressable instances
|
||||
rpcProtocol.set(ExtHostContext.ExtHostLogService, <ExtHostLogServiceShape><any>extHostLogService);
|
||||
@@ -105,6 +106,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostTunnelService, extHostTunnelService);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostWindow, extHostWindow);
|
||||
|
||||
// automatically create and register addressable instances
|
||||
const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, accessor.get(IExtHostDecorations));
|
||||
@@ -131,7 +133,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
|
||||
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
|
||||
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
|
||||
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
|
||||
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
|
||||
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
|
||||
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extensionStoragePaths));
|
||||
@@ -586,6 +587,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostTerminalService.registerLinkHandler(handler);
|
||||
},
|
||||
registerTerminalLinkProvider(handler: vscode.TerminalLinkProvider): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostTerminalService.registerLinkProvider(handler);
|
||||
},
|
||||
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
|
||||
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension);
|
||||
},
|
||||
|
||||
@@ -450,6 +450,8 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
|
||||
$stopSendingDataEvents(): void;
|
||||
$startHandlingLinks(): void;
|
||||
$stopHandlingLinks(): void;
|
||||
$startLinkProvider(): void;
|
||||
$stopLinkProvider(): void;
|
||||
$setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void;
|
||||
|
||||
// Process
|
||||
@@ -1380,6 +1382,17 @@ export interface IShellAndArgsDto {
|
||||
args: string[] | string | undefined;
|
||||
}
|
||||
|
||||
export interface ITerminalLinkDto {
|
||||
/** The ID of the link to enable activation and disposal. */
|
||||
id: number;
|
||||
/** The startIndex of the link in the line. */
|
||||
startIndex: number;
|
||||
/** The length of the link in the line. */
|
||||
length: number;
|
||||
/** The descriptive label for what the link does when activated. */
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export interface ITerminalDimensionsDto {
|
||||
columns: number;
|
||||
rows: number;
|
||||
@@ -1406,6 +1419,8 @@ export interface ExtHostTerminalServiceShape {
|
||||
$getAvailableShells(): Promise<IShellDefinitionDto[]>;
|
||||
$getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
|
||||
$handleLink(id: number, link: string): Promise<boolean>;
|
||||
$provideLinks(id: number, line: string): Promise<ITerminalLinkDto[]>;
|
||||
$activateLink(id: number, linkId: number): void;
|
||||
$initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import type * as vscode from 'vscode';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto, ITerminalLinkDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
@@ -39,6 +39,7 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
|
||||
getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
|
||||
getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string;
|
||||
registerLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable;
|
||||
registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable;
|
||||
getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection;
|
||||
}
|
||||
|
||||
@@ -293,6 +294,13 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
}
|
||||
}
|
||||
|
||||
let nextLinkId = 1;
|
||||
|
||||
interface ICachedLinkEntry {
|
||||
provider: vscode.TerminalLinkProvider;
|
||||
link: vscode.TerminalLink;
|
||||
}
|
||||
|
||||
export abstract class BaseExtHostTerminalService implements IExtHostTerminalService, ExtHostTerminalServiceShape {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
@@ -307,6 +315,8 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
|
||||
private readonly _bufferer: TerminalDataBufferer;
|
||||
private readonly _linkHandlers: Set<vscode.TerminalLinkHandler> = new Set();
|
||||
private readonly _linkProviders: Set<vscode.TerminalLinkProvider> = new Set();
|
||||
private readonly _terminalLinkCache: Map<number, Map<number, ICachedLinkEntry>> = new Map();
|
||||
|
||||
public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; }
|
||||
public get terminals(): ExtHostTerminal[] { return this._terminals; }
|
||||
@@ -547,17 +557,30 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
|
||||
public registerLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable {
|
||||
this._linkHandlers.add(handler);
|
||||
if (this._linkHandlers.size === 1) {
|
||||
if (this._linkHandlers.size === 1 && this._linkProviders.size === 0) {
|
||||
this._proxy.$startHandlingLinks();
|
||||
}
|
||||
return new VSCodeDisposable(() => {
|
||||
this._linkHandlers.delete(handler);
|
||||
if (this._linkHandlers.size === 0) {
|
||||
if (this._linkHandlers.size === 0 && this._linkProviders.size === 0) {
|
||||
this._proxy.$stopHandlingLinks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable {
|
||||
this._linkProviders.add(provider);
|
||||
if (this._linkProviders.size === 1) {
|
||||
this._proxy.$startLinkProvider();
|
||||
}
|
||||
return new VSCodeDisposable(() => {
|
||||
this._linkProviders.delete(provider);
|
||||
if (this._linkProviders.size === 0) {
|
||||
this._proxy.$stopLinkProvider();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async $handleLink(id: number, link: string): Promise<boolean> {
|
||||
const terminal = this._getTerminalById(id);
|
||||
if (!terminal) {
|
||||
@@ -577,6 +600,62 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
return false;
|
||||
}
|
||||
|
||||
public async $provideLinks(terminalId: number, line: string): Promise<ITerminalLinkDto[]> {
|
||||
const terminal = this._getTerminalById(terminalId);
|
||||
if (!terminal) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Discard any cached links the terminal has been holding, currently all links are released
|
||||
// when new links are provided.
|
||||
this._terminalLinkCache.delete(terminalId);
|
||||
|
||||
const result: ITerminalLinkDto[] = [];
|
||||
const context: vscode.TerminalLinkContext = { terminal, line };
|
||||
const promises: vscode.ProviderResult<{ provider: vscode.TerminalLinkProvider, links: vscode.TerminalLink[] }>[] = [];
|
||||
for (const provider of this._linkProviders) {
|
||||
promises.push(new Promise(async r => {
|
||||
const links = (await provider.provideTerminalLinks(context)) || [];
|
||||
r({ provider, links });
|
||||
}));
|
||||
}
|
||||
|
||||
const provideResults = await Promise.all(promises);
|
||||
const cacheLinkMap = new Map<number, ICachedLinkEntry>();
|
||||
for (const provideResult of provideResults) {
|
||||
if (provideResult && provideResult.links.length > 0) {
|
||||
result.push(...provideResult.links.map(providerLink => {
|
||||
const link = {
|
||||
id: nextLinkId++,
|
||||
startIndex: providerLink.startIndex,
|
||||
length: providerLink.length,
|
||||
label: providerLink.tooltip
|
||||
};
|
||||
cacheLinkMap.set(link.id, {
|
||||
provider: provideResult.provider,
|
||||
link: providerLink
|
||||
});
|
||||
return link;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
this._terminalLinkCache.set(terminalId, cacheLinkMap);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
$activateLink(terminalId: number, linkId: number): void {
|
||||
const cachedLink = this._terminalLinkCache.get(terminalId)?.get(linkId);
|
||||
if (!cachedLink) {
|
||||
return;
|
||||
}
|
||||
cachedLink.provider.handleTerminalLink(cachedLink.link);
|
||||
// TODO: Handle when result is false? Should this be return void instead and remove
|
||||
// TerminalLink.target? It's a simple call to window.openUri for the extension otherwise
|
||||
// and would simplify the API.
|
||||
}
|
||||
|
||||
private _onProcessExit(id: number, exitCode: number | undefined): void {
|
||||
this._bufferer.stopBuffering(id);
|
||||
|
||||
|
||||
@@ -1252,7 +1252,7 @@ export class MarkdownString {
|
||||
// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
|
||||
this.value += (this.supportThemeIcons ? escapeCodicons(value) : value)
|
||||
.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
|
||||
.replace('\n', '\n\n');
|
||||
.replace(/\n/, '\n\n');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostWindowShape, MainContext, MainThreadWindowShape, IMainContext, IOpenUriOptions } from './extHost.protocol';
|
||||
import { ExtHostWindowShape, MainContext, MainThreadWindowShape, IOpenUriOptions } from './extHost.protocol';
|
||||
import { WindowState } from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
|
||||
export class ExtHostWindow implements ExtHostWindowShape {
|
||||
export class ExtHostWindow implements IExtHostWindow {
|
||||
|
||||
private static InitialState: WindowState = {
|
||||
focused: true
|
||||
@@ -24,8 +26,8 @@ export class ExtHostWindow implements ExtHostWindowShape {
|
||||
private _state = ExtHostWindow.InitialState;
|
||||
get state(): WindowState { return this._state; }
|
||||
|
||||
constructor(mainContext: IMainContext) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadWindow);
|
||||
constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) {
|
||||
this._proxy = extHostRpc.getProxy(MainContext.MainThreadWindow);
|
||||
this._proxy.$getWindowVisibility().then(isFocused => this.$onDidChangeWindowFocus(isFocused));
|
||||
}
|
||||
|
||||
@@ -67,3 +69,6 @@ export class ExtHostWindow implements ExtHostWindowShape {
|
||||
return URI.from(result);
|
||||
}
|
||||
}
|
||||
|
||||
export const IExtHostWindow = createDecorator<IExtHostWindow>('IExtHostWindow');
|
||||
export interface IExtHostWindow extends ExtHostWindow, ExtHostWindowShape { }
|
||||
|
||||
@@ -29,12 +29,14 @@ import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
|
||||
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
|
||||
import { ExtHostTunnelService } from 'vs/workbench/api/node/extHostTunnelService';
|
||||
import { IExtHostApiDeprecationService, ExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
|
||||
import { IExtHostWindow, ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
|
||||
|
||||
// register singleton services
|
||||
registerSingleton(ILogService, ExtHostLogService);
|
||||
registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService);
|
||||
registerSingleton(IExtHostOutputService, ExtHostOutputService2);
|
||||
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
|
||||
registerSingleton(IExtHostWindow, ExtHostWindow);
|
||||
registerSingleton(IExtHostDecorations, ExtHostDecorations);
|
||||
registerSingleton(IExtHostConfiguration, ExtHostConfiguration);
|
||||
registerSingleton(IExtHostCommands, ExtHostCommands);
|
||||
|
||||
@@ -121,6 +121,6 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
|
||||
}
|
||||
|
||||
protected createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService {
|
||||
return new ExtHostVariableResolverService(folders, undefined, configurationService, process.env as env.IProcessEnvironment);
|
||||
return new ExtHostVariableResolverService(folders, editorService, configurationService, process.env as env.IProcessEnvironment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ CommandsRegistry.registerCommand({
|
||||
handler: async function (accessor: ServicesAccessor, prefix: unknown) {
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
|
||||
quickInputService.quickAccess.show(typeof prefix === 'string' ? prefix : undefined);
|
||||
quickInputService.quickAccess.show(typeof prefix === 'string' ? prefix : undefined, { preserveValue: typeof prefix === 'string' /* preserve as is if provided */ });
|
||||
},
|
||||
description: {
|
||||
description: `Quick access`,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { hasWorkspaceFileExtension, IWorkspaceFolderCreationData, IRecentFile, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { normalize } from 'vs/base/common/path';
|
||||
import { basename } from 'vs/base/common/resources';
|
||||
import { basename, extUri } from 'vs/base/common/resources';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IWindowOpenable } from 'vs/platform/windows/common/windows';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -357,7 +357,7 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources:
|
||||
for (const textEditorControl of textEditorControls) {
|
||||
if (isCodeEditor(textEditorControl)) {
|
||||
const model = textEditorControl.getModel();
|
||||
if (model?.uri?.toString() === file.resource.toString()) {
|
||||
if (extUri.isEqual(model?.uri, file.resource)) {
|
||||
return withNullAsUndefined(textEditorControl.saveViewState());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { dirname, isEqual, basenameOrAuthority } from 'vs/base/common/resources';
|
||||
import { dirname, isEqual, basenameOrAuthority, extUri } from 'vs/base/common/resources';
|
||||
import { IconLabel, IIconLabelValueOptions, IIconLabelCreationOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
@@ -24,7 +24,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
|
||||
export interface IResourceLabelProps {
|
||||
resource?: URI | { master?: URI, detail?: URI };
|
||||
resource?: URI | { primary?: URI, secondary?: URI };
|
||||
name?: string | string[];
|
||||
description?: string;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ function toResource(props: IResourceLabelProps | undefined): URI | undefined {
|
||||
return props.resource;
|
||||
}
|
||||
|
||||
return props.resource.master;
|
||||
return props.resource.primary;
|
||||
}
|
||||
|
||||
export interface IResourceLabelOptions extends IIconLabelValueOptions {
|
||||
@@ -307,7 +307,7 @@ class ResourceLabelWidget extends IconLabel {
|
||||
return; // only update if resource exists
|
||||
}
|
||||
|
||||
if (model.uri.toString() === resource.toString()) {
|
||||
if (extUri.isEqual(model.uri, resource)) {
|
||||
if (this.lastKnownDetectedModeId !== model.getModeId()) {
|
||||
this.render(true); // update if the language id of the model has changed from our last known state
|
||||
}
|
||||
@@ -379,9 +379,9 @@ class ResourceLabelWidget extends IconLabel {
|
||||
|
||||
setResource(label: IResourceLabelProps, options: IResourceLabelOptions = Object.create(null)): void {
|
||||
const resource = toResource(label);
|
||||
const isMasterDetail = label?.resource && !URI.isUri(label.resource);
|
||||
const isSideBySideEditor = label?.resource && !URI.isUri(label.resource);
|
||||
|
||||
if (!options.forceLabel && !isMasterDetail && resource?.scheme === Schemas.untitled) {
|
||||
if (!options.forceLabel && !isSideBySideEditor && resource?.scheme === Schemas.untitled) {
|
||||
// Untitled labels are very dynamic because they may change
|
||||
// whenever the content changes (unless a path is associated).
|
||||
// As such we always ask the actual editor for it's name and
|
||||
@@ -390,7 +390,7 @@ class ResourceLabelWidget extends IconLabel {
|
||||
// we assume that the client does not want to display them
|
||||
// and as such do not override.
|
||||
//
|
||||
// We do not touch the label if it represents a master-detail
|
||||
// We do not touch the label if it represents a primary-secondary
|
||||
// because in that case we expect it to carry a proper label
|
||||
// and description.
|
||||
const untitledModel = this.textFileService.untitled.get(resource);
|
||||
|
||||
@@ -568,7 +568,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
return;
|
||||
}
|
||||
|
||||
const firstOpen = storageService.getBoolean(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN, StorageScope.WORKSPACE);
|
||||
// The `firstRun` flag check is a safety-net hack for Codespaces, until we can verify the first open fix
|
||||
const firstOpen = (storageService.getBoolean(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN, StorageScope.WORKSPACE) || (defaultLayout as { firstRun: boolean })?.firstRun);
|
||||
if (!firstOpen) {
|
||||
return;
|
||||
}
|
||||
@@ -790,7 +791,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
|
||||
private getInitialFilesToOpen(): { filesToOpenOrCreate?: IPath[], filesToDiff?: IPath[] } | undefined {
|
||||
const defaultLayout = this.environmentService.options?.defaultLayout;
|
||||
if (defaultLayout?.editors?.length && this.storageService.getBoolean(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN, StorageScope.WORKSPACE)) {
|
||||
// The `firstRun` flag check is a safety-net hack for Codespaces, until we can verify the first open fix
|
||||
if (defaultLayout?.editors?.length && (this.storageService.getBoolean(WorkspaceStorageSettings.WORKSPACE_FIRST_OPEN, StorageScope.WORKSPACE) || (defaultLayout as { firstRun: boolean })?.firstRun)) {
|
||||
this._openedDefaultEditors = true;
|
||||
|
||||
return {
|
||||
|
||||
@@ -29,11 +29,11 @@ export class BinaryResourceDiffEditor extends SideBySideEditor {
|
||||
}
|
||||
|
||||
getMetadata(): string | undefined {
|
||||
const master = this.masterEditorPane;
|
||||
const details = this.detailsEditorPane;
|
||||
const primary = this.primaryEditorPane;
|
||||
const secondary = this.secondaryEditorPane;
|
||||
|
||||
if (master instanceof BaseBinaryResourceEditor && details instanceof BaseBinaryResourceEditor) {
|
||||
return nls.localize('metadataDiff', "{0} ↔ {1}", details.getMetadata(), master.getMetadata());
|
||||
if (primary instanceof BaseBinaryResourceEditor && secondary instanceof BaseBinaryResourceEditor) {
|
||||
return nls.localize('metadataDiff', "{0} ↔ {1}", secondary.getMetadata(), primary.getMetadata());
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@@ -234,7 +234,7 @@ export class BreadcrumbsControl {
|
||||
this._breadcrumbsDisposables.clear();
|
||||
|
||||
// honor diff editors and such
|
||||
const uri = toResource(this._editorGroup.activeEditor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
const uri = toResource(this._editorGroup.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY });
|
||||
|
||||
if (!uri || !this._fileService.canHandleResource(uri)) {
|
||||
// cleanup and return when there is no input or when
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import * as nls from 'vs/nls';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
import { EditorInput, IEditorInputFactory, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, TextCompareEditorActiveContext, EditorPinnedContext, EditorGroupEditorsCountContext, EditorStickyContext } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, IEditorInputFactory, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, TextCompareEditorActiveContext, EditorPinnedContext, EditorGroupEditorsCountContext, EditorStickyContext, ActiveEditorAvailableEditorIdsContext } from 'vs/workbench/common/editor';
|
||||
import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor';
|
||||
import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
JoinAllGroupsAction, FocusLeftGroup, FocusAboveGroup, FocusRightGroup, FocusBelowGroup, EditorLayoutSingleAction, EditorLayoutTwoColumnsAction, EditorLayoutThreeColumnsAction, EditorLayoutTwoByTwoGridAction,
|
||||
EditorLayoutTwoRowsAction, EditorLayoutThreeRowsAction, EditorLayoutTwoColumnsBottomAction, EditorLayoutTwoRowsRightAction, NewEditorGroupLeftAction, NewEditorGroupRightAction,
|
||||
NewEditorGroupAboveAction, NewEditorGroupBelowAction, SplitEditorOrthogonalAction, CloseEditorInAllGroupsAction, NavigateToLastEditLocationAction, ToggleGroupSizesAction, ShowAllEditorsByMostRecentlyUsedAction,
|
||||
QuickAccessPreviousRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction, QuickAccessLeastRecentlyUsedEditorAction, QuickAccessLeastRecentlyUsedEditorInGroupAction
|
||||
QuickAccessPreviousRecentlyUsedEditorAction, OpenPreviousRecentlyUsedEditorInGroupAction, OpenNextRecentlyUsedEditorInGroupAction, QuickAccessLeastRecentlyUsedEditorAction, QuickAccessLeastRecentlyUsedEditorInGroupAction, ReopenResourcesAction, ToggleEditorTypeAction
|
||||
} from 'vs/workbench/browser/parts/editor/editorActions';
|
||||
import * as editorCommands from 'vs/workbench/browser/parts/editor/editorCommands';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -173,28 +173,28 @@ interface ISerializedSideBySideEditorInput {
|
||||
name: string;
|
||||
description: string | undefined;
|
||||
|
||||
detailsSerialized: string;
|
||||
masterSerialized: string;
|
||||
primarySerialized: string;
|
||||
secondarySerialized: string;
|
||||
|
||||
detailsTypeId: string;
|
||||
masterTypeId: string;
|
||||
primaryTypeId: string;
|
||||
secondaryTypeId: string;
|
||||
}
|
||||
|
||||
export abstract class AbstractSideBySideEditorInputFactory implements IEditorInputFactory {
|
||||
|
||||
private getInputFactories(detailsId: string, masterId: string): [IEditorInputFactory | undefined, IEditorInputFactory | undefined] {
|
||||
private getInputFactories(secondaryId: string, primaryId: string): [IEditorInputFactory | undefined, IEditorInputFactory | undefined] {
|
||||
const registry = Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories);
|
||||
|
||||
return [registry.getEditorInputFactory(detailsId), registry.getEditorInputFactory(masterId)];
|
||||
return [registry.getEditorInputFactory(secondaryId), registry.getEditorInputFactory(primaryId)];
|
||||
}
|
||||
|
||||
canSerialize(editorInput: EditorInput): boolean {
|
||||
const input = editorInput as SideBySideEditorInput | DiffEditorInput;
|
||||
|
||||
if (input.details && input.master) {
|
||||
const [detailsInputFactory, masterInputFactory] = this.getInputFactories(input.details.getTypeId(), input.master.getTypeId());
|
||||
if (input.primary && input.secondary) {
|
||||
const [secondaryInputFactory, primaryInputFactory] = this.getInputFactories(input.secondary.getTypeId(), input.primary.getTypeId());
|
||||
|
||||
return !!(detailsInputFactory?.canSerialize(input.details) && masterInputFactory?.canSerialize(input.master));
|
||||
return !!(secondaryInputFactory?.canSerialize(input.secondary) && primaryInputFactory?.canSerialize(input.primary));
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -203,20 +203,20 @@ export abstract class AbstractSideBySideEditorInputFactory implements IEditorInp
|
||||
serialize(editorInput: EditorInput): string | undefined {
|
||||
const input = editorInput as SideBySideEditorInput | DiffEditorInput;
|
||||
|
||||
if (input.details && input.master) {
|
||||
const [detailsInputFactory, masterInputFactory] = this.getInputFactories(input.details.getTypeId(), input.master.getTypeId());
|
||||
if (detailsInputFactory && masterInputFactory) {
|
||||
const detailsSerialized = detailsInputFactory.serialize(input.details);
|
||||
const masterSerialized = masterInputFactory.serialize(input.master);
|
||||
if (input.primary && input.secondary) {
|
||||
const [secondaryInputFactory, primaryInputFactory] = this.getInputFactories(input.secondary.getTypeId(), input.primary.getTypeId());
|
||||
if (primaryInputFactory && secondaryInputFactory) {
|
||||
const primarySerialized = primaryInputFactory.serialize(input.primary);
|
||||
const secondarySerialized = secondaryInputFactory.serialize(input.secondary);
|
||||
|
||||
if (detailsSerialized && masterSerialized) {
|
||||
if (primarySerialized && secondarySerialized) {
|
||||
const serializedEditorInput: ISerializedSideBySideEditorInput = {
|
||||
name: input.getName(),
|
||||
description: input.getDescription(),
|
||||
detailsSerialized,
|
||||
masterSerialized,
|
||||
detailsTypeId: input.details.getTypeId(),
|
||||
masterTypeId: input.master.getTypeId()
|
||||
primarySerialized: primarySerialized,
|
||||
secondarySerialized: secondarySerialized,
|
||||
primaryTypeId: input.primary.getTypeId(),
|
||||
secondaryTypeId: input.secondary.getTypeId()
|
||||
};
|
||||
|
||||
return JSON.stringify(serializedEditorInput);
|
||||
@@ -230,33 +230,33 @@ export abstract class AbstractSideBySideEditorInputFactory implements IEditorInp
|
||||
deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): EditorInput | undefined {
|
||||
const deserialized: ISerializedSideBySideEditorInput = JSON.parse(serializedEditorInput);
|
||||
|
||||
const [detailsInputFactory, masterInputFactory] = this.getInputFactories(deserialized.detailsTypeId, deserialized.masterTypeId);
|
||||
if (detailsInputFactory && masterInputFactory) {
|
||||
const detailsInput = detailsInputFactory.deserialize(instantiationService, deserialized.detailsSerialized);
|
||||
const masterInput = masterInputFactory.deserialize(instantiationService, deserialized.masterSerialized);
|
||||
const [secondaryInputFactory, primaryInputFactory] = this.getInputFactories(deserialized.secondaryTypeId, deserialized.primaryTypeId);
|
||||
if (primaryInputFactory && secondaryInputFactory) {
|
||||
const primaryInput = primaryInputFactory.deserialize(instantiationService, deserialized.primarySerialized);
|
||||
const secondaryInput = secondaryInputFactory.deserialize(instantiationService, deserialized.secondarySerialized);
|
||||
|
||||
if (detailsInput && masterInput) {
|
||||
return this.createEditorInput(deserialized.name, deserialized.description, detailsInput, masterInput);
|
||||
if (primaryInput && secondaryInput) {
|
||||
return this.createEditorInput(deserialized.name, deserialized.description, secondaryInput, primaryInput);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected abstract createEditorInput(name: string, description: string | undefined, detailsInput: EditorInput, masterInput: EditorInput): EditorInput;
|
||||
protected abstract createEditorInput(name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput;
|
||||
}
|
||||
|
||||
class SideBySideEditorInputFactory extends AbstractSideBySideEditorInputFactory {
|
||||
|
||||
protected createEditorInput(name: string, description: string | undefined, detailsInput: EditorInput, masterInput: EditorInput): EditorInput {
|
||||
return new SideBySideEditorInput(name, description, detailsInput, masterInput);
|
||||
protected createEditorInput(name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
|
||||
return new SideBySideEditorInput(name, description, secondaryInput, primaryInput);
|
||||
}
|
||||
}
|
||||
|
||||
class DiffEditorInputFactory extends AbstractSideBySideEditorInputFactory {
|
||||
|
||||
protected createEditorInput(name: string, description: string | undefined, detailsInput: EditorInput, masterInput: EditorInput): EditorInput {
|
||||
return new DiffEditorInput(name, description, detailsInput, masterInput);
|
||||
protected createEditorInput(name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
|
||||
return new DiffEditorInput(name, description, secondaryInput, primaryInput);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,6 +386,8 @@ registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutThreeRows
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoByTwoGridAction), 'View: Grid Editor Layout (2x2)', category);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoRowsRightAction), 'View: Two Rows Right Editor Layout', category);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(EditorLayoutTwoColumnsBottomAction), 'View: Two Columns Bottom Editor Layout', category);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(ReopenResourcesAction), 'View: Reopen Editor With...', category, ActiveEditorAvailableEditorIdsContext);
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleEditorTypeAction), 'View: Toggle Editor Type', category, ActiveEditorAvailableEditorIdsContext);
|
||||
|
||||
// Register Quick Editor Actions including built in quick navigate support for some
|
||||
|
||||
@@ -461,6 +463,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.SHOW_EDITORS_IN_GROUP, title: nls.localize('showOpenedEditors', "Show Opened Editors") }, group: '3_open', order: 10, when: ContextKeyExpr.has('config.workbench.editor.showTabs') });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '5_close', order: 10, when: ContextKeyExpr.has('config.workbench.editor.showTabs') });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20, when: ContextKeyExpr.has('config.workbench.editor.showTabs') });
|
||||
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: ReopenResourcesAction.ID, title: ReopenResourcesAction.LABEL }, group: '6_reopen', order: 20, when: ActiveEditorAvailableEditorIdsContext });
|
||||
|
||||
interface IEditorToolItem { id: string; title: string; icon?: { dark?: URI; light?: URI; } | ThemeIcon; }
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IHistoryService } from 'vs/workbench/services/history/common/history';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { CLOSE_EDITOR_COMMAND_ID, MOVE_ACTIVE_EDITOR_COMMAND_ID, ActiveEditorMoveArguments, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, SPLIT_EDITOR_DOWN, splitEditor, LAYOUT_EDITOR_GROUPS_COMMAND_ID, mergeAllGroups } from 'vs/workbench/browser/parts/editor/editorCommands';
|
||||
import { IEditorGroupsService, IEditorGroup, GroupsArrangement, GroupLocation, GroupDirection, preferredSideBySideGroupDirection, IFindGroupScope, GroupOrientation, EditorGroupLayout, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorGroupsService, IEditorGroup, GroupsArrangement, GroupLocation, GroupDirection, preferredSideBySideGroupDirection, IFindGroupScope, GroupOrientation, EditorGroupLayout, GroupsOrder, OpenEditorContext } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
@@ -22,6 +22,7 @@ import { ItemActivation, IQuickInputService } from 'vs/platform/quickinput/commo
|
||||
import { AllEditorsByMostRecentlyUsedQuickAccess, ActiveGroupEditorsByMostRecentlyUsedQuickAccess, AllEditorsByAppearanceQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { IFilesConfigurationService, AutoSaveMode } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
|
||||
import { openEditorWith, getAllAvailableEditors } from 'vs/workbench/services/editor/common/editorOpenWith';
|
||||
|
||||
export class ExecuteCommandAction extends Action {
|
||||
|
||||
@@ -580,7 +581,7 @@ abstract class BaseCloseAllAction extends Action {
|
||||
else {
|
||||
let name: string;
|
||||
if (editor instanceof SideBySideEditorInput) {
|
||||
name = editor.master.getName(); // prefer shorter names by using master's name in this case
|
||||
name = editor.primary.getName(); // prefer shorter names by using primary's name in this case
|
||||
} else {
|
||||
name = editor.getName();
|
||||
}
|
||||
@@ -1775,3 +1776,72 @@ export class NewEditorGroupBelowAction extends BaseCreateEditorGroupAction {
|
||||
super(id, label, GroupDirection.DOWN, editorGroupService);
|
||||
}
|
||||
}
|
||||
|
||||
export class ReopenResourcesAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.action.reopenWithEditor';
|
||||
static readonly LABEL = nls.localize('workbench.action.reopenWithEditor', "Reopen Editor With...");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
const activeInput = this.editorService.activeEditor;
|
||||
if (!activeInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
const activeEditorPane = this.editorService.activeEditorPane;
|
||||
if (!activeEditorPane) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = activeEditorPane.options;
|
||||
const group = activeEditorPane.group;
|
||||
await openEditorWith(activeInput, undefined, options, group, this.editorService, this.configurationService, this.quickInputService);
|
||||
}
|
||||
}
|
||||
|
||||
export class ToggleEditorTypeAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.action.toggleEditorType';
|
||||
static readonly LABEL = nls.localize('workbench.action.toggleEditorType', "Toggle Editor Type");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
const activeEditorPane = this.editorService.activeEditorPane;
|
||||
if (!activeEditorPane) {
|
||||
return;
|
||||
}
|
||||
|
||||
const input = activeEditorPane.input;
|
||||
if (!input.resource) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = activeEditorPane.options;
|
||||
const group = activeEditorPane.group;
|
||||
|
||||
const overrides = getAllAvailableEditors(input.resource, options, group, this.editorService);
|
||||
const firstNonActiveOverride = overrides.find(([_, entry]) => !entry.active);
|
||||
if (!firstNonActiveOverride) {
|
||||
return;
|
||||
}
|
||||
|
||||
await firstNonActiveOverride[0].open(input, { ...options, override: firstNonActiveOverride[1].id }, group, OpenEditorContext.NEW_EDITOR)?.override;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,8 +530,12 @@ class DropOverlay extends Themable {
|
||||
}
|
||||
}
|
||||
|
||||
export interface EditorDropTargetDelegate {
|
||||
groupContainsPredicate?(groupView: IEditorGroupView): boolean;
|
||||
export interface IEditorDropTargetDelegate {
|
||||
|
||||
/**
|
||||
* A helper to figure out if the drop target contains the provided group.
|
||||
*/
|
||||
containsGroup?(groupView: IEditorGroupView): boolean;
|
||||
}
|
||||
|
||||
export class EditorDropTarget extends Themable {
|
||||
@@ -546,7 +550,7 @@ export class EditorDropTarget extends Themable {
|
||||
constructor(
|
||||
private accessor: IEditorGroupsAccessor,
|
||||
private container: HTMLElement,
|
||||
private readonly delegate: EditorDropTargetDelegate,
|
||||
private readonly delegate: IEditorDropTargetDelegate,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService
|
||||
) {
|
||||
@@ -620,7 +624,8 @@ export class EditorDropTarget extends Themable {
|
||||
|
||||
private findTargetGroupView(child: HTMLElement): IEditorGroupView | undefined {
|
||||
const groups = this.accessor.groups;
|
||||
return groups.find(groupView => isAncestor(child, groupView.element) || this.delegate.groupContainsPredicate?.(groupView));
|
||||
|
||||
return groups.find(groupView => isAncestor(child, groupView.element) || this.delegate.containsGroup?.(groupView));
|
||||
}
|
||||
|
||||
private updateContainer(isDraggedOver: boolean): void {
|
||||
|
||||
@@ -527,7 +527,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
|
||||
// Include both sides of side by side editors when being closed
|
||||
if (editor instanceof SideBySideEditorInput) {
|
||||
editorsToClose.push(editor.master, editor.details);
|
||||
editorsToClose.push(editor.primary, editor.secondary);
|
||||
}
|
||||
|
||||
// For each editor to close, we call dispose() to free up any resources.
|
||||
@@ -537,7 +537,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
for (const editor of editorsToClose) {
|
||||
if (!this.accessor.groups.some(groupView => groupView.group.contains(editor, {
|
||||
strictEquals: true, // only if this input is not shared across editor groups
|
||||
supportSideBySide: true // include side by side editor master & details
|
||||
supportSideBySide: true // include side by side editor primary & secondary
|
||||
}))) {
|
||||
editor.dispose();
|
||||
}
|
||||
@@ -1359,8 +1359,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
return false; // editor must be dirty and not saving
|
||||
}
|
||||
|
||||
if (editor instanceof SideBySideEditorInput && this._group.contains(editor.master)) {
|
||||
return false; // master-side of editor is still opened somewhere else
|
||||
if (editor instanceof SideBySideEditorInput && this._group.contains(editor.primary)) {
|
||||
return false; // primary-side of editor is still opened somewhere else
|
||||
}
|
||||
|
||||
// Note: we explicitly decide to ask for confirm if closing a normal editor even
|
||||
@@ -1378,8 +1378,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
return true; // exact editor still opened
|
||||
}
|
||||
|
||||
if (editor instanceof SideBySideEditorInput && otherGroup.contains(editor.master)) {
|
||||
return true; // master side of side by side editor still opened
|
||||
if (editor instanceof SideBySideEditorInput && otherGroup.contains(editor.primary)) {
|
||||
return true; // primary side of side by side editor still opened
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -1404,7 +1404,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
|
||||
let name: string;
|
||||
if (editor instanceof SideBySideEditorInput) {
|
||||
name = editor.master.getName(); // prefer shorter names by using master's name in this case
|
||||
name = editor.primary.getName(); // prefer shorter names by using primary's name in this case
|
||||
} else {
|
||||
name = editor.getName();
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/co
|
||||
import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup';
|
||||
import { EditorDropTarget, EditorDropTargetDelegate } from 'vs/workbench/browser/parts/editor/editorDropTarget';
|
||||
import { EditorDropTarget, IEditorDropTargetDelegate } from 'vs/workbench/browser/parts/editor/editorDropTarget';
|
||||
import { IEditorDropService } from 'vs/workbench/services/editor/browser/editorDropService';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { CenteredViewLayout } from 'vs/base/browser/ui/centered/centeredViewLayout';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
@@ -780,6 +781,14 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region IEditorDropService
|
||||
|
||||
createEditorDropTarget(container: HTMLElement, delegate: IEditorDropTargetDelegate): IDisposable {
|
||||
return this.instantiationService.createInstance(EditorDropTarget, this, container, delegate);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Part
|
||||
|
||||
// TODO @sbatten @joao find something better to prevent editor taking over #79897
|
||||
@@ -820,7 +829,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
||||
this.centeredLayoutWidget = this._register(new CenteredViewLayout(this.container, this.gridWidgetView, this.globalMemento[EditorPart.EDITOR_PART_CENTERED_VIEW_STORAGE_KEY]));
|
||||
|
||||
// Drop support
|
||||
this._register(this.createEditorDropTarget(this.container, {}));
|
||||
this._register(this.createEditorDropTarget(this.container, Object.create(null)));
|
||||
|
||||
// No drop in the editor
|
||||
const overlay = document.createElement('div');
|
||||
@@ -1097,16 +1106,24 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
||||
}
|
||||
|
||||
// Persist centered view state
|
||||
const centeredLayoutState = this.centeredLayoutWidget.state;
|
||||
if (this.centeredLayoutWidget.isDefault(centeredLayoutState)) {
|
||||
delete this.globalMemento[EditorPart.EDITOR_PART_CENTERED_VIEW_STORAGE_KEY];
|
||||
} else {
|
||||
this.globalMemento[EditorPart.EDITOR_PART_CENTERED_VIEW_STORAGE_KEY] = centeredLayoutState;
|
||||
if (this.centeredLayoutWidget) {
|
||||
const centeredLayoutState = this.centeredLayoutWidget.state;
|
||||
if (this.centeredLayoutWidget.isDefault(centeredLayoutState)) {
|
||||
delete this.globalMemento[EditorPart.EDITOR_PART_CENTERED_VIEW_STORAGE_KEY];
|
||||
} else {
|
||||
this.globalMemento[EditorPart.EDITOR_PART_CENTERED_VIEW_STORAGE_KEY] = centeredLayoutState;
|
||||
}
|
||||
}
|
||||
|
||||
super.saveState();
|
||||
}
|
||||
|
||||
toJSON(): object {
|
||||
return {
|
||||
type: Parts.EDITOR_PART
|
||||
};
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
||||
// Forward to all groups
|
||||
@@ -1122,20 +1139,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
toJSON(): object {
|
||||
return {
|
||||
type: Parts.EDITOR_PART
|
||||
};
|
||||
}
|
||||
|
||||
//#region TODO@matt this should move into some kind of service
|
||||
|
||||
createEditorDropTarget(container: HTMLElement, delegate: EditorDropTargetDelegate): IDisposable {
|
||||
return this.instantiationService.createInstance(EditorDropTarget, this, container, delegate);
|
||||
}
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
registerSingleton(IEditorGroupsService, EditorPart);
|
||||
registerSingleton(IEditorDropService, EditorPart);
|
||||
|
||||
@@ -137,7 +137,7 @@ export abstract class BaseEditorQuickAccessProvider extends PickerQuickAccessPro
|
||||
}
|
||||
|
||||
return this.doGetEditors().map(({ editor, groupId }): IEditorQuickPickItem => {
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.PRIMARY });
|
||||
const isDirty = editor.isDirty() && !editor.isSaving();
|
||||
const description = editor.getDescription();
|
||||
const nameAndDescription = description ? `${editor.getName()} ${description}` : editor.getName();
|
||||
|
||||
@@ -54,22 +54,22 @@ import { STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGRO
|
||||
import { themeColorFromId } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
class SideBySideEditorEncodingSupport implements IEncodingSupport {
|
||||
constructor(private master: IEncodingSupport, private details: IEncodingSupport) { }
|
||||
constructor(private primary: IEncodingSupport, private secondary: IEncodingSupport) { }
|
||||
|
||||
getEncoding(): string | undefined {
|
||||
return this.master.getEncoding(); // always report from modified (right hand) side
|
||||
return this.primary.getEncoding(); // always report from modified (right hand) side
|
||||
}
|
||||
|
||||
setEncoding(encoding: string, mode: EncodingMode): void {
|
||||
[this.master, this.details].forEach(editor => editor.setEncoding(encoding, mode));
|
||||
[this.primary, this.secondary].forEach(editor => editor.setEncoding(encoding, mode));
|
||||
}
|
||||
}
|
||||
|
||||
class SideBySideEditorModeSupport implements IModeSupport {
|
||||
constructor(private master: IModeSupport, private details: IModeSupport) { }
|
||||
constructor(private primary: IModeSupport, private secondary: IModeSupport) { }
|
||||
|
||||
setMode(mode: string): void {
|
||||
[this.master, this.details].forEach(editor => editor.setMode(mode));
|
||||
[this.primary, this.secondary].forEach(editor => editor.setMode(mode));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,14 +82,14 @@ function toEditorWithEncodingSupport(input: IEditorInput): IEncodingSupport | nu
|
||||
|
||||
// Side by Side (diff) Editor
|
||||
if (input instanceof SideBySideEditorInput) {
|
||||
const masterEncodingSupport = toEditorWithEncodingSupport(input.master);
|
||||
const detailsEncodingSupport = toEditorWithEncodingSupport(input.details);
|
||||
const primaryEncodingSupport = toEditorWithEncodingSupport(input.primary);
|
||||
const secondaryEncodingSupport = toEditorWithEncodingSupport(input.secondary);
|
||||
|
||||
if (masterEncodingSupport && detailsEncodingSupport) {
|
||||
return new SideBySideEditorEncodingSupport(masterEncodingSupport, detailsEncodingSupport);
|
||||
if (primaryEncodingSupport && secondaryEncodingSupport) {
|
||||
return new SideBySideEditorEncodingSupport(primaryEncodingSupport, secondaryEncodingSupport);
|
||||
}
|
||||
|
||||
return masterEncodingSupport;
|
||||
return primaryEncodingSupport;
|
||||
}
|
||||
|
||||
// File or Resource Editor
|
||||
@@ -111,14 +111,14 @@ function toEditorWithModeSupport(input: IEditorInput): IModeSupport | null {
|
||||
|
||||
// Side by Side (diff) Editor
|
||||
if (input instanceof SideBySideEditorInput) {
|
||||
const masterModeSupport = toEditorWithModeSupport(input.master);
|
||||
const detailsModeSupport = toEditorWithModeSupport(input.details);
|
||||
const primaryModeSupport = toEditorWithModeSupport(input.primary);
|
||||
const secondaryModeSupport = toEditorWithModeSupport(input.secondary);
|
||||
|
||||
if (masterModeSupport && detailsModeSupport) {
|
||||
return new SideBySideEditorModeSupport(masterModeSupport, detailsModeSupport);
|
||||
if (primaryModeSupport && secondaryModeSupport) {
|
||||
return new SideBySideEditorModeSupport(primaryModeSupport, secondaryModeSupport);
|
||||
}
|
||||
|
||||
return masterModeSupport;
|
||||
return primaryModeSupport;
|
||||
}
|
||||
|
||||
// File or Resource Editor
|
||||
@@ -685,14 +685,14 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
||||
else if (activeEditorPane instanceof BaseBinaryResourceEditor || activeEditorPane instanceof BinaryResourceDiffEditor) {
|
||||
const binaryEditors: BaseBinaryResourceEditor[] = [];
|
||||
if (activeEditorPane instanceof BinaryResourceDiffEditor) {
|
||||
const details = activeEditorPane.getDetailsEditorPane();
|
||||
if (details instanceof BaseBinaryResourceEditor) {
|
||||
binaryEditors.push(details);
|
||||
const primary = activeEditorPane.getPrimaryEditorPane();
|
||||
if (primary instanceof BaseBinaryResourceEditor) {
|
||||
binaryEditors.push(primary);
|
||||
}
|
||||
|
||||
const master = activeEditorPane.getMasterEditorPane();
|
||||
if (master instanceof BaseBinaryResourceEditor) {
|
||||
binaryEditors.push(master);
|
||||
const secondary = activeEditorPane.getSecondaryEditorPane();
|
||||
if (secondary instanceof BaseBinaryResourceEditor) {
|
||||
binaryEditors.push(secondary);
|
||||
}
|
||||
} else {
|
||||
binaryEditors.push(activeEditorPane);
|
||||
@@ -871,7 +871,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
|
||||
private onResourceEncodingChange(resource: URI): void {
|
||||
const activeEditorPane = this.editorService.activeEditorPane;
|
||||
if (activeEditorPane) {
|
||||
const activeResource = toResource(activeEditorPane.input, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
const activeResource = toResource(activeEditorPane.input, { supportSideBySide: SideBySideEditor.PRIMARY });
|
||||
if (activeResource && isEqual(activeResource, resource)) {
|
||||
const activeCodeEditor = withNullAsUndefined(getCodeEditor(activeEditorPane.getControl()));
|
||||
|
||||
@@ -1064,7 +1064,7 @@ export class ChangeModeAction extends Action {
|
||||
}
|
||||
|
||||
const textModel = activeTextEditorControl.getModel();
|
||||
const resource = this.editorService.activeEditor ? toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.MASTER }) : null;
|
||||
const resource = this.editorService.activeEditor ? toResource(this.editorService.activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY }) : null;
|
||||
|
||||
let hasLanguageSupport = !!resource;
|
||||
if (resource?.scheme === Schemas.untitled && !this.textFileService.untitled.get(resource)?.hasAssociatedFilePath) {
|
||||
@@ -1161,7 +1161,7 @@ export class ChangeModeAction extends Action {
|
||||
let languageSelection: ILanguageSelection | undefined;
|
||||
if (pick === autoDetectMode) {
|
||||
if (textModel) {
|
||||
const resource = toResource(activeEditor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
const resource = toResource(activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY });
|
||||
if (resource) {
|
||||
languageSelection = this.modeService.createByFilepathOrFirstLine(resource, textModel.getLineContent(1));
|
||||
}
|
||||
@@ -1356,7 +1356,7 @@ export class ChangeEncodingAction extends Action {
|
||||
|
||||
await timeout(50); // quick input is sensitive to being opened so soon after another
|
||||
|
||||
const resource = toResource(activeEditorPane.input, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
const resource = toResource(activeEditorPane.input, { supportSideBySide: SideBySideEditor.PRIMARY });
|
||||
if (!resource || (!this.fileService.canHandleResource(resource) && resource.scheme !== Schemas.untitled)) {
|
||||
return; // encoding detection only possible for resources the file service can handle or that are untitled
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ export class EditorsObserver extends Disposable {
|
||||
}
|
||||
|
||||
private updateEditorResourcesMap(editor: IEditorInput, add: boolean): void {
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.PRIMARY });
|
||||
if (!resource) {
|
||||
return; // require a resource
|
||||
}
|
||||
|
||||
@@ -22,17 +22,16 @@ import { assertIsDefined } from 'vs/base/common/types';
|
||||
export class SideBySideEditor extends BaseEditor {
|
||||
|
||||
static readonly ID: string = 'workbench.editor.sidebysideEditor';
|
||||
static MASTER: SideBySideEditor | undefined;
|
||||
|
||||
get minimumMasterWidth() { return this.masterEditorPane ? this.masterEditorPane.minimumWidth : 0; }
|
||||
get maximumMasterWidth() { return this.masterEditorPane ? this.masterEditorPane.maximumWidth : Number.POSITIVE_INFINITY; }
|
||||
get minimumMasterHeight() { return this.masterEditorPane ? this.masterEditorPane.minimumHeight : 0; }
|
||||
get maximumMasterHeight() { return this.masterEditorPane ? this.masterEditorPane.maximumHeight : Number.POSITIVE_INFINITY; }
|
||||
private get minimumPrimaryWidth() { return this.primaryEditorPane ? this.primaryEditorPane.minimumWidth : 0; }
|
||||
private get maximumPrimaryWidth() { return this.primaryEditorPane ? this.primaryEditorPane.maximumWidth : Number.POSITIVE_INFINITY; }
|
||||
private get minimumPrimaryHeight() { return this.primaryEditorPane ? this.primaryEditorPane.minimumHeight : 0; }
|
||||
private get maximumPrimaryHeight() { return this.primaryEditorPane ? this.primaryEditorPane.maximumHeight : Number.POSITIVE_INFINITY; }
|
||||
|
||||
get minimumDetailsWidth() { return this.detailsEditorPane ? this.detailsEditorPane.minimumWidth : 0; }
|
||||
get maximumDetailsWidth() { return this.detailsEditorPane ? this.detailsEditorPane.maximumWidth : Number.POSITIVE_INFINITY; }
|
||||
get minimumDetailsHeight() { return this.detailsEditorPane ? this.detailsEditorPane.minimumHeight : 0; }
|
||||
get maximumDetailsHeight() { return this.detailsEditorPane ? this.detailsEditorPane.maximumHeight : Number.POSITIVE_INFINITY; }
|
||||
private get minimumSecondaryWidth() { return this.secondaryEditorPane ? this.secondaryEditorPane.minimumWidth : 0; }
|
||||
private get maximumSecondaryWidth() { return this.secondaryEditorPane ? this.secondaryEditorPane.maximumWidth : Number.POSITIVE_INFINITY; }
|
||||
private get minimumSecondaryHeight() { return this.secondaryEditorPane ? this.secondaryEditorPane.minimumHeight : 0; }
|
||||
private get maximumSecondaryHeight() { return this.secondaryEditorPane ? this.secondaryEditorPane.maximumHeight : Number.POSITIVE_INFINITY; }
|
||||
|
||||
// these setters need to exist because this extends from BaseEditor
|
||||
set minimumWidth(value: number) { /* noop */ }
|
||||
@@ -40,16 +39,16 @@ export class SideBySideEditor extends BaseEditor {
|
||||
set minimumHeight(value: number) { /* noop */ }
|
||||
set maximumHeight(value: number) { /* noop */ }
|
||||
|
||||
get minimumWidth() { return this.minimumMasterWidth + this.minimumDetailsWidth; }
|
||||
get maximumWidth() { return this.maximumMasterWidth + this.maximumDetailsWidth; }
|
||||
get minimumHeight() { return this.minimumMasterHeight + this.minimumDetailsHeight; }
|
||||
get maximumHeight() { return this.maximumMasterHeight + this.maximumDetailsHeight; }
|
||||
get minimumWidth() { return this.minimumPrimaryWidth + this.minimumSecondaryWidth; }
|
||||
get maximumWidth() { return this.maximumPrimaryWidth + this.maximumSecondaryWidth; }
|
||||
get minimumHeight() { return this.minimumPrimaryHeight + this.minimumSecondaryHeight; }
|
||||
get maximumHeight() { return this.maximumPrimaryHeight + this.maximumSecondaryHeight; }
|
||||
|
||||
protected masterEditorPane?: BaseEditor;
|
||||
protected detailsEditorPane?: BaseEditor;
|
||||
protected primaryEditorPane?: BaseEditor;
|
||||
protected secondaryEditorPane?: BaseEditor;
|
||||
|
||||
private masterEditorContainer: HTMLElement | undefined;
|
||||
private detailsEditorContainer: HTMLElement | undefined;
|
||||
private primaryEditorContainer: HTMLElement | undefined;
|
||||
private secondaryEditorContainer: HTMLElement | undefined;
|
||||
|
||||
private splitview: SplitView | undefined;
|
||||
private dimension: DOM.Dimension = new DOM.Dimension(0, 0);
|
||||
@@ -74,19 +73,19 @@ export class SideBySideEditor extends BaseEditor {
|
||||
const splitview = this.splitview = this._register(new SplitView(parent, { orientation: Orientation.HORIZONTAL }));
|
||||
this._register(this.splitview.onDidSashReset(() => splitview.distributeViewSizes()));
|
||||
|
||||
this.detailsEditorContainer = DOM.$('.details-editor-container');
|
||||
this.secondaryEditorContainer = DOM.$('.secondary-editor-container');
|
||||
this.splitview.addView({
|
||||
element: this.detailsEditorContainer,
|
||||
layout: size => this.detailsEditorPane && this.detailsEditorPane.layout(new DOM.Dimension(size, this.dimension.height)),
|
||||
element: this.secondaryEditorContainer,
|
||||
layout: size => this.secondaryEditorPane && this.secondaryEditorPane.layout(new DOM.Dimension(size, this.dimension.height)),
|
||||
minimumSize: 220,
|
||||
maximumSize: Number.POSITIVE_INFINITY,
|
||||
onDidChange: Event.None
|
||||
}, Sizing.Distribute);
|
||||
|
||||
this.masterEditorContainer = DOM.$('.master-editor-container');
|
||||
this.primaryEditorContainer = DOM.$('.primary-editor-container');
|
||||
this.splitview.addView({
|
||||
element: this.masterEditorContainer,
|
||||
layout: size => this.masterEditorPane && this.masterEditorPane.layout(new DOM.Dimension(size, this.dimension.height)),
|
||||
element: this.primaryEditorContainer,
|
||||
layout: size => this.primaryEditorPane && this.primaryEditorPane.layout(new DOM.Dimension(size, this.dimension.height)),
|
||||
minimumSize: 220,
|
||||
maximumSize: Number.POSITIVE_INFINITY,
|
||||
onDidChange: Event.None
|
||||
@@ -103,30 +102,30 @@ export class SideBySideEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
setOptions(options: EditorOptions | undefined): void {
|
||||
if (this.masterEditorPane) {
|
||||
this.masterEditorPane.setOptions(options);
|
||||
if (this.primaryEditorPane) {
|
||||
this.primaryEditorPane.setOptions(options);
|
||||
}
|
||||
}
|
||||
|
||||
protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void {
|
||||
if (this.masterEditorPane) {
|
||||
this.masterEditorPane.setVisible(visible, group);
|
||||
if (this.primaryEditorPane) {
|
||||
this.primaryEditorPane.setVisible(visible, group);
|
||||
}
|
||||
|
||||
if (this.detailsEditorPane) {
|
||||
this.detailsEditorPane.setVisible(visible, group);
|
||||
if (this.secondaryEditorPane) {
|
||||
this.secondaryEditorPane.setVisible(visible, group);
|
||||
}
|
||||
|
||||
super.setEditorVisible(visible, group);
|
||||
}
|
||||
|
||||
clearInput(): void {
|
||||
if (this.masterEditorPane) {
|
||||
this.masterEditorPane.clearInput();
|
||||
if (this.primaryEditorPane) {
|
||||
this.primaryEditorPane.clearInput();
|
||||
}
|
||||
|
||||
if (this.detailsEditorPane) {
|
||||
this.detailsEditorPane.clearInput();
|
||||
if (this.secondaryEditorPane) {
|
||||
this.secondaryEditorPane.clearInput();
|
||||
}
|
||||
|
||||
this.disposeEditors();
|
||||
@@ -135,8 +134,8 @@ export class SideBySideEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
if (this.masterEditorPane) {
|
||||
this.masterEditorPane.focus();
|
||||
if (this.primaryEditorPane) {
|
||||
this.primaryEditorPane.focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,19 +147,19 @@ export class SideBySideEditor extends BaseEditor {
|
||||
}
|
||||
|
||||
getControl(): IEditorControl | undefined {
|
||||
if (this.masterEditorPane) {
|
||||
return this.masterEditorPane.getControl();
|
||||
if (this.primaryEditorPane) {
|
||||
return this.primaryEditorPane.getControl();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getMasterEditorPane(): IEditorPane | undefined {
|
||||
return this.masterEditorPane;
|
||||
getPrimaryEditorPane(): IEditorPane | undefined {
|
||||
return this.primaryEditorPane;
|
||||
}
|
||||
|
||||
getDetailsEditorPane(): IEditorPane | undefined {
|
||||
return this.detailsEditorPane;
|
||||
getSecondaryEditorPane(): IEditorPane | undefined {
|
||||
return this.secondaryEditorPane;
|
||||
}
|
||||
|
||||
private async updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
@@ -172,21 +171,21 @@ export class SideBySideEditor extends BaseEditor {
|
||||
return this.setNewInput(newInput, options, token);
|
||||
}
|
||||
|
||||
if (!this.detailsEditorPane || !this.masterEditorPane) {
|
||||
if (!this.secondaryEditorPane || !this.primaryEditorPane) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
this.detailsEditorPane.setInput(newInput.details, undefined, token),
|
||||
this.masterEditorPane.setInput(newInput.master, options, token)
|
||||
this.secondaryEditorPane.setInput(newInput.secondary, undefined, token),
|
||||
this.primaryEditorPane.setInput(newInput.primary, options, token)
|
||||
]);
|
||||
}
|
||||
|
||||
private setNewInput(newInput: SideBySideEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
const detailsEditor = this.doCreateEditor(newInput.details, assertIsDefined(this.detailsEditorContainer));
|
||||
const masterEditor = this.doCreateEditor(newInput.master, assertIsDefined(this.masterEditorContainer));
|
||||
const secondaryEditor = this.doCreateEditor(newInput.secondary, assertIsDefined(this.secondaryEditorContainer));
|
||||
const primaryEditor = this.doCreateEditor(newInput.primary, assertIsDefined(this.primaryEditorContainer));
|
||||
|
||||
return this.onEditorsCreated(detailsEditor, masterEditor, newInput.details, newInput.master, options, token);
|
||||
return this.onEditorsCreated(secondaryEditor, primaryEditor, newInput.secondary, newInput.primary, options, token);
|
||||
}
|
||||
|
||||
private doCreateEditor(editorInput: EditorInput, container: HTMLElement): BaseEditor {
|
||||
@@ -202,48 +201,48 @@ export class SideBySideEditor extends BaseEditor {
|
||||
return editor;
|
||||
}
|
||||
|
||||
private async onEditorsCreated(details: BaseEditor, master: BaseEditor, detailsInput: EditorInput, masterInput: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
this.detailsEditorPane = details;
|
||||
this.masterEditorPane = master;
|
||||
private async onEditorsCreated(secondary: BaseEditor, primary: BaseEditor, secondaryInput: EditorInput, primaryInput: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
|
||||
this.secondaryEditorPane = secondary;
|
||||
this.primaryEditorPane = primary;
|
||||
|
||||
this._onDidSizeConstraintsChange.input = Event.any(
|
||||
Event.map(details.onDidSizeConstraintsChange, () => undefined),
|
||||
Event.map(master.onDidSizeConstraintsChange, () => undefined)
|
||||
Event.map(secondary.onDidSizeConstraintsChange, () => undefined),
|
||||
Event.map(primary.onDidSizeConstraintsChange, () => undefined)
|
||||
);
|
||||
|
||||
this.onDidCreateEditors.fire(undefined);
|
||||
|
||||
await Promise.all([
|
||||
this.detailsEditorPane.setInput(detailsInput, undefined, token),
|
||||
this.masterEditorPane.setInput(masterInput, options, token)]
|
||||
this.secondaryEditorPane.setInput(secondaryInput, undefined, token),
|
||||
this.primaryEditorPane.setInput(primaryInput, options, token)]
|
||||
);
|
||||
}
|
||||
|
||||
updateStyles(): void {
|
||||
super.updateStyles();
|
||||
|
||||
if (this.masterEditorContainer) {
|
||||
this.masterEditorContainer.style.boxShadow = `-6px 0 5px -5px ${this.getColor(scrollbarShadow)}`;
|
||||
if (this.primaryEditorContainer) {
|
||||
this.primaryEditorContainer.style.boxShadow = `-6px 0 5px -5px ${this.getColor(scrollbarShadow)}`;
|
||||
}
|
||||
}
|
||||
|
||||
private disposeEditors(): void {
|
||||
if (this.detailsEditorPane) {
|
||||
this.detailsEditorPane.dispose();
|
||||
this.detailsEditorPane = undefined;
|
||||
if (this.secondaryEditorPane) {
|
||||
this.secondaryEditorPane.dispose();
|
||||
this.secondaryEditorPane = undefined;
|
||||
}
|
||||
|
||||
if (this.masterEditorPane) {
|
||||
this.masterEditorPane.dispose();
|
||||
this.masterEditorPane = undefined;
|
||||
if (this.primaryEditorPane) {
|
||||
this.primaryEditorPane.dispose();
|
||||
this.primaryEditorPane = undefined;
|
||||
}
|
||||
|
||||
if (this.detailsEditorContainer) {
|
||||
DOM.clearNode(this.detailsEditorContainer);
|
||||
if (this.secondaryEditorContainer) {
|
||||
DOM.clearNode(this.secondaryEditorContainer);
|
||||
}
|
||||
|
||||
if (this.masterEditorContainer) {
|
||||
DOM.clearNode(this.masterEditorContainer);
|
||||
if (this.primaryEditorContainer) {
|
||||
DOM.clearNode(this.primaryEditorContainer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1087,7 +1087,7 @@ export class TabsTitleControl extends TitleControl {
|
||||
);
|
||||
|
||||
// Tests helper
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER });
|
||||
const resource = toResource(editor, { supportSideBySide: SideBySideEditor.PRIMARY });
|
||||
if (resource) {
|
||||
tabContainer.setAttribute('data-resource-name', basenameOrAuthority(resource));
|
||||
} else {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user