mirror of
https://github.com/Microsoft/vscode
synced 2024-09-19 18:48:00 +00:00
Merge branch 'master' into link
This commit is contained in:
commit
9fce34075f
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -39,6 +39,7 @@
|
|||
],
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"npm.exclude": "**/extensions/**",
|
||||
"npm.packageManager": "yarn",
|
||||
"emmet.excludeLanguages": [],
|
||||
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||
"typescript.preferences.quoteStyle": "single",
|
||||
|
|
|
@ -114,6 +114,7 @@ const copyrightFilter = [
|
|||
'!**/*.opts',
|
||||
'!**/*.disabled',
|
||||
'!**/*.code-workspace',
|
||||
'!**/*.js.map',
|
||||
'!**/promise-polyfill/polyfill.js',
|
||||
'!build/**/*.init',
|
||||
'!resources/linux/snap/snapcraft.yaml',
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
"request": "^2.85.0",
|
||||
"terser": "4.3.8",
|
||||
"tslint": "^5.9.1",
|
||||
"typescript": "3.7.0-dev.20191017",
|
||||
"typescript": "3.7.1-rc",
|
||||
"vsce": "1.48.0",
|
||||
"vscode-telemetry-extractor": "^1.5.4",
|
||||
"xml2js": "^0.4.17"
|
||||
|
|
|
@ -2297,10 +2297,10 @@ typed-rest-client@^0.9.0:
|
|||
tunnel "0.0.4"
|
||||
underscore "1.8.3"
|
||||
|
||||
typescript@3.7.0-dev.20191017:
|
||||
version "3.7.0-dev.20191017"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.0-dev.20191017.tgz#e61440dd445edea6d7b9a699e7c5d5fbcd1906f2"
|
||||
integrity sha512-Yi0lCPEN0cn9Gp8TEEkPpgKNR5SWAmx9Hmzzz+oEuivw6amURqRGynaLyFZkMA9iMsvYG5LLqhdlFO3uu5ZT/w==
|
||||
typescript@3.7.1-rc:
|
||||
version "3.7.1-rc"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.1-rc.tgz#2054b872d67f8dc732e36c1df397f9327f37ada0"
|
||||
integrity sha512-2rMtWppLsaPvmpXsoIAXWDBQVnJMw1ITGGSnidMuayLj9iCmMRT69ncKZw/Mk5rXfJkilApKucWQZxproALoRw==
|
||||
|
||||
typescript@^3.0.1:
|
||||
version "3.5.3"
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
"git": {
|
||||
"name": "vscode-codicons",
|
||||
"repositoryUrl": "https://github.com/microsoft/vscode-codicons",
|
||||
"commitHash": "7f14c092f65f658cd520df3f13765efe828d0ba4"
|
||||
"commitHash": "3e404025e1ce19702f5363ef6dd3339bfc6d9115"
|
||||
}
|
||||
},
|
||||
"license": "MIT and Creative Commons Attribution 4.0",
|
||||
|
|
|
@ -401,6 +401,11 @@
|
|||
"command": "git.stashApplyLatest",
|
||||
"title": "%command.stashApplyLatest%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.stashDrop",
|
||||
"title": "%command.stashDrop%",
|
||||
"category": "Git"
|
||||
}
|
||||
],
|
||||
"menus": {
|
||||
|
@ -573,10 +578,6 @@
|
|||
"command": "git.deleteTag",
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.getTags",
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.fetch",
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
|
||||
|
@ -664,6 +665,10 @@
|
|||
{
|
||||
"command": "git.stashApplyLatest",
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.stashDrop",
|
||||
"when": "config.git.enabled && gitOpenRepositoryCount != 0"
|
||||
}
|
||||
],
|
||||
"scm/title": [
|
||||
|
@ -817,6 +822,11 @@
|
|||
"group": "6_stash",
|
||||
"when": "scmProvider == git"
|
||||
},
|
||||
{
|
||||
"command": "git.stashDrop",
|
||||
"group": "6_stash",
|
||||
"when": "scmProvider == git"
|
||||
},
|
||||
{
|
||||
"command": "git.showOutput",
|
||||
"group": "7_repository",
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
"command.stashPopLatest": "Pop Latest Stash",
|
||||
"command.stashApply": "Apply Stash...",
|
||||
"command.stashApplyLatest": "Apply Latest Stash",
|
||||
"command.stashDrop": "Drop Stash...",
|
||||
"config.enabled": "Whether git is enabled.",
|
||||
"config.path": "Path and filename of the git executable, e.g. `C:\\Program Files\\Git\\bin\\git.exe` (Windows).",
|
||||
"config.autoRepositoryDetection": "Configures when repositories should be automatically detected.",
|
||||
|
@ -120,7 +121,7 @@
|
|||
"config.scanRepositories": "List of paths to search for git repositories in.",
|
||||
"config.showProgress": "Controls whether git actions should show progress.",
|
||||
"config.rebaseWhenSync": "Force git to use rebase when running the sync command.",
|
||||
"config.confirmEmptyCommits": "Always confirm the creation of empty commits.",
|
||||
"config.confirmEmptyCommits": "Always confirm the creation of empty commits for the 'Git: Commit Empty' command.",
|
||||
"config.fetchOnPull": "Fetch all branches when pulling or just the current one.",
|
||||
"config.pullTags": "Fetch all tags when pulling.",
|
||||
"config.autoStash": "Stash any changes before pulling and restore them after successful pull.",
|
||||
|
|
|
@ -2241,6 +2241,18 @@ export class CommandCenter {
|
|||
await repository.applyStash();
|
||||
}
|
||||
|
||||
@command('git.stashDrop', { repository: true })
|
||||
async stashDrop(repository: Repository): Promise<void> {
|
||||
const placeHolder = localize('pick stash to drop', "Pick a stash to drop");
|
||||
const stash = await this.pickStash(repository, placeHolder);
|
||||
|
||||
if (!stash) {
|
||||
return;
|
||||
}
|
||||
|
||||
await repository.dropStash(stash.index);
|
||||
}
|
||||
|
||||
private async pickStash(repository: Repository, placeHolder: string): Promise<Stash | undefined> {
|
||||
const stashes = await repository.getStashes();
|
||||
|
||||
|
|
|
@ -1597,6 +1597,24 @@ export class Repository {
|
|||
}
|
||||
}
|
||||
|
||||
async dropStash(index?: number): Promise<void> {
|
||||
const args = ['stash', 'drop'];
|
||||
|
||||
if (typeof index === 'number') {
|
||||
args.push(`stash@{${index}}`);
|
||||
}
|
||||
|
||||
try {
|
||||
await this.run(args);
|
||||
} catch (err) {
|
||||
if (/No stash found/.test(err.stderr || '')) {
|
||||
err.gitErrorCode = GitErrorCodes.NoStashFound;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
getStatus(limit = 5000): Promise<{ status: IFileStatus[]; didHitLimit: boolean; }> {
|
||||
return new Promise<{ status: IFileStatus[]; didHitLimit: boolean; }>((c, e) => {
|
||||
const parser = new GitStatusParser();
|
||||
|
|
|
@ -1254,6 +1254,10 @@ export class Repository implements Disposable {
|
|||
return await this.run(Operation.Stash, () => this.repository.popStash(index));
|
||||
}
|
||||
|
||||
async dropStash(index?: number): Promise<void> {
|
||||
return await this.run(Operation.Stash, () => this.repository.dropStash(index));
|
||||
}
|
||||
|
||||
async applyStash(index?: number): Promise<void> {
|
||||
return await this.run(Operation.Stash, () => this.repository.applyStash(index));
|
||||
}
|
||||
|
|
|
@ -80,10 +80,16 @@
|
|||
},
|
||||
{
|
||||
"scopeName": "documentation.injection",
|
||||
"path": "./syntaxes/jsdoc.injection.tmLanguage.json",
|
||||
"path": "./syntaxes/jsdoc.ts.injection.tmLanguage.json",
|
||||
"injectTo": [
|
||||
"source.ts",
|
||||
"source.tsx",
|
||||
"source.tsx"
|
||||
]
|
||||
},
|
||||
{
|
||||
"scopeName": "documentation.injection",
|
||||
"path": "./syntaxes/jsdoc.js.injection.tmLanguage.json",
|
||||
"injectTo": [
|
||||
"source.js",
|
||||
"source.js.jsx"
|
||||
]
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
|
||||
{
|
||||
"injectionSelector": "L:comment.block.documentation",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#jsdocbody"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"jsdocbody": {
|
||||
"begin": "(?<=/\\*\\*)([^*]|\\*(?!/))*$",
|
||||
"while": "(^|\\G)\\s*\\*(?!/)(?=([^*]|[*](?!/))*$)",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "text.html.markdown#fenced_code_block_js"
|
||||
},
|
||||
{
|
||||
"include": "text.html.markdown#fenced_code_block_ts"
|
||||
},
|
||||
{
|
||||
"include": "text.html.markdown#fenced_code_block_unknown"
|
||||
},
|
||||
{
|
||||
"include": "#example"
|
||||
},
|
||||
{
|
||||
"include": "source.ts#docblock"
|
||||
},
|
||||
{
|
||||
"include": "text.html.markdown#inline"
|
||||
}
|
||||
]
|
||||
},
|
||||
"example": {
|
||||
"begin": "((@)example)\\s+(?=([^*]|[*](?!/))*$).*$",
|
||||
"while": "(^|\\G)\\s(?!@)(?=([^*]|[*](?!/))*$)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "storage.type.class.jsdoc"
|
||||
},
|
||||
"2": {
|
||||
"name": "punctuation.definition.block.tag.jsdoc"
|
||||
}
|
||||
},
|
||||
"contentName": "meta.embedded.block.example.source.ts",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "source.js.jsx"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"scopeName": "documentation.injection"
|
||||
}
|
|
@ -63,26 +63,26 @@ class ChangeOperation {
|
|||
*/
|
||||
class BufferSynchronizer {
|
||||
|
||||
private readonly _pending = new Map<string, CloseOperation | OpenOperation | ChangeOperation>();
|
||||
private readonly _pending = new ResourceMap<CloseOperation | OpenOperation | ChangeOperation>();
|
||||
|
||||
constructor(
|
||||
private readonly client: ITypeScriptServiceClient
|
||||
) { }
|
||||
|
||||
public open(args: Proto.OpenRequestArgs) {
|
||||
public open(resource: vscode.Uri, args: Proto.OpenRequestArgs) {
|
||||
if (this.supportsBatching) {
|
||||
this.updatePending(args.file, pending => {
|
||||
pending.set(args.file, new OpenOperation(args));
|
||||
this.updatePending(resource, pending => {
|
||||
pending.set(resource, new OpenOperation(args));
|
||||
});
|
||||
} else {
|
||||
this.client.executeWithoutWaitingForResponse('open', args);
|
||||
}
|
||||
}
|
||||
|
||||
public close(filepath: string) {
|
||||
public close(resource: vscode.Uri, filepath: string) {
|
||||
if (this.supportsBatching) {
|
||||
this.updatePending(filepath, pending => {
|
||||
pending.set(filepath, new CloseOperation(filepath));
|
||||
this.updatePending(resource, pending => {
|
||||
pending.set(resource, new CloseOperation(filepath));
|
||||
});
|
||||
} else {
|
||||
const args: Proto.FileRequestArgs = { file: filepath };
|
||||
|
@ -90,14 +90,14 @@ class BufferSynchronizer {
|
|||
}
|
||||
}
|
||||
|
||||
public change(filepath: string, events: readonly vscode.TextDocumentContentChangeEvent[]) {
|
||||
public change(resource: vscode.Uri, filepath: string, events: readonly vscode.TextDocumentContentChangeEvent[]) {
|
||||
if (!events.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.supportsBatching) {
|
||||
this.updatePending(filepath, pending => {
|
||||
pending.set(filepath, new ChangeOperation({
|
||||
this.updatePending(resource, pending => {
|
||||
pending.set(resource, new ChangeOperation({
|
||||
fileName: filepath,
|
||||
textChanges: events.map((change): Proto.CodeEdit => ({
|
||||
newText: change.text,
|
||||
|
@ -136,7 +136,7 @@ class BufferSynchronizer {
|
|||
const closedFiles: string[] = [];
|
||||
const openFiles: Proto.OpenRequestArgs[] = [];
|
||||
const changedFiles: Proto.FileCodeEdits[] = [];
|
||||
for (const change of this._pending.values()) {
|
||||
for (const change of this._pending.values) {
|
||||
switch (change.type) {
|
||||
case 'change': changedFiles.push(change.args); break;
|
||||
case 'open': openFiles.push(change.args); break;
|
||||
|
@ -152,8 +152,8 @@ class BufferSynchronizer {
|
|||
return this.client.apiVersion.gte(API.v340) && vscode.workspace.getConfiguration('typescript', null).get<boolean>('useBatchedBufferSync', true);
|
||||
}
|
||||
|
||||
private updatePending(filepath: string, f: (pending: Map<string, CloseOperation | OpenOperation | ChangeOperation>) => void): void {
|
||||
if (this._pending.has(filepath)) {
|
||||
private updatePending(resource: vscode.Uri, f: (pending: ResourceMap<CloseOperation | OpenOperation | ChangeOperation>) => void): void {
|
||||
if (this._pending.has(resource)) {
|
||||
// we saw this file before, make sure we flush before working with it again
|
||||
this.flush();
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ class SyncedBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
this.synchronizer.open(args);
|
||||
this.synchronizer.open(this.resource, args);
|
||||
this.state = BufferState.Open;
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ class SyncedBuffer {
|
|||
}
|
||||
|
||||
public close(): void {
|
||||
this.synchronizer.close(this.filepath);
|
||||
this.synchronizer.close(this.resource, this.filepath);
|
||||
this.state = BufferState.Closed;
|
||||
}
|
||||
|
||||
|
@ -228,7 +228,7 @@ class SyncedBuffer {
|
|||
console.error(`Unexpected buffer state: ${this.state}`);
|
||||
}
|
||||
|
||||
this.synchronizer.change(this.filepath, events);
|
||||
this.synchronizer.change(this.resource, this.filepath, events);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ class TypeScriptFoldingProvider implements vscode.FoldingRangeProvider {
|
|||
|
||||
const start = range.start.line;
|
||||
// workaround for #47240
|
||||
const end = (range.end.character > 0 && new Set(['}', ']']).has(document.getText(new vscode.Range(range.end.translate(0, -1), range.end))))
|
||||
const end = (range.end.character > 0 && ['}', ']'].includes(document.getText(new vscode.Range(range.end.translate(0, -1), range.end))))
|
||||
? Math.max(range.end.line - 1, range.start.line)
|
||||
: range.end.line;
|
||||
|
||||
|
|
|
@ -9,13 +9,14 @@ import * as nls from 'vscode-nls';
|
|||
import * as Proto from '../protocol';
|
||||
import { ITypeScriptServiceClient } from '../typescriptService';
|
||||
import API from '../utils/api';
|
||||
import { Delayer } from '../utils/async';
|
||||
import { nulToken } from '../utils/cancellation';
|
||||
import { VersionDependentRegistration } from '../utils/dependentRegistration';
|
||||
import { Disposable } from '../utils/dispose';
|
||||
import * as fileSchemes from '../utils/fileSchemes';
|
||||
import { doesResourceLookLikeATypeScriptFile } from '../utils/languageDescription';
|
||||
import * as typeConverters from '../utils/typeConverters';
|
||||
import FileConfigurationManager from './fileConfigurationManager';
|
||||
import { Delayer } from '../utils/async';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
@ -43,10 +44,6 @@ interface RenameAction {
|
|||
readonly jsTsFileThatIsBeingMoved: vscode.Uri;
|
||||
}
|
||||
|
||||
function doesResourceLookLikeATypeScriptFile(resource: vscode.Uri): boolean {
|
||||
return /\.tsx?$/i.test(resource.fsPath);
|
||||
}
|
||||
|
||||
class UpdateImportsOnFileRenameHandler extends Disposable {
|
||||
public static readonly minVersion = API.v300;
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
import * as vscode from 'vscode';
|
||||
import * as Proto from '../protocol';
|
||||
import { ITypeScriptServiceClient } from '../typescriptService';
|
||||
import * as fileSchemes from '../utils/fileSchemes';
|
||||
import { doesResourceLookLikeAJavaScriptFile, doesResourceLookLikeATypeScriptFile } from '../utils/languageDescription';
|
||||
import * as typeConverters from '../utils/typeConverters';
|
||||
|
||||
function getSymbolKind(item: Proto.NavtoItem): vscode.SymbolKind {
|
||||
|
@ -35,7 +37,7 @@ class TypeScriptWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvide
|
|||
return [];
|
||||
}
|
||||
|
||||
const filepath = this.client.toOpenedFilePath(document);
|
||||
const filepath = await this.toOpenedFiledPath(document);
|
||||
if (!filepath) {
|
||||
return [];
|
||||
}
|
||||
|
@ -62,10 +64,25 @@ class TypeScriptWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvide
|
|||
return result;
|
||||
}
|
||||
|
||||
private async toOpenedFiledPath(document: vscode.TextDocument) {
|
||||
if (document.uri.scheme === fileSchemes.git) {
|
||||
try {
|
||||
const path = vscode.Uri.file(JSON.parse(document.uri.query)?.path);
|
||||
if (doesResourceLookLikeATypeScriptFile(path) || doesResourceLookLikeAJavaScriptFile(path)) {
|
||||
const document = await vscode.workspace.openTextDocument(path);
|
||||
return this.client.toOpenedFilePath(document);
|
||||
}
|
||||
} catch {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
return this.client.toOpenedFilePath(document);
|
||||
}
|
||||
|
||||
private static getLabel(item: Proto.NavtoItem) {
|
||||
let label = item.name;
|
||||
const label = item.name;
|
||||
if (item.kind === 'method' || item.kind === 'function') {
|
||||
label += '()';
|
||||
return label + '()';
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
@ -75,17 +92,16 @@ class TypeScriptWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvide
|
|||
// general questions so we check the active editor. If this
|
||||
// doesn't match we take the first TS document.
|
||||
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor) {
|
||||
const document = editor.document;
|
||||
if (document && this.modeIds.indexOf(document.languageId) >= 0) {
|
||||
return document;
|
||||
const activeDocument = vscode.window.activeTextEditor?.document;
|
||||
if (activeDocument) {
|
||||
if (this.modeIds.includes(activeDocument.languageId)) {
|
||||
return activeDocument;
|
||||
}
|
||||
}
|
||||
|
||||
const documents = vscode.workspace.textDocuments;
|
||||
for (const document of documents) {
|
||||
if (this.modeIds.indexOf(document.languageId) >= 0) {
|
||||
if (this.modeIds.includes(document.languageId)) {
|
||||
return document;
|
||||
}
|
||||
}
|
||||
|
@ -98,4 +114,4 @@ export function register(
|
|||
modeIds: string[],
|
||||
) {
|
||||
return vscode.languages.registerWorkspaceSymbolProvider(new TypeScriptWorkspaceSymbolProvider(client, modeIds));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export const file = 'file';
|
||||
|
||||
export const untitled = 'untitled';
|
||||
|
||||
export const git = 'git';
|
||||
export const walkThroughSnippet = 'walkThroughSnippet';
|
||||
|
||||
export const supportedSchemes = [
|
||||
|
@ -17,4 +16,4 @@ export const supportedSchemes = [
|
|||
|
||||
export function isSupportedScheme(scheme: string): boolean {
|
||||
return supportedSchemes.indexOf(scheme) >= 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { basename } from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as languageModeIds from './languageModeIds';
|
||||
|
||||
export const enum DiagnosticLanguage {
|
||||
|
@ -48,3 +49,11 @@ export function isTsConfigFileName(fileName: string): boolean {
|
|||
export function isJsConfigOrTsConfigFileName(fileName: string): boolean {
|
||||
return /^[jt]sconfig\.(.+\.)?json$/i.test(basename(fileName));
|
||||
}
|
||||
|
||||
export function doesResourceLookLikeATypeScriptFile(resource: vscode.Uri): boolean {
|
||||
return /\.tsx?$/i.test(resource.fsPath);
|
||||
}
|
||||
|
||||
export function doesResourceLookLikeAJavaScriptFile(resource: vscode.Uri): boolean {
|
||||
return /\.jsx?$/i.test(resource.fsPath);
|
||||
}
|
||||
|
|
|
@ -13,27 +13,25 @@ const localize = loadMessageBundle();
|
|||
const typingsInstallTimeout = 30 * 1000;
|
||||
|
||||
export default class TypingsStatus extends Disposable {
|
||||
private _acquiringTypings: { [eventId: string]: NodeJS.Timer } = Object.create({});
|
||||
private _client: ITypeScriptServiceClient;
|
||||
private _subscriptions: vscode.Disposable[] = [];
|
||||
private readonly _acquiringTypings = new Map<number, NodeJS.Timer>();
|
||||
private readonly _client: ITypeScriptServiceClient;
|
||||
|
||||
constructor(client: ITypeScriptServiceClient) {
|
||||
super();
|
||||
this._client = client;
|
||||
|
||||
this._subscriptions.push(
|
||||
this._register(
|
||||
this._client.onDidBeginInstallTypings(event => this.onBeginInstallTypings(event.eventId)));
|
||||
|
||||
this._subscriptions.push(
|
||||
this._register(
|
||||
this._client.onDidEndInstallTypings(event => this.onEndInstallTypings(event.eventId)));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
super.dispose();
|
||||
this._subscriptions.forEach(x => x.dispose());
|
||||
|
||||
for (const eventId of Object.keys(this._acquiringTypings)) {
|
||||
clearTimeout(this._acquiringTypings[eventId]);
|
||||
for (const timeout of this._acquiringTypings.values()) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,37 +40,36 @@ export default class TypingsStatus extends Disposable {
|
|||
}
|
||||
|
||||
private onBeginInstallTypings(eventId: number): void {
|
||||
if (this._acquiringTypings[eventId]) {
|
||||
if (this._acquiringTypings.has(eventId)) {
|
||||
return;
|
||||
}
|
||||
this._acquiringTypings[eventId] = setTimeout(() => {
|
||||
this._acquiringTypings.set(eventId, setTimeout(() => {
|
||||
this.onEndInstallTypings(eventId);
|
||||
}, typingsInstallTimeout);
|
||||
}, typingsInstallTimeout));
|
||||
}
|
||||
|
||||
private onEndInstallTypings(eventId: number): void {
|
||||
const timer = this._acquiringTypings[eventId];
|
||||
const timer = this._acquiringTypings.get(eventId);
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
delete this._acquiringTypings[eventId];
|
||||
this._acquiringTypings.delete(eventId);
|
||||
}
|
||||
}
|
||||
|
||||
export class AtaProgressReporter {
|
||||
export class AtaProgressReporter extends Disposable {
|
||||
|
||||
private _promises = new Map<number, Function>();
|
||||
private _disposable: vscode.Disposable;
|
||||
private readonly _promises = new Map<number, Function>();
|
||||
|
||||
constructor(client: ITypeScriptServiceClient) {
|
||||
this._disposable = vscode.Disposable.from(
|
||||
client.onDidBeginInstallTypings(e => this._onBegin(e.eventId)),
|
||||
client.onDidEndInstallTypings(e => this._onEndOrTimeout(e.eventId)),
|
||||
client.onTypesInstallerInitializationFailed(_ => this.onTypesInstallerInitializationFailed()));
|
||||
super();
|
||||
this._register(client.onDidBeginInstallTypings(e => this._onBegin(e.eventId)));
|
||||
this._register(client.onDidEndInstallTypings(e => this._onEndOrTimeout(e.eventId)));
|
||||
this._register(client.onTypesInstallerInitializationFailed(_ => this.onTypesInstallerInitializationFailed()));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._disposable.dispose();
|
||||
super.dispose();
|
||||
this._promises.forEach(value => value());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.40.0",
|
||||
"distro": "879a75db0f86c41ef432c8740266aefced54e9b7",
|
||||
"distro": "2fd17a3cb58818370b0abc2de4728553ad812e7e",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
|
@ -129,7 +129,7 @@
|
|||
"source-map": "^0.4.4",
|
||||
"ts-loader": "^4.4.2",
|
||||
"tslint": "^5.16.0",
|
||||
"typescript": "3.7.0-dev.20191017",
|
||||
"typescript": "3.7.1-rc",
|
||||
"typescript-formatter": "7.1.0",
|
||||
"underscore": "^1.8.2",
|
||||
"vinyl": "^2.0.0",
|
||||
|
|
|
@ -10,10 +10,10 @@ import { SubmenuAction } from 'vs/base/browser/ui/menu/menu';
|
|||
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
|
||||
|
||||
export interface IContextMenuEvent {
|
||||
shiftKey?: boolean;
|
||||
ctrlKey?: boolean;
|
||||
altKey?: boolean;
|
||||
metaKey?: boolean;
|
||||
readonly shiftKey?: boolean;
|
||||
readonly ctrlKey?: boolean;
|
||||
readonly altKey?: boolean;
|
||||
readonly metaKey?: boolean;
|
||||
}
|
||||
|
||||
export class ContextSubMenu extends SubmenuAction {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
@font-face {
|
||||
font-family: "codicon";
|
||||
src: url("./codicon.ttf?297296ccad95f5838f73ae67efd78fbc") format("truetype");
|
||||
src: url("./codicon.ttf?0d7ce4078a0bf127a55edc6b4b1996eb") format("truetype");
|
||||
}
|
||||
|
||||
.codicon[class*='codicon-'] {
|
||||
|
@ -197,13 +197,13 @@
|
|||
.codicon-color-mode:before { content: "\f130" }
|
||||
.codicon-comment-discussion:before { content: "\f131" }
|
||||
.codicon-compare-changes:before { content: "\f132" }
|
||||
.codicon-continue:before { content: "\f133" }
|
||||
.codicon-credit-card:before { content: "\f134" }
|
||||
.codicon-current-and-breakpoint:before { content: "\f135" }
|
||||
.codicon-current:before { content: "\f136" }
|
||||
.codicon-dash:before { content: "\f137" }
|
||||
.codicon-dashboard:before { content: "\f138" }
|
||||
.codicon-database:before { content: "\f139" }
|
||||
.codicon-credit-card:before { content: "\f133" }
|
||||
.codicon-current-and-breakpoint:before { content: "\f134" }
|
||||
.codicon-current:before { content: "\f135" }
|
||||
.codicon-dash:before { content: "\f136" }
|
||||
.codicon-dashboard:before { content: "\f137" }
|
||||
.codicon-database:before { content: "\f138" }
|
||||
.codicon-debug-continue:before { content: "\f139" }
|
||||
.codicon-debug-disconnect:before { content: "\f13a" }
|
||||
.codicon-debug-pause:before { content: "\f13b" }
|
||||
.codicon-debug-restart:before { content: "\f13c" }
|
||||
|
|
Binary file not shown.
|
@ -430,12 +430,16 @@ class TreeRenderer<T, TFilterData, TRef, TTemplateData> implements IListRenderer
|
|||
|
||||
nodes.forEach(node => {
|
||||
const ref = model.getNodeLocation(node);
|
||||
const parentRef = model.getParentNodeLocation(ref);
|
||||
try {
|
||||
const parentRef = model.getParentNodeLocation(ref);
|
||||
|
||||
if (node.collapsible && node.children.length > 0 && !node.collapsed) {
|
||||
set.add(node);
|
||||
} else if (parentRef) {
|
||||
set.add(model.getNode(parentRef));
|
||||
if (node.collapsible && node.children.length > 0 && !node.collapsed) {
|
||||
set.add(node);
|
||||
} else if (parentRef) {
|
||||
set.add(model.getNode(parentRef));
|
||||
}
|
||||
} catch {
|
||||
// noop
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -257,7 +257,12 @@ export class ObjectTreeModel<T extends NonNullable<any>, TFilterData extends Non
|
|||
throw new TreeError(this.user, `Invalid getParentNodeLocation call`);
|
||||
}
|
||||
|
||||
const node = this.nodes.get(element)!;
|
||||
const node = this.nodes.get(element);
|
||||
|
||||
if (!node) {
|
||||
throw new TreeError(this.user, `Tree element not found: ${element}`);
|
||||
}
|
||||
|
||||
const location = this.model.getNodeLocation(node);
|
||||
const parentLocation = this.model.getParentNodeLocation(location);
|
||||
const parent = this.model.getNode(parentLocation);
|
||||
|
|
|
@ -137,6 +137,7 @@ export interface Location {
|
|||
export interface ParseOptions {
|
||||
disallowComments?: boolean;
|
||||
allowTrailingComma?: boolean;
|
||||
allowEmptyContent?: boolean;
|
||||
}
|
||||
|
||||
export namespace ParseOptions {
|
||||
|
@ -785,7 +786,7 @@ export function getLocation(text: string, position: number): Location {
|
|||
if (position < offset) {
|
||||
throw earlyReturnException;
|
||||
}
|
||||
setPreviousNode(value, offset, length, getLiteralNodeType(value));
|
||||
setPreviousNode(value, offset, length, getNodeType(value));
|
||||
|
||||
if (position <= offset + length) {
|
||||
throw earlyReturnException;
|
||||
|
@ -848,7 +849,7 @@ export function parse(text: string, errors: ParseError[] = [], options: ParseOpt
|
|||
function onValue(value: any) {
|
||||
if (Array.isArray(currentParent)) {
|
||||
(<any[]>currentParent).push(value);
|
||||
} else if (currentProperty) {
|
||||
} else if (currentProperty !== null) {
|
||||
currentParent[currentProperty] = value;
|
||||
}
|
||||
}
|
||||
|
@ -927,7 +928,7 @@ export function parseTree(text: string, errors: ParseError[] = [], options: Pars
|
|||
ensurePropertyComplete(offset + length);
|
||||
},
|
||||
onLiteralValue: (value: any, offset: number, length: number) => {
|
||||
onValue({ type: getLiteralNodeType(value), offset, length, parent: currentParent, value });
|
||||
onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });
|
||||
ensurePropertyComplete(offset + length);
|
||||
},
|
||||
onSeparator: (sep: string, offset: number, length: number) => {
|
||||
|
@ -1287,7 +1288,11 @@ export function visit(text: string, visitor: JSONVisitor, options: ParseOptions
|
|||
|
||||
scanNext();
|
||||
if (_scanner.getToken() === SyntaxKind.EOF) {
|
||||
return true;
|
||||
if (options.allowEmptyContent) {
|
||||
return true;
|
||||
}
|
||||
handleError(ParseErrorCode.ValueExpected, [], []);
|
||||
return false;
|
||||
}
|
||||
if (!parseValue()) {
|
||||
handleError(ParseErrorCode.ValueExpected, [], []);
|
||||
|
@ -1333,11 +1338,19 @@ export function stripComments(text: string, replaceCh?: string): string {
|
|||
return parts.join('');
|
||||
}
|
||||
|
||||
function getLiteralNodeType(value: any): NodeType {
|
||||
export function getNodeType(value: any): NodeType {
|
||||
switch (typeof value) {
|
||||
case 'boolean': return 'boolean';
|
||||
case 'number': return 'number';
|
||||
case 'string': return 'string';
|
||||
case 'object': {
|
||||
if (!value) {
|
||||
return 'null';
|
||||
} else if (Array.isArray(value)) {
|
||||
return 'array';
|
||||
}
|
||||
return 'object';
|
||||
}
|
||||
default: return 'null';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -189,7 +189,7 @@ export const setImmediate: ISetImmediate = (function defineSetImmediate() {
|
|||
id: myId,
|
||||
callback: callback
|
||||
});
|
||||
globals.postMessage({ vscodeSetImmediateId: myId }, '*'); // TODO@alex please revisit
|
||||
globals.postMessage({ vscodeSetImmediateId: myId }, '*');
|
||||
};
|
||||
}
|
||||
if (typeof process !== 'undefined' && typeof process.nextTick === 'function') {
|
||||
|
|
|
@ -12,7 +12,6 @@ import { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/v
|
|||
import { DomReadingContext, ViewLine, ViewLineOptions } from 'vs/editor/browser/viewParts/lines/viewLine';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { IViewLines, LineVisibleRanges, VisibleRanges, HorizontalPosition } from 'vs/editor/common/view/renderingContext';
|
||||
import { ViewContext } from 'vs/editor/common/view/viewContext';
|
||||
|
@ -74,8 +73,8 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
|
|||
private _typicalHalfwidthCharacterWidth: number;
|
||||
private _isViewportWrapping: boolean;
|
||||
private _revealHorizontalRightPadding: number;
|
||||
private _selections: Selection[];
|
||||
private _cursorSurroundingLines: number;
|
||||
private _cursorSurroundingLinesStyle: 'default' | 'all';
|
||||
private _canUseLayerHinting: boolean;
|
||||
private _viewLineOptions: ViewLineOptions;
|
||||
|
||||
|
@ -103,9 +102,9 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
|
|||
this._isViewportWrapping = wrappingInfo.isViewportWrapping;
|
||||
this._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding);
|
||||
this._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines);
|
||||
this._cursorSurroundingLinesStyle = options.get(EditorOption.cursorSurroundingLinesStyle);
|
||||
this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting);
|
||||
this._viewLineOptions = new ViewLineOptions(conf, this._context.theme.type);
|
||||
this._selections = [];
|
||||
|
||||
PartFingerprints.write(this.domNode, PartFingerprint.ViewLines);
|
||||
this.domNode.setClassName('view-lines');
|
||||
|
@ -156,6 +155,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
|
|||
this._isViewportWrapping = wrappingInfo.isViewportWrapping;
|
||||
this._revealHorizontalRightPadding = options.get(EditorOption.revealHorizontalRightPadding);
|
||||
this._cursorSurroundingLines = options.get(EditorOption.cursorSurroundingLines);
|
||||
this._cursorSurroundingLinesStyle = options.get(EditorOption.cursorSurroundingLinesStyle);
|
||||
this._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting);
|
||||
Configuration.applyFontInfo(this.domNode, fontInfo);
|
||||
|
||||
|
@ -186,7 +186,6 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
|
|||
return false;
|
||||
}
|
||||
public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {
|
||||
this._selections = e.selections;
|
||||
const rendStartLineNumber = this._visibleLines.getStartLineNumber();
|
||||
const rendEndLineNumber = this._visibleLines.getEndLineNumber();
|
||||
let r = false;
|
||||
|
@ -571,10 +570,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
|
|||
boxStartY = this._context.viewLayout.getVerticalOffsetForLineNumber(range.startLineNumber);
|
||||
boxEndY = this._context.viewLayout.getVerticalOffsetForLineNumber(range.endLineNumber) + this._lineHeight;
|
||||
|
||||
const shouldIgnoreScrollOff = source === 'mouse' && (
|
||||
this._selections.length > 1 // scroll off might trigger scrolling and mess up with multi cursor
|
||||
|| (this._selections.length > 0 && this._selections[0].isEmpty()) // we don't want to single click triggering selection
|
||||
);
|
||||
const shouldIgnoreScrollOff = source === 'mouse' && this._cursorSurroundingLinesStyle === 'default';
|
||||
|
||||
if (!shouldIgnoreScrollOff) {
|
||||
const context = Math.min((viewportHeight / this._lineHeight) / 2, this._cursorSurroundingLines);
|
||||
|
@ -589,7 +585,10 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
|
|||
|
||||
let newScrollTop: number;
|
||||
|
||||
if (verticalType === viewEvents.VerticalRevealType.Center || verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport) {
|
||||
if (boxEndY - boxStartY > viewportHeight) {
|
||||
// the box is larger than the viewport ... scroll to its top
|
||||
newScrollTop = boxStartY;
|
||||
} else if (verticalType === viewEvents.VerticalRevealType.Center || verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport) {
|
||||
if (verticalType === viewEvents.VerticalRevealType.CenterIfOutsideViewport && viewportStartY <= boxStartY && boxEndY <= viewportEndY) {
|
||||
// Box is already in the viewport... do nothing
|
||||
newScrollTop = viewportStartY;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/editor';
|
||||
import 'vs/css!./media/tokens';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-editor .vs-whitespace {
|
||||
display:inline-block;
|
||||
}
|
||||
|
|
@ -71,6 +71,12 @@ export interface IEditorOptions {
|
|||
* Defaults to 0.
|
||||
*/
|
||||
cursorSurroundingLines?: number;
|
||||
/**
|
||||
* Controls when `cursorSurroundingLines` should be enforced
|
||||
* Defaults to `default`, `cursorSurroundingLines` is not enforced when cursor position is changed
|
||||
* by mouse.
|
||||
*/
|
||||
cursorSurroundingLinesStyle?: 'default' | 'all';
|
||||
/**
|
||||
* Render last line number when the file ends with a newline.
|
||||
* Defaults to true.
|
||||
|
@ -2722,6 +2728,7 @@ export const enum EditorOption {
|
|||
cursorSmoothCaretAnimation,
|
||||
cursorStyle,
|
||||
cursorSurroundingLines,
|
||||
cursorSurroundingLinesStyle,
|
||||
cursorWidth,
|
||||
disableLayerHinting,
|
||||
disableMonospaceOptimizations,
|
||||
|
@ -2936,6 +2943,18 @@ export const EditorOptions = {
|
|||
0, 0, Constants.MAX_SAFE_SMALL_INTEGER,
|
||||
{ description: nls.localize('cursorSurroundingLines', "Controls the minimal number of visible leading and trailing lines surrounding the cursor. Known as 'scrollOff' or `scrollOffset` in some other editors.") }
|
||||
)),
|
||||
cursorSurroundingLinesStyle: register(new EditorStringEnumOption(
|
||||
EditorOption.cursorSurroundingLinesStyle, 'cursorSurroundingLinesStyle',
|
||||
'default' as 'default' | 'all',
|
||||
['default', 'all'] as const,
|
||||
{
|
||||
enumDescriptions: [
|
||||
nls.localize('cursorSurroundingLinesStyle.default', "`cursorSurroundingLines` is enforced only when triggered from keyboard and api"),
|
||||
nls.localize('cursorSurroundingLinesStyle.all', "`cursorSurroundingLines` is enforced always.")
|
||||
],
|
||||
description: nls.localize('cursorSurroundingLinesStyle', "Controls when `cursorSurroundingLines` should be enforced")
|
||||
}
|
||||
)),
|
||||
cursorWidth: register(new EditorIntOption(
|
||||
EditorOption.cursorWidth, 'cursorWidth',
|
||||
0, 0, Constants.MAX_SAFE_SMALL_INTEGER,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IScrollDimensions, IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout';
|
||||
|
@ -65,15 +65,23 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
|||
}
|
||||
if (e.hasChanged(EditorOption.layoutInfo)) {
|
||||
const layoutInfo = options.get(EditorOption.layoutInfo);
|
||||
const width = layoutInfo.contentWidth;
|
||||
const height = layoutInfo.contentHeight;
|
||||
const scrollDimensions = this.scrollable.getScrollDimensions();
|
||||
const scrollWidth = scrollDimensions.scrollWidth;
|
||||
const scrollHeight = this._getTotalHeight(width, height, scrollWidth);
|
||||
|
||||
this.scrollable.setScrollDimensions({
|
||||
width: layoutInfo.contentWidth,
|
||||
height: layoutInfo.contentHeight
|
||||
width: width,
|
||||
height: height,
|
||||
scrollHeight: scrollHeight
|
||||
});
|
||||
} else {
|
||||
this._updateHeight();
|
||||
}
|
||||
if (e.hasChanged(EditorOption.smoothScrolling)) {
|
||||
this._configureSmoothScrollDuration();
|
||||
}
|
||||
this._updateHeight();
|
||||
}
|
||||
public onFlushed(lineCount: number): void {
|
||||
this._linesLayout.onFlushed(lineCount);
|
||||
|
@ -87,37 +95,41 @@ export class ViewLayout extends Disposable implements IViewLayout {
|
|||
|
||||
// ---- end view event handlers
|
||||
|
||||
private _getHorizontalScrollbarHeight(scrollDimensions: IScrollDimensions): number {
|
||||
private _getHorizontalScrollbarHeight(width: number, scrollWidth: number): number {
|
||||
const options = this._configuration.options;
|
||||
const scrollbar = options.get(EditorOption.scrollbar);
|
||||
if (scrollbar.horizontal === ScrollbarVisibility.Hidden) {
|
||||
// horizontal scrollbar not visible
|
||||
return 0;
|
||||
}
|
||||
if (scrollDimensions.width >= scrollDimensions.scrollWidth) {
|
||||
if (width >= scrollWidth) {
|
||||
// horizontal scrollbar not visible
|
||||
return 0;
|
||||
}
|
||||
return scrollbar.horizontalScrollbarSize;
|
||||
}
|
||||
|
||||
private _getTotalHeight(): number {
|
||||
private _getTotalHeight(width: number, height: number, scrollWidth: number): number {
|
||||
const options = this._configuration.options;
|
||||
const scrollDimensions = this.scrollable.getScrollDimensions();
|
||||
|
||||
let result = this._linesLayout.getLinesTotalHeight();
|
||||
if (options.get(EditorOption.scrollBeyondLastLine)) {
|
||||
result += scrollDimensions.height - options.get(EditorOption.lineHeight);
|
||||
result += height - options.get(EditorOption.lineHeight);
|
||||
} else {
|
||||
result += this._getHorizontalScrollbarHeight(scrollDimensions);
|
||||
result += this._getHorizontalScrollbarHeight(width, scrollWidth);
|
||||
}
|
||||
|
||||
return Math.max(scrollDimensions.height, result);
|
||||
return Math.max(height, result);
|
||||
}
|
||||
|
||||
private _updateHeight(): void {
|
||||
const scrollDimensions = this.scrollable.getScrollDimensions();
|
||||
const width = scrollDimensions.width;
|
||||
const height = scrollDimensions.height;
|
||||
const scrollWidth = scrollDimensions.scrollWidth;
|
||||
const scrollHeight = this._getTotalHeight(width, height, scrollWidth);
|
||||
this.scrollable.setScrollDimensions({
|
||||
scrollHeight: this._getTotalHeight()
|
||||
scrollHeight: scrollHeight
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -783,7 +783,7 @@ function _renderLine(input: ResolvedRenderLineInput, sb: IStringBuilder): Render
|
|||
if (!fontIsMonospace) {
|
||||
const partIsOnlyWhitespace = (partType === 'vs-whitespace');
|
||||
if (partIsOnlyWhitespace || !containsForeignElements) {
|
||||
sb.appendASCIIString(' style="width:');
|
||||
sb.appendASCIIString(' style="display:inline-block;width:');
|
||||
sb.appendASCIIString(String(spaceWidth * partContentCnt));
|
||||
sb.appendASCIIString('px"');
|
||||
}
|
||||
|
|
|
@ -489,7 +489,7 @@ export class StartFindWithSelectionAction extends EditorAction {
|
|||
forceRevealReplace: false,
|
||||
seedSearchStringFromSelection: true,
|
||||
seedSearchStringFromGlobalClipboard: false,
|
||||
shouldFocus: FindStartFocusAction.FocusFindInput,
|
||||
shouldFocus: FindStartFocusAction.NoFocusChange,
|
||||
shouldAnimate: true,
|
||||
updateSearchScope: false
|
||||
});
|
||||
|
|
|
@ -189,8 +189,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||
createPart(48, 12),
|
||||
]);
|
||||
let expectedOutput = [
|
||||
'<span class="vs-whitespace" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="mtk2">export</span>',
|
||||
'<span class="mtk3">\u00a0</span>',
|
||||
'<span class="mtk4">class</span>',
|
||||
|
@ -201,8 +201,8 @@ suite('viewLineRenderer.renderLine', () => {
|
|||
'<span class="mtk9">\u00a0</span>',
|
||||
'<span class="mtk10">//\u00a0</span>',
|
||||
'<span class="mtk11">http://test.com</span>',
|
||||
'<span class="vs-whitespace" style="width:20px">\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="width:30px">\u00b7\u00b7\u00b7</span>'
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:20px">\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:30px">\u00b7\u00b7\u00b7</span>'
|
||||
].join('');
|
||||
let expectedOffsetsArr = [
|
||||
[0],
|
||||
|
@ -867,10 +867,10 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
null,
|
||||
[
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="mtk2">He</span>',
|
||||
'<span class="mtk3">llo\u00a0world!</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
|
@ -889,12 +889,12 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
null,
|
||||
[
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="mtk2">He</span>',
|
||||
'<span class="mtk3">llo\u00a0world!</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
|
@ -913,11 +913,11 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
null,
|
||||
[
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="mtk2">He</span>',
|
||||
'<span class="mtk3">llo\u00a0world!</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
|
@ -936,15 +936,15 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
null,
|
||||
[
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u2192\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="width:20px">\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u2192\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:20px">\u00b7\u00b7</span>',
|
||||
'<span class="mtk2">He</span>',
|
||||
'<span class="mtk3">llo\u00a0world!</span>',
|
||||
'<span class="vs-whitespace" style="width:20px">\u00b7\uffeb</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u2192\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\uffeb</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:20px">\u00b7\uffeb</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u2192\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u00b7\uffeb</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
|
@ -965,13 +965,13 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
[
|
||||
'<span>',
|
||||
'<span class="">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="width:20px">\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:20px">\u00b7\u00b7</span>',
|
||||
'<span class="mtk2">He</span>',
|
||||
'<span class="mtk3">llo\u00a0world!</span>',
|
||||
'<span class="vs-whitespace" style="width:20px">\u00b7\uffeb</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u2192\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\uffeb</span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:20px">\u00b7\uffeb</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u2192\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u00b7\uffeb</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u00b7\u00b7\u00b7\u00b7</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
|
@ -1016,11 +1016,11 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
[
|
||||
'<span>',
|
||||
'<span class="mtk1">it</span>',
|
||||
'<span class="vs-whitespace" style="width:20px">\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:20px">\u00b7\u00b7</span>',
|
||||
'<span class="mtk1">it</span>',
|
||||
'<span class="mtk2">\u00a0</span>',
|
||||
'<span class="mtk3">it</span>',
|
||||
'<span class="vs-whitespace" style="width:20px">\u00b7\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:20px">\u00b7\u00b7</span>',
|
||||
'<span class="mtk3">it</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
|
@ -1041,12 +1041,12 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
null,
|
||||
[
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:10px">\u00b7</span>',
|
||||
'<span class="mtk0">Hel</span>',
|
||||
'<span class="mtk1">lo</span>',
|
||||
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:10px">\u00b7</span>',
|
||||
'<span class="mtk2">world!</span>',
|
||||
'<span class="vs-whitespace" style="width:30px">\u2192\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:30px">\u2192\u00a0\u00a0</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
|
@ -1088,12 +1088,12 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
[new LineRange(0, 14)],
|
||||
[
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:10px">\u00b7</span>',
|
||||
'<span class="mtk0">Hel</span>',
|
||||
'<span class="mtk1">lo</span>',
|
||||
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:10px">\u00b7</span>',
|
||||
'<span class="mtk2">world!</span>',
|
||||
'<span class="vs-whitespace" style="width:30px">\u2192\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:30px">\u2192\u00a0\u00a0</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
|
@ -1113,7 +1113,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
[new LineRange(0, 5)],
|
||||
[
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:10px">\u00b7</span>',
|
||||
'<span class="mtk0">Hel</span>',
|
||||
'<span class="mtk1">lo</span>',
|
||||
'<span class="mtk2">\u00a0world!\u00a0\u00a0\u00a0</span>',
|
||||
|
@ -1137,11 +1137,11 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
[new LineRange(0, 5), new LineRange(9, 14)],
|
||||
[
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:10px">\u00b7</span>',
|
||||
'<span class="mtk0">Hel</span>',
|
||||
'<span class="mtk1">lo</span>',
|
||||
'<span class="mtk2">\u00a0world!</span>',
|
||||
'<span class="vs-whitespace" style="width:30px">\u2192\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:30px">\u2192\u00a0\u00a0</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
|
@ -1162,11 +1162,11 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
[new LineRange(9, 14), new LineRange(0, 5)],
|
||||
[
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:10px">\u00b7</span>',
|
||||
'<span class="mtk0">Hel</span>',
|
||||
'<span class="mtk1">lo</span>',
|
||||
'<span class="mtk2">\u00a0world!</span>',
|
||||
'<span class="vs-whitespace" style="width:30px">\u2192\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:30px">\u2192\u00a0\u00a0</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
);
|
||||
|
@ -1184,9 +1184,9 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
[new LineRange(0, 1), new LineRange(1, 2), new LineRange(2, 3)],
|
||||
[
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:10px">\u00b7</span>',
|
||||
'<span class="mtk0">*</span>',
|
||||
'<span class="vs-whitespace" style="width:10px">\u00b7</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:10px">\u00b7</span>',
|
||||
'<span class="mtk0">S</span>',
|
||||
'</span>',
|
||||
].join('')
|
||||
|
@ -1293,7 +1293,7 @@ suite('viewLineRenderer.renderLine 2', () => {
|
|||
|
||||
let expected = [
|
||||
'<span>',
|
||||
'<span class="vs-whitespace" style="width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="vs-whitespace" style="display:inline-block;width:40px">\u2192\u00a0\u00a0\u00a0</span>',
|
||||
'<span class="mtk3 before">b</span>',
|
||||
'<span class="mtk3">la</span>',
|
||||
'</span>'
|
||||
|
|
6
src/vs/monaco.d.ts
vendored
6
src/vs/monaco.d.ts
vendored
|
@ -2484,6 +2484,12 @@ declare namespace monaco.editor {
|
|||
* Defaults to 0.
|
||||
*/
|
||||
cursorSurroundingLines?: number;
|
||||
/**
|
||||
* Controls when `cursorSurroundingLines` should be enforced
|
||||
* Defaults to `default`, `cursorSurroundingLines` is not enforced when cursor position is changed
|
||||
* by mouse.
|
||||
*/
|
||||
cursorSurroundingLinesStyle?: 'default' | 'all';
|
||||
/**
|
||||
* Render last line number when the file ends with a newline.
|
||||
* Defaults to true.
|
||||
|
|
|
@ -7,7 +7,7 @@ import { virtualMachineHint } from 'vs/base/node/id';
|
|||
import { IMachineInfo, WorkspaceStats, WorkspaceStatItem, PerformanceInfo, SystemInfo, IRemoteDiagnosticInfo, IRemoteDiagnosticError, isRemoteDiagnosticError, IWorkspaceInformation } from 'vs/platform/diagnostics/common/diagnostics';
|
||||
import { readdir, stat, exists, readFile } from 'fs';
|
||||
import { join, basename } from 'vs/base/common/path';
|
||||
import { parse, ParseError } from 'vs/base/common/json';
|
||||
import { parse, ParseError, getNodeType } from 'vs/base/common/json';
|
||||
import { listProcesses } from 'vs/base/node/ps';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { repeat, pad } from 'vs/base/common/strings';
|
||||
|
@ -223,7 +223,7 @@ export function collectLaunchConfigs(folder: string): Promise<WorkspaceStatItem[
|
|||
return resolve([]);
|
||||
}
|
||||
|
||||
if (json['configurations']) {
|
||||
if (getNodeType(json) === 'object' && json['configurations']) {
|
||||
for (const each of json['configurations']) {
|
||||
const type = each['type'];
|
||||
if (type) {
|
||||
|
|
|
@ -188,7 +188,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
|
|||
|
||||
private hasErrors(content: string): boolean {
|
||||
const parseErrors: ParseError[] = [];
|
||||
parse(content, parseErrors);
|
||||
parse(content, parseErrors, { allowEmptyContent: true, allowTrailingComma: true });
|
||||
return parseErrors.length > 0;
|
||||
}
|
||||
|
||||
|
@ -248,13 +248,23 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
|
|||
}
|
||||
|
||||
private getIgnoredSettings(settingsContent?: string): string[] {
|
||||
const value: string[] = (settingsContent ? parse(settingsContent)['configurationSync.settingsToIgnore'] : this.configurationService.getValue<string[]>('configurationSync.settingsToIgnore')) || [];
|
||||
let value: string[] = [];
|
||||
if (settingsContent) {
|
||||
const setting = parse(settingsContent);
|
||||
if (setting) {
|
||||
value = setting['configurationSync.settingsToIgnore'];
|
||||
}
|
||||
} else {
|
||||
value = this.configurationService.getValue<string[]>('configurationSync.settingsToIgnore');
|
||||
}
|
||||
const added: string[] = [], removed: string[] = [];
|
||||
for (const key of value) {
|
||||
if (startsWith(key, '-')) {
|
||||
removed.push(key.substring(1));
|
||||
} else {
|
||||
added.push(key);
|
||||
if (Array.isArray(value)) {
|
||||
for (const key of value) {
|
||||
if (startsWith(key, '-')) {
|
||||
removed.push(key.substring(1));
|
||||
} else {
|
||||
added.push(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return [...DEFAULT_IGNORED_SETTINGS, ...added].filter(setting => removed.indexOf(setting) === -1);
|
||||
|
|
|
@ -285,12 +285,9 @@ function doParseStoredWorkspace(path: URI, contents: string): IStoredWorkspace {
|
|||
let storedWorkspace: IStoredWorkspace = json.parse(contents); // use fault tolerant parser
|
||||
|
||||
// Filter out folders which do not have a path or uri set
|
||||
if (Array.isArray(storedWorkspace.folders)) {
|
||||
if (storedWorkspace && Array.isArray(storedWorkspace.folders)) {
|
||||
storedWorkspace.folders = storedWorkspace.folders.filter(folder => isStoredWorkspaceFolder(folder));
|
||||
}
|
||||
|
||||
// Validate
|
||||
if (!Array.isArray(storedWorkspace.folders)) {
|
||||
} else {
|
||||
throw new Error(`${path} looks like an invalid workspace file.`);
|
||||
}
|
||||
|
||||
|
|
|
@ -130,12 +130,9 @@ export class WorkspacesMainService extends Disposable implements IWorkspacesMain
|
|||
let storedWorkspace: IStoredWorkspace = json.parse(contents); // use fault tolerant parser
|
||||
|
||||
// Filter out folders which do not have a path or uri set
|
||||
if (Array.isArray(storedWorkspace.folders)) {
|
||||
if (storedWorkspace && Array.isArray(storedWorkspace.folders)) {
|
||||
storedWorkspace.folders = storedWorkspace.folders.filter(folder => isStoredWorkspaceFolder(folder));
|
||||
}
|
||||
|
||||
// Validate
|
||||
if (!Array.isArray(storedWorkspace.folders)) {
|
||||
} else {
|
||||
throw new Error(`${path.toString()} looks like an invalid workspace file.`);
|
||||
}
|
||||
|
||||
|
|
95
src/vs/vscode.proposed.d.ts
vendored
95
src/vs/vscode.proposed.d.ts
vendored
|
@ -16,8 +16,12 @@
|
|||
|
||||
declare module 'vscode' {
|
||||
|
||||
//#region Joh - call hierarchy
|
||||
//#region Joh - call hierarchy: https://github.com/microsoft/vscode/issues/70231
|
||||
|
||||
/**
|
||||
* Represents programming constructs like functions or constructors in the context
|
||||
* of call hierarchy.
|
||||
*/
|
||||
export class CallHierarchyItem {
|
||||
/**
|
||||
* The name of this item.
|
||||
|
@ -50,7 +54,7 @@ declare module 'vscode' {
|
|||
range: Range;
|
||||
|
||||
/**
|
||||
* The range that should be selected and reveal when this symbol is being picked, e.g. the name of a function.
|
||||
* The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function.
|
||||
* Must be contained by the [`range`](#CallHierarchyItem.range).
|
||||
*/
|
||||
selectionRange: Range;
|
||||
|
@ -58,35 +62,112 @@ declare module 'vscode' {
|
|||
constructor(kind: SymbolKind, name: string, detail: string, uri: Uri, range: Range, selectionRange: Range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an incoming call, e.g. a caller of a method or constructor.
|
||||
*/
|
||||
export class CallHierarchyIncomingCall {
|
||||
|
||||
/**
|
||||
* The item that makes the call.
|
||||
*/
|
||||
from: CallHierarchyItem;
|
||||
|
||||
/**
|
||||
* The range at which at which the calls appears. This is relative to the caller
|
||||
* denoted by [`this.from`](#CallHierarchyIncomingCall.from).
|
||||
*/
|
||||
fromRanges: Range[];
|
||||
|
||||
/**
|
||||
* Create a new call object.
|
||||
*
|
||||
* @param item The item making the call.
|
||||
* @param fromRanges The ranges at which the calls appear.
|
||||
*/
|
||||
constructor(item: CallHierarchyItem, fromRanges: Range[]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc.
|
||||
*/
|
||||
export class CallHierarchyOutgoingCall {
|
||||
fromRanges: Range[];
|
||||
|
||||
/**
|
||||
* The item that is called.
|
||||
*/
|
||||
to: CallHierarchyItem;
|
||||
|
||||
/**
|
||||
* The range at which this item is called. This is the range relative to the caller, e.g the item
|
||||
* passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls)
|
||||
* and not [`this.to`](#CallHierarchyOutgoingCall.to).
|
||||
*/
|
||||
fromRanges: Range[];
|
||||
|
||||
/**
|
||||
* Create a new call object.
|
||||
*
|
||||
* @param item The item being called
|
||||
* @param fromRanges The ranges at which the calls appear.
|
||||
*/
|
||||
constructor(item: CallHierarchyItem, fromRanges: Range[]);
|
||||
}
|
||||
|
||||
export interface CallHierarchyItemProvider {
|
||||
/**
|
||||
* The call hierarchy provider interface describes the constract between extensions
|
||||
* and the call hierarchy feature which allows to browse calls and caller of function,
|
||||
* methods, constructor etc.
|
||||
*/
|
||||
export interface CallHierarchyProvider {
|
||||
|
||||
/**
|
||||
* Bootstraps call hierarchy by returning the item that is denoted by the given document
|
||||
* and position. This item will be used as entry into the call graph. Providers should
|
||||
* return `undefined` or `null` when there is no item at the given location.
|
||||
*
|
||||
* @param document The document in which the command was invoked.
|
||||
* @param position The position at which the command was invoked.
|
||||
* @param token A cancellation token.
|
||||
* @returns A call hierarchy item or a thenable that resolves to such. The lack of a result can be
|
||||
* signaled by returning `undefined` or `null`.
|
||||
*/
|
||||
prepareCallHierarchy(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<CallHierarchyItem>;
|
||||
|
||||
/**
|
||||
* Provide a list of callers for the provided item, e.g. all function calling a function.
|
||||
* Provide all incoming calls for an item, e.g all callers for a method. In graph terms this descibes directed
|
||||
* and annotated edges inside the call graph, e.g the given item is the starting node and the result is the nodes
|
||||
* that can be reached.
|
||||
*
|
||||
* @param item The hierarchy item for which incoming calls should be computed.
|
||||
* @param token A cancellation token.
|
||||
* @returns A set of incoming calls or a thenable that resolves to such. The lack of a result can be
|
||||
* signaled by returning `undefined` or `null`.
|
||||
*/
|
||||
provideCallHierarchyIncomingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult<CallHierarchyIncomingCall[]>;
|
||||
|
||||
/**
|
||||
* Provide a list of calls for the provided item, e.g. all functions call from a function.
|
||||
* Provide all outgoing calls for an item, e.g call calls to functions, methods, or constructors from the given item. In
|
||||
* graph terms this descibes directed and annotated edges inside the call graph, e.g the given item is the starting
|
||||
* node and the result is the nodes that can be reached.
|
||||
*
|
||||
* @param item The hierarchy item for which outgoing calls should be computed.
|
||||
* @param token A cancellation token.
|
||||
* @returns A set of outgoing calls or a thenable that resolves to such. The lack of a result can be
|
||||
* signaled by returning `undefined` or `null`.
|
||||
*/
|
||||
provideCallHierarchyOutgoingCalls(item: CallHierarchyItem, token: CancellationToken): ProviderResult<CallHierarchyOutgoingCall[]>;
|
||||
}
|
||||
|
||||
export namespace languages {
|
||||
export function registerCallHierarchyProvider(selector: DocumentSelector, provider: CallHierarchyItemProvider): Disposable;
|
||||
|
||||
/**
|
||||
* Register a call hierarchy provider.
|
||||
*
|
||||
* @param selector A selector that defines the documents this provider is applicable to.
|
||||
* @param provider A call hierarchy provider.
|
||||
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
|
||||
*/
|
||||
export function registerCallHierarchyProvider(selector: DocumentSelector, provider: CallHierarchyProvider): Disposable;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
|
|
@ -18,7 +18,7 @@ import { Extensions as PanelExtensions, PanelDescriptor, PanelRegistry } from 'v
|
|||
import { ICommentInfo, ICommentService } from 'vs/workbench/contrib/comments/browser/commentService';
|
||||
import { CommentsPanel } from 'vs/workbench/contrib/comments/browser/commentsPanel';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { CommentProviderFeatures, ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape } from '../common/extHost.protocol';
|
||||
import { CommentProviderFeatures, ExtHostCommentsShape, ExtHostContext, IExtHostContext, MainContext, MainThreadCommentsShape, CommentThreadChanges } from '../common/extHost.protocol';
|
||||
import { COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbench/contrib/comments/browser/commentsTreeViewer';
|
||||
|
||||
|
||||
|
@ -116,17 +116,15 @@ export class MainThreadCommentThread implements modes.CommentThread {
|
|||
this._isDisposed = false;
|
||||
}
|
||||
|
||||
batchUpdate(
|
||||
range: IRange,
|
||||
label: string,
|
||||
contextValue: string | undefined,
|
||||
comments: modes.Comment[],
|
||||
collapsibleState: modes.CommentThreadCollapsibleState) {
|
||||
this._range = range;
|
||||
this._label = label;
|
||||
this._contextValue = contextValue;
|
||||
this._comments = comments;
|
||||
this._collapsibleState = collapsibleState;
|
||||
batchUpdate(changes: CommentThreadChanges) {
|
||||
const modified = (value: keyof CommentThreadChanges): boolean =>
|
||||
Object.prototype.hasOwnProperty.call(changes, value);
|
||||
|
||||
if (modified('range')) { this._range = changes.range!; }
|
||||
if (modified('label')) { this._label = changes.label; }
|
||||
if (modified('contextValue')) { this._contextValue = changes.contextValue; }
|
||||
if (modified('comments')) { this._comments = changes.comments; }
|
||||
if (modified('collapseState')) { this._collapsibleState = changes.collapseState; }
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
@ -228,13 +226,9 @@ export class MainThreadCommentController {
|
|||
updateCommentThread(commentThreadHandle: number,
|
||||
threadId: string,
|
||||
resource: UriComponents,
|
||||
range: IRange,
|
||||
label: string,
|
||||
contextValue: string | undefined,
|
||||
comments: modes.Comment[],
|
||||
collapsibleState: modes.CommentThreadCollapsibleState): void {
|
||||
changes: CommentThreadChanges): void {
|
||||
let thread = this.getKnownThread(commentThreadHandle);
|
||||
thread.batchUpdate(range, label, contextValue, comments, collapsibleState);
|
||||
thread.batchUpdate(changes);
|
||||
|
||||
this._commentService.updateComments(this._uniqueId, {
|
||||
added: [],
|
||||
|
@ -430,18 +424,14 @@ export class MainThreadComments extends Disposable implements MainThreadComments
|
|||
commentThreadHandle: number,
|
||||
threadId: string,
|
||||
resource: UriComponents,
|
||||
range: IRange,
|
||||
label: string,
|
||||
contextValue: string | undefined,
|
||||
comments: modes.Comment[],
|
||||
collapsibleState: modes.CommentThreadCollapsibleState): void {
|
||||
changes: CommentThreadChanges): void {
|
||||
let provider = this._commentControllers.get(handle);
|
||||
|
||||
if (!provider) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return provider.updateCommentThread(commentThreadHandle, threadId, resource, range, label, contextValue, comments, collapsibleState);
|
||||
return provider.updateCommentThread(commentThreadHandle, threadId, resource, changes);
|
||||
}
|
||||
|
||||
$deleteCommentThread(handle: number, commentThreadHandle: number) {
|
||||
|
|
|
@ -369,7 +369,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
registerSelectionRangeProvider(selector: vscode.DocumentSelector, provider: vscode.SelectionRangeProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerSelectionRangeProvider(extension, selector, provider);
|
||||
},
|
||||
registerCallHierarchyProvider(selector: vscode.DocumentSelector, provider: vscode.CallHierarchyItemProvider): vscode.Disposable {
|
||||
registerCallHierarchyProvider(selector: vscode.DocumentSelector, provider: vscode.CallHierarchyProvider): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostLanguageFeatures.registerCallHierarchyProvider(extension, selector, provider);
|
||||
},
|
||||
|
|
|
@ -131,12 +131,20 @@ export interface CommentProviderFeatures {
|
|||
reactionHandler?: boolean;
|
||||
}
|
||||
|
||||
export type CommentThreadChanges = Partial<{
|
||||
range: IRange,
|
||||
label: string,
|
||||
contextValue: string,
|
||||
comments: modes.Comment[],
|
||||
collapseState: modes.CommentThreadCollapsibleState
|
||||
}>;
|
||||
|
||||
export interface MainThreadCommentsShape extends IDisposable {
|
||||
$registerCommentController(handle: number, id: string, label: string): void;
|
||||
$unregisterCommentController(handle: number): void;
|
||||
$updateCommentControllerFeatures(handle: number, features: CommentProviderFeatures): void;
|
||||
$createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, extensionId: ExtensionIdentifier): modes.CommentThread | undefined;
|
||||
$updateCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, label: string | undefined, contextValue: string | undefined, comments: modes.Comment[], collapseState: modes.CommentThreadCollapsibleState): void;
|
||||
$updateCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, changes: CommentThreadChanges): void;
|
||||
$deleteCommentThread(handle: number, commentThreadHandle: number): void;
|
||||
$onDidCommentThreadsChange(handle: number, event: modes.CommentThreadChangedEvent): void;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
|
|||
import * as vscode from 'vscode';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as types from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IRawColorInfo, IWorkspaceEditDto, ICallHierarchyItemDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IRawColorInfo, IWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/model';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
|
@ -182,22 +182,6 @@ export class ExtHostApiCommands {
|
|||
],
|
||||
returns: 'A promise that resolves to an array of DocumentLink-instances.'
|
||||
});
|
||||
this._register('vscode.executeCallHierarchyProviderIncomingCalls', this._executeCallHierarchyIncomingCallsProvider, {
|
||||
description: 'Execute call hierarchy provider for incoming calls',
|
||||
args: [
|
||||
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
|
||||
{ name: 'position', description: 'Position in a text document', constraint: types.Position },
|
||||
],
|
||||
returns: 'A promise that resolves to an array of CallHierarchyIncomingCall-instances.'
|
||||
});
|
||||
this._register('vscode.executeCallHierarchyProviderOutgoingCalls', this._executeCallHierarchyOutgoingCallsProvider, {
|
||||
description: 'Execute call hierarchy provider for outgoing calls',
|
||||
args: [
|
||||
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
|
||||
{ name: 'position', description: 'Position in a text document', constraint: types.Position },
|
||||
],
|
||||
returns: 'A promise that resolves to an array of CallHierarchyOutgoingCall-instances.'
|
||||
});
|
||||
this._register('vscode.executeDocumentColorProvider', this._executeDocumentColorProvider, {
|
||||
description: 'Execute document color provider.',
|
||||
args: [
|
||||
|
@ -573,36 +557,6 @@ export class ExtHostApiCommands {
|
|||
return this._commands.executeCommand<modes.ILink[]>('_executeLinkProvider', resource)
|
||||
.then(tryMapWith(typeConverters.DocumentLink.to));
|
||||
}
|
||||
|
||||
private async _executeCallHierarchyIncomingCallsProvider(resource: URI, position: types.Position): Promise<vscode.CallHierarchyIncomingCall[]> {
|
||||
type IncomingCallDto = {
|
||||
from: ICallHierarchyItemDto;
|
||||
fromRanges: IRange[];
|
||||
};
|
||||
const args = { resource, position: typeConverters.Position.from(position) };
|
||||
const calls = await this._commands.executeCommand<IncomingCallDto[]>('_executeCallHierarchyIncomingCalls', args);
|
||||
|
||||
const result: vscode.CallHierarchyIncomingCall[] = [];
|
||||
for (const call of calls) {
|
||||
result.push(new types.CallHierarchyIncomingCall(typeConverters.CallHierarchyItem.to(call.from), <vscode.Range[]>call.fromRanges.map(typeConverters.Range.to)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private async _executeCallHierarchyOutgoingCallsProvider(resource: URI, position: types.Position): Promise<vscode.CallHierarchyOutgoingCall[]> {
|
||||
type OutgoingCallDto = {
|
||||
fromRanges: IRange[];
|
||||
to: ICallHierarchyItemDto;
|
||||
};
|
||||
const args = { resource, position: typeConverters.Position.from(position) };
|
||||
const calls = await this._commands.executeCommand<OutgoingCallDto[]>('_executeCallHierarchyOutgoingCalls', args);
|
||||
|
||||
const result: vscode.CallHierarchyOutgoingCall[] = [];
|
||||
for (const call of calls) {
|
||||
result.push(new types.CallHierarchyOutgoingCall(typeConverters.CallHierarchyItem.to(call.to), <vscode.Range[]>call.fromRanges.map(typeConverters.Range.to)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function tryMapWith<T, R>(f: (x: T) => R) {
|
||||
|
|
|
@ -16,7 +16,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
|||
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as types from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostCommentsShape, IMainContext, MainContext, MainThreadCommentsShape } from './extHost.protocol';
|
||||
import { ExtHostCommentsShape, IMainContext, MainContext, MainThreadCommentsShape, CommentThreadChanges } from './extHost.protocol';
|
||||
import { ExtHostCommands } from './extHostCommands';
|
||||
|
||||
type ProviderHandle = number;
|
||||
|
@ -213,12 +213,21 @@ export class ExtHostComments implements ExtHostCommentsShape, IDisposable {
|
|||
|
||||
}
|
||||
}
|
||||
type CommentThreadModification = Partial<{
|
||||
range: vscode.Range,
|
||||
label: string | undefined,
|
||||
contextValue: string | undefined,
|
||||
comments: vscode.Comment[],
|
||||
collapsibleState: vscode.CommentThreadCollapsibleState
|
||||
}>;
|
||||
|
||||
export class ExtHostCommentThread implements vscode.CommentThread {
|
||||
private static _handlePool: number = 0;
|
||||
readonly handle = ExtHostCommentThread._handlePool++;
|
||||
public commentHandle: number = 0;
|
||||
|
||||
private modifications: CommentThreadModification = Object.create(null);
|
||||
|
||||
set threadId(id: string) {
|
||||
this._id = id;
|
||||
}
|
||||
|
@ -245,6 +254,7 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
|||
set range(range: vscode.Range) {
|
||||
if (!range.isEqual(this._range)) {
|
||||
this._range = range;
|
||||
this.modifications.range = range;
|
||||
this._onDidUpdateCommentThread.fire();
|
||||
}
|
||||
}
|
||||
|
@ -261,6 +271,7 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
|||
|
||||
set label(label: string | undefined) {
|
||||
this._label = label;
|
||||
this.modifications.label = label;
|
||||
this._onDidUpdateCommentThread.fire();
|
||||
}
|
||||
|
||||
|
@ -272,6 +283,7 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
|||
|
||||
set contextValue(context: string | undefined) {
|
||||
this._contextValue = context;
|
||||
this.modifications.contextValue = context;
|
||||
this._onDidUpdateCommentThread.fire();
|
||||
}
|
||||
|
||||
|
@ -281,6 +293,7 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
|||
|
||||
set comments(newComments: vscode.Comment[]) {
|
||||
this._comments = newComments;
|
||||
this.modifications.comments = newComments;
|
||||
this._onDidUpdateCommentThread.fire();
|
||||
}
|
||||
|
||||
|
@ -292,6 +305,7 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
|||
|
||||
set collapsibleState(newState: vscode.CommentThreadCollapsibleState) {
|
||||
this._collapseState = newState;
|
||||
this.modifications.collapsibleState = newState;
|
||||
this._onDidUpdateCommentThread.fire();
|
||||
}
|
||||
|
||||
|
@ -353,22 +367,34 @@ export class ExtHostCommentThread implements vscode.CommentThread {
|
|||
this._acceptInputDisposables.value = new DisposableStore();
|
||||
}
|
||||
|
||||
const commentThreadRange = extHostTypeConverter.Range.from(this._range);
|
||||
const label = this.label;
|
||||
const contextValue = this.contextValue;
|
||||
const comments = this._comments.map(cmt => { return convertToModeComment(this, this._commentController, cmt, this._commentsMap); });
|
||||
const collapsibleState = convertToCollapsibleState(this._collapseState);
|
||||
const modified = (value: keyof CommentThreadModification): boolean =>
|
||||
Object.prototype.hasOwnProperty.call(this.modifications, value);
|
||||
|
||||
const formattedModifications: CommentThreadChanges = {};
|
||||
if (modified('range')) {
|
||||
formattedModifications.range = extHostTypeConverter.Range.from(this._range);
|
||||
}
|
||||
if (modified('label')) {
|
||||
formattedModifications.label = this.label;
|
||||
}
|
||||
if (modified('contextValue')) {
|
||||
formattedModifications.contextValue = this.contextValue;
|
||||
}
|
||||
if (modified('comments')) {
|
||||
formattedModifications.comments =
|
||||
this._comments.map(cmt => convertToModeComment(this, this._commentController, cmt, this._commentsMap));
|
||||
}
|
||||
if (modified('collapsibleState')) {
|
||||
formattedModifications.collapseState = convertToCollapsibleState(this._collapseState);
|
||||
}
|
||||
this.modifications = {};
|
||||
|
||||
this._proxy.$updateCommentThread(
|
||||
this._commentController.handle,
|
||||
this.handle,
|
||||
this._id!,
|
||||
this._uri,
|
||||
commentThreadRange,
|
||||
label,
|
||||
contextValue,
|
||||
comments,
|
||||
collapsibleState
|
||||
formattedModifications
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -471,8 +471,8 @@ class OnTypeFormattingAdapter {
|
|||
|
||||
class NavigateTypeAdapter {
|
||||
|
||||
private readonly _symbolCache: { [id: number]: vscode.SymbolInformation } = Object.create(null);
|
||||
private readonly _resultCache: { [id: number]: [number, number] } = Object.create(null);
|
||||
private readonly _symbolCache = new Map<number, vscode.SymbolInformation>();
|
||||
private readonly _resultCache = new Map<number, [number, number]>();
|
||||
private readonly _provider: vscode.WorkspaceSymbolProvider;
|
||||
|
||||
constructor(provider: vscode.WorkspaceSymbolProvider) {
|
||||
|
@ -493,40 +493,38 @@ class NavigateTypeAdapter {
|
|||
continue;
|
||||
}
|
||||
const symbol = extHostProtocol.IdObject.mixin(typeConvert.WorkspaceSymbol.from(item));
|
||||
this._symbolCache[symbol._id!] = item;
|
||||
this._symbolCache.set(symbol._id!, item);
|
||||
result.symbols.push(symbol);
|
||||
}
|
||||
}
|
||||
}).then(() => {
|
||||
if (result.symbols.length > 0) {
|
||||
this._resultCache[result._id!] = [result.symbols[0]._id!, result.symbols[result.symbols.length - 1]._id!];
|
||||
this._resultCache.set(result._id!, [result.symbols[0]._id!, result.symbols[result.symbols.length - 1]._id!]);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
resolveWorkspaceSymbol(symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolDto | undefined> {
|
||||
|
||||
async resolveWorkspaceSymbol(symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolDto | undefined> {
|
||||
if (typeof this._provider.resolveWorkspaceSymbol !== 'function') {
|
||||
return Promise.resolve(symbol);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
const item = this._symbolCache[symbol._id!];
|
||||
const item = this._symbolCache.get(symbol._id!);
|
||||
if (item) {
|
||||
return asPromise(() => this._provider.resolveWorkspaceSymbol!(item, token)).then(value => {
|
||||
return value && mixin(symbol, typeConvert.WorkspaceSymbol.from(value), true);
|
||||
});
|
||||
const value = await asPromise(() => this._provider.resolveWorkspaceSymbol!(item, token));
|
||||
return value && mixin(symbol, typeConvert.WorkspaceSymbol.from(value), true);
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
releaseWorkspaceSymbols(id: number): any {
|
||||
const range = this._resultCache[id];
|
||||
const range = this._resultCache.get(id);
|
||||
if (range) {
|
||||
for (let [from, to] = range; from <= to; from++) {
|
||||
delete this._symbolCache[from];
|
||||
this._symbolCache.delete(from);
|
||||
}
|
||||
delete this._resultCache[id];
|
||||
this._resultCache.delete(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1039,7 +1037,7 @@ class CallHierarchyAdapter {
|
|||
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
private readonly _provider: vscode.CallHierarchyItemProvider
|
||||
private readonly _provider: vscode.CallHierarchyProvider
|
||||
) { }
|
||||
|
||||
async prepareSession(uri: URI, position: IPosition, token: CancellationToken): Promise<{ sessionId: string, root: extHostProtocol.ICallHierarchyItemDto } | undefined> {
|
||||
|
@ -1080,11 +1078,12 @@ class CallHierarchyAdapter {
|
|||
}
|
||||
|
||||
releaseSession(sessionId: string): void {
|
||||
this._cache.delete(sessionId);
|
||||
this._cache.delete(sessionId.charAt(0));
|
||||
}
|
||||
|
||||
private _cacheAndConvertItem(sessionId: string, item: vscode.CallHierarchyItem): extHostProtocol.ICallHierarchyItemDto {
|
||||
const array = this._cache.get(sessionId.charAt(0))!;
|
||||
private _cacheAndConvertItem(itemOrSessionId: string, item: vscode.CallHierarchyItem): extHostProtocol.ICallHierarchyItemDto {
|
||||
const sessionId = itemOrSessionId.charAt(0);
|
||||
const array = this._cache.get(sessionId)!;
|
||||
const dto: extHostProtocol.ICallHierarchyItemDto = {
|
||||
id: sessionId + String.fromCharCode(array.length),
|
||||
name: item.name,
|
||||
|
@ -1534,7 +1533,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
|
|||
|
||||
// --- call hierarchy
|
||||
|
||||
registerCallHierarchyProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CallHierarchyItemProvider): vscode.Disposable {
|
||||
registerCallHierarchyProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CallHierarchyProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new CallHierarchyAdapter(this._documents, provider), extension);
|
||||
this._proxy.$registerCallHierarchyProvider(handle, this._transformDocumentSelector(selector));
|
||||
return this._createDisposable(handle);
|
||||
|
|
|
@ -20,17 +20,16 @@ import { DataTransfers } from 'vs/base/browser/dnd';
|
|||
import { DragMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { normalizeDriveLetter } from 'vs/base/common/labels';
|
||||
import { MIME_BINARY } from 'vs/base/common/mime';
|
||||
import { isWindows, isLinux, isWeb } from 'vs/base/common/platform';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IEditorIdentifier, GroupIdentifier } from 'vs/workbench/common/editor';
|
||||
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { addDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
import { addDisposableListener, EventType, asDomUri } from 'vs/base/browser/dom';
|
||||
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
|
||||
export interface IDraggedResource {
|
||||
|
@ -330,15 +329,8 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources:
|
|||
const lineDelimiter = isWindows ? '\r\n' : '\n';
|
||||
event.dataTransfer.setData(DataTransfers.TEXT, sources.map(source => source.resource.scheme === Schemas.file ? normalize(normalizeDriveLetter(source.resource.fsPath)) : source.resource.toString()).join(lineDelimiter));
|
||||
|
||||
const envService = accessor.get(IWorkbenchEnvironmentService);
|
||||
const hasRemote = !!envService.configuration.remoteAuthority;
|
||||
if (
|
||||
!(isLinux && hasRemote) && // Not supported on linux remote due to chrome limitation https://github.com/microsoft/vscode-remote-release/issues/849
|
||||
!isWeb // Does not seem to work anymore when running from web, the file ends up being empty (and PWA crashes)
|
||||
) {
|
||||
// Download URL: enables support to drag a tab as file to desktop (only single file supported)
|
||||
event.dataTransfer.setData(DataTransfers.DOWNLOAD_URL, [MIME_BINARY, basename(firstSource.resource), firstSource.resource.toString()].join(':'));
|
||||
}
|
||||
// Download URL: enables support to drag a tab as file to desktop (only single file supported)
|
||||
event.dataTransfer.setData(DataTransfers.DOWNLOAD_URL, [MIME_BINARY, basename(firstSource.resource), asDomUri(firstSource.resource).toString()].join(':'));
|
||||
|
||||
// Resource URLs: allows to drop multiple resources to a target in VS Code (not directories)
|
||||
const files = sources.filter(s => !s.isDirectory);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { suggestFilename } from 'vs/base/common/mime';
|
||||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { createMemoizer } from 'vs/base/common/decorators';
|
||||
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { basenameOrAuthority, dirname } from 'vs/base/common/resources';
|
||||
import { EditorInput, IEncodingSupport, EncodingMode, ConfirmResult, Verbosity, IModeSupport } from 'vs/workbench/common/editor';
|
||||
|
@ -22,6 +22,7 @@ import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverServ
|
|||
export class UntitledEditorInput extends EditorInput implements IEncodingSupport, IModeSupport {
|
||||
|
||||
static readonly ID: string = 'workbench.editors.untitledEditorInput';
|
||||
private static readonly MEMOIZER = createMemoizer();
|
||||
|
||||
private cachedModel: UntitledEditorModel | null = null;
|
||||
private modelResolve: Promise<UntitledEditorModel & IResolvedTextEditorModel> | null = null;
|
||||
|
@ -43,6 +44,7 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
|
|||
@ILabelService private readonly labelService: ILabelService
|
||||
) {
|
||||
super();
|
||||
this._register(this.labelService.onDidChangeFormatters(() => UntitledEditorInput.MEMOIZER.clear()));
|
||||
}
|
||||
|
||||
get hasAssociatedFilePath(): boolean {
|
||||
|
@ -61,17 +63,17 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
|
|||
return this.hasAssociatedFilePath ? basenameOrAuthority(this.resource) : this.resource.path;
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledEditorInput.MEMOIZER
|
||||
private get shortDescription(): string {
|
||||
return this.labelService.getUriBasenameLabel(dirname(this.resource));
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledEditorInput.MEMOIZER
|
||||
private get mediumDescription(): string {
|
||||
return this.labelService.getUriLabel(dirname(this.resource), { relative: true });
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledEditorInput.MEMOIZER
|
||||
private get longDescription(): string {
|
||||
return this.labelService.getUriLabel(dirname(this.resource));
|
||||
}
|
||||
|
@ -92,17 +94,17 @@ export class UntitledEditorInput extends EditorInput implements IEncodingSupport
|
|||
}
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledEditorInput.MEMOIZER
|
||||
private get shortTitle(): string {
|
||||
return this.getName();
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledEditorInput.MEMOIZER
|
||||
private get mediumTitle(): string {
|
||||
return this.labelService.getUriLabel(this.resource, { relative: true });
|
||||
}
|
||||
|
||||
@memoize
|
||||
@UntitledEditorInput.MEMOIZER
|
||||
private get longTitle(): string {
|
||||
return this.labelService.getUriLabel(this.resource);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ class CallHierarchyController implements IEditorContribution {
|
|||
private readonly _dispoables = new DisposableStore();
|
||||
private readonly _sessionDisposables = new DisposableStore();
|
||||
|
||||
private _widget?: CallHierarchyTreePeekWidget;
|
||||
|
||||
constructor(
|
||||
private readonly _editor: ICodeEditor,
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
|
@ -74,24 +76,24 @@ class CallHierarchyController implements IEditorContribution {
|
|||
const direction = this._storageService.getNumber(CallHierarchyController._StorageDirection, StorageScope.GLOBAL, <number>CallHierarchyDirection.CallsFrom);
|
||||
|
||||
Event.any<any>(this._editor.onDidChangeModel, this._editor.onDidChangeModelLanguage)(this.endCallHierarchy, this, this._sessionDisposables);
|
||||
const widget = this._instantiationService.createInstance(
|
||||
this._widget = this._instantiationService.createInstance(
|
||||
CallHierarchyTreePeekWidget,
|
||||
this._editor,
|
||||
position,
|
||||
direction
|
||||
);
|
||||
|
||||
widget.showLoading();
|
||||
this._widget.showLoading();
|
||||
this._ctxIsVisible.set(true);
|
||||
|
||||
const cts = new CancellationTokenSource();
|
||||
|
||||
this._sessionDisposables.add(widget.onDidClose(() => {
|
||||
this._sessionDisposables.add(this._widget.onDidClose(() => {
|
||||
this.endCallHierarchy();
|
||||
this._storageService.store(CallHierarchyController._StorageDirection, widget.direction, StorageScope.GLOBAL);
|
||||
this._storageService.store(CallHierarchyController._StorageDirection, this._widget!.direction, StorageScope.GLOBAL);
|
||||
}));
|
||||
this._sessionDisposables.add({ dispose() { cts.dispose(true); } });
|
||||
this._sessionDisposables.add(widget);
|
||||
this._sessionDisposables.add(this._widget);
|
||||
|
||||
try {
|
||||
const model = await CallHierarchyModel.create(document, position, cts.token);
|
||||
|
@ -99,16 +101,22 @@ class CallHierarchyController implements IEditorContribution {
|
|||
return; // nothing
|
||||
} else if (model) {
|
||||
this._sessionDisposables.add(model);
|
||||
widget.showItem(model);
|
||||
this._widget.showModel(model);
|
||||
} else {
|
||||
widget.showMessage(localize('no.item', "No results"));
|
||||
this._widget.showMessage(localize('no.item', "No results"));
|
||||
}
|
||||
} catch (e) {
|
||||
widget.showMessage(localize('error', "Failed to show call hierarchy"));
|
||||
this._widget.showMessage(localize('error', "Failed to show call hierarchy"));
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
toggleCallHierarchyDirection(): void {
|
||||
if (this._widget) {
|
||||
this._widget.toggleDirection();
|
||||
}
|
||||
}
|
||||
|
||||
endCallHierarchy(): void {
|
||||
this._sessionDisposables.clear();
|
||||
this._ctxIsVisible.set(false);
|
||||
|
@ -135,17 +143,38 @@ registerEditorAction(class extends EditorAction {
|
|||
primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H
|
||||
},
|
||||
precondition: ContextKeyExpr.and(
|
||||
_ctxCallHierarchyVisible.negate(),
|
||||
_ctxHasCompletionItemProvider,
|
||||
PeekContext.notInPeekEditor
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
async run(_accessor: ServicesAccessor, editor: ICodeEditor, args: any): Promise<void> {
|
||||
async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
|
||||
return CallHierarchyController.get(editor).startCallHierarchy();
|
||||
}
|
||||
});
|
||||
|
||||
registerEditorAction(class extends EditorAction {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.toggleCallHierarchy',
|
||||
label: localize('title.toggle', "Toggle Call Hierarchy"),
|
||||
alias: 'Toggle Call Hierarchy',
|
||||
kbOpts: {
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyMod.Shift + KeyMod.Alt + KeyCode.KEY_H
|
||||
},
|
||||
precondition: _ctxCallHierarchyVisible
|
||||
});
|
||||
}
|
||||
|
||||
async run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
|
||||
return CallHierarchyController.get(editor).toggleCallHierarchyDirection();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
registerEditorCommand(new class extends EditorCommand {
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
|||
import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions';
|
||||
import { isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
|
||||
|
@ -105,14 +104,3 @@ export class CallHierarchyModel {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
export async function provideIncomingCalls(model: ITextModel, position: IPosition, token: CancellationToken): Promise<IncomingCall[]> {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
export async function provideOutgoingCalls(model: ITextModel, position: IPosition, token: CancellationToken): Promise<OutgoingCall[]> {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
registerDefaultLanguageCommand('_executeCallHierarchyIncomingCalls', async (model, position) => provideIncomingCalls(model, position, CancellationToken.None));
|
||||
registerDefaultLanguageCommand('_executeCallHierarchyOutgoingCalls', async (model, position) => provideOutgoingCalls(model, position, CancellationToken.None));
|
||||
|
|
|
@ -42,19 +42,14 @@ const enum State {
|
|||
|
||||
class ChangeHierarchyDirectionAction extends Action {
|
||||
|
||||
constructor(direction: CallHierarchyDirection, updateDirection: (direction: CallHierarchyDirection) => void) {
|
||||
constructor(getDirection: () => CallHierarchyDirection, toggleDirection: () => void) {
|
||||
super('', undefined, '', true, () => {
|
||||
if (direction === CallHierarchyDirection.CallsTo) {
|
||||
direction = CallHierarchyDirection.CallsFrom;
|
||||
} else {
|
||||
direction = CallHierarchyDirection.CallsTo;
|
||||
}
|
||||
updateDirection(direction);
|
||||
toggleDirection();
|
||||
update();
|
||||
return Promise.resolve();
|
||||
});
|
||||
const update = () => {
|
||||
if (direction === CallHierarchyDirection.CallsFrom) {
|
||||
if (getDirection() === CallHierarchyDirection.CallsFrom) {
|
||||
this.label = localize('toggle.from', "Showing Calls");
|
||||
this.class = 'calls-from';
|
||||
} else {
|
||||
|
@ -198,6 +193,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
|||
addClass(treeContainer, 'tree');
|
||||
container.appendChild(treeContainer);
|
||||
const options: IAsyncDataTreeOptions<callHTree.Call, FuzzyScore> = {
|
||||
sorter: new callHTree.Sorter(),
|
||||
identityProvider: new callHTree.IdentityProvider(() => this._direction),
|
||||
ariaLabel: localize('tree.aria', "Call Hierarchy"),
|
||||
expandOnlyOnTwistieClick: true,
|
||||
|
@ -269,12 +265,8 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
|||
let previewUri: URI;
|
||||
if (this._direction === CallHierarchyDirection.CallsFrom) {
|
||||
// outgoing calls: show caller and highlight focused calls
|
||||
const parent = this._tree.getParentElement(element);
|
||||
if (parent instanceof callHTree.Call) {
|
||||
previewUri = parent.item.uri;
|
||||
} else {
|
||||
previewUri = parent.root.uri;
|
||||
}
|
||||
previewUri = element.parent ? element.parent.item.uri : element.model.root.uri;
|
||||
|
||||
} else {
|
||||
// incoming calls: show caller and highlight focused calls
|
||||
previewUri = element.item.uri;
|
||||
|
@ -365,42 +357,47 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget {
|
|||
this._message.focus();
|
||||
}
|
||||
|
||||
async showItem(item: CallHierarchyModel): Promise<void> {
|
||||
async showModel(model: CallHierarchyModel): Promise<void> {
|
||||
|
||||
this._show();
|
||||
const viewState = this._treeViewStates.get(this._direction);
|
||||
|
||||
await this._tree.setInput(item, viewState);
|
||||
await this._tree.setInput(model, viewState);
|
||||
|
||||
const root = <ITreeNode<callHTree.Call>>this._tree.getNode(item).children[0];
|
||||
const root = <ITreeNode<callHTree.Call>>this._tree.getNode(model).children[0];
|
||||
await this._tree.expand(root.element);
|
||||
|
||||
if (root.children.length === 0) {
|
||||
//
|
||||
this.showMessage(this._direction === CallHierarchyDirection.CallsFrom
|
||||
? localize('empt.callsFrom', "No calls from '{0}'", item.root.name)
|
||||
: localize('empt.callsTo', "No callers of '{0}'", item.root.name));
|
||||
? localize('empt.callsFrom', "No calls from '{0}'", model.root.name)
|
||||
: localize('empt.callsTo', "No callers of '{0}'", model.root.name));
|
||||
|
||||
} else {
|
||||
this._parent.dataset['state'] = State.Data;
|
||||
this._tree.domFocus();
|
||||
this._tree.setFocus([root.children[0].element]);
|
||||
if (!viewState) {
|
||||
this._tree.setFocus([root.children[0].element]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._changeDirectionAction) {
|
||||
const changeDirection = async (newDirection: CallHierarchyDirection) => {
|
||||
if (this._direction !== newDirection) {
|
||||
this._treeViewStates.set(this._direction, this._tree.getViewState());
|
||||
this._direction = newDirection;
|
||||
await this.showItem(item);
|
||||
}
|
||||
};
|
||||
this._changeDirectionAction = new ChangeHierarchyDirectionAction(this._direction, changeDirection);
|
||||
this._changeDirectionAction = new ChangeHierarchyDirectionAction(() => this._direction, () => this.toggleDirection());
|
||||
this._disposables.add(this._changeDirectionAction);
|
||||
this._actionbarWidget!.push(this._changeDirectionAction, { icon: true, label: false });
|
||||
}
|
||||
}
|
||||
|
||||
async toggleDirection(): Promise<void> {
|
||||
const model = this._tree.getInput();
|
||||
if (model) {
|
||||
const newDirection = this._direction === CallHierarchyDirection.CallsTo ? CallHierarchyDirection.CallsFrom : CallHierarchyDirection.CallsTo;
|
||||
this._treeViewStates.set(this._direction, this._tree.getViewState());
|
||||
this._direction = newDirection;
|
||||
await this.showModel(model);
|
||||
}
|
||||
}
|
||||
|
||||
private _show() {
|
||||
if (!this._isShowing) {
|
||||
this.editor.revealLineInCenterIfOutsideViewport(this._where.lineNumber, ScrollType.Smooth);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IAsyncDataSource, ITreeRenderer, ITreeNode } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IAsyncDataSource, ITreeRenderer, ITreeNode, ITreeSorter } from 'vs/base/browser/ui/tree/tree';
|
||||
import { CallHierarchyItem, CallHierarchyDirection, CallHierarchyModel, } from 'vs/workbench/contrib/callHierarchy/browser/callHierarchy';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IIdentityProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
|
@ -11,13 +11,24 @@ import { FuzzyScore, createMatches } from 'vs/base/common/filters';
|
|||
import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';
|
||||
import { SymbolKinds, Location } from 'vs/editor/common/modes';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { compare } from 'vs/base/common/strings';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
|
||||
export class Call {
|
||||
constructor(
|
||||
readonly item: CallHierarchyItem,
|
||||
readonly locations: Location[],
|
||||
readonly model: CallHierarchyModel
|
||||
readonly model: CallHierarchyModel,
|
||||
readonly parent: Call | undefined
|
||||
) { }
|
||||
|
||||
static compare(a: Call, b: Call): number {
|
||||
let res = compare(a.item.uri.toString(), b.item.uri.toString());
|
||||
if (res === 0) {
|
||||
res = Range.compareRangesUsingStarts(a.item.range, b.item.range);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
export class DataSource implements IAsyncDataSource<CallHierarchyModel, Call> {
|
||||
|
@ -32,43 +43,40 @@ export class DataSource implements IAsyncDataSource<CallHierarchyModel, Call> {
|
|||
|
||||
async getChildren(element: CallHierarchyModel | Call): Promise<Call[]> {
|
||||
if (element instanceof CallHierarchyModel) {
|
||||
return [new Call(element.root, [], element)];
|
||||
return [new Call(element.root, [], element, undefined)];
|
||||
}
|
||||
|
||||
const results: Call[] = [];
|
||||
const { model, item } = element;
|
||||
|
||||
if (this.getDirection() === CallHierarchyDirection.CallsFrom) {
|
||||
await this._getOutgoingCalls(element.model, element.item, results);
|
||||
return (await model.resolveOutgoingCalls(item, CancellationToken.None)).map(call => {
|
||||
return new Call(
|
||||
call.to,
|
||||
call.fromRanges.map(range => ({ range, uri: item.uri })),
|
||||
model,
|
||||
element
|
||||
);
|
||||
});
|
||||
|
||||
} else {
|
||||
await this._getIncomingCalls(element.model, element.item, results);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private async _getOutgoingCalls(model: CallHierarchyModel, item: CallHierarchyItem, bucket: Call[]): Promise<void> {
|
||||
|
||||
const outgoingCalls = await model.resolveOutgoingCalls(item, CancellationToken.None);
|
||||
for (const call of outgoingCalls) {
|
||||
bucket.push(new Call(
|
||||
call.to,
|
||||
call.fromRanges.map(range => ({ range, uri: item.uri })),
|
||||
model
|
||||
));
|
||||
return (await model.resolveIncomingCalls(item, CancellationToken.None)).map(call => {
|
||||
return new Call(
|
||||
call.from,
|
||||
call.fromRanges.map(range => ({ range, uri: call.from.uri })),
|
||||
model,
|
||||
element
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async _getIncomingCalls(model: CallHierarchyModel, item: CallHierarchyItem, bucket: Call[]): Promise<void> {
|
||||
const incomingCalls = await model.resolveIncomingCalls(item, CancellationToken.None);
|
||||
for (const call of incomingCalls) {
|
||||
bucket.push(new Call(
|
||||
call.from,
|
||||
call.fromRanges.map(range => ({ range, uri: call.from.uri })),
|
||||
model
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class Sorter implements ITreeSorter<Call> {
|
||||
|
||||
compare(element: Call, otherElement: Call): number {
|
||||
return Call.compare(element, otherElement);
|
||||
}
|
||||
}
|
||||
|
||||
export class IdentityProvider implements IIdentityProvider<Call> {
|
||||
|
||||
|
@ -77,7 +85,11 @@ export class IdentityProvider implements IIdentityProvider<Call> {
|
|||
) { }
|
||||
|
||||
getId(element: Call): { toString(): string; } {
|
||||
return this.getDirection() + '->' + element.item.id;
|
||||
let res = this.getDirection() + JSON.stringify(element.item.uri) + JSON.stringify(element.item.range);
|
||||
if (element.parent) {
|
||||
res += this.getId(element.parent);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,4 +6,5 @@
|
|||
.monaco-editor .accessibilityHelpWidget {
|
||||
padding: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
overflow: auto;
|
||||
}
|
||||
|
|
|
@ -263,11 +263,13 @@ class AccessibilityHelpWidget extends Widget implements IOverlayWidget {
|
|||
private _layout(): void {
|
||||
let editorLayout = this._editor.getLayoutInfo();
|
||||
|
||||
let top = Math.round((editorLayout.height - AccessibilityHelpWidget.HEIGHT) / 2);
|
||||
this._domNode.setTop(top);
|
||||
const width = Math.min(editorLayout.width - 40, AccessibilityHelpWidget.WIDTH);
|
||||
const height = Math.min(editorLayout.height - 40, AccessibilityHelpWidget.HEIGHT);
|
||||
|
||||
let left = Math.round((editorLayout.width - AccessibilityHelpWidget.WIDTH) / 2);
|
||||
this._domNode.setLeft(left);
|
||||
this._domNode.setTop(Math.round((editorLayout.height - height) / 2));
|
||||
this._domNode.setLeft(Math.round((editorLayout.width - width) / 2));
|
||||
this._domNode.setWidth(width);
|
||||
this._domNode.setHeight(height);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { ParseError, parse } from 'vs/base/common/json';
|
||||
import { ParseError, parse, getNodeType } from 'vs/base/common/json';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
@ -91,10 +91,14 @@ export class LanguageConfigurationFileHandler {
|
|||
private _handleConfigFile(languageIdentifier: LanguageIdentifier, configFileLocation: URI): void {
|
||||
this._fileService.readFile(configFileLocation).then((contents) => {
|
||||
const errors: ParseError[] = [];
|
||||
const configuration = <ILanguageConfiguration>parse(contents.value.toString(), errors);
|
||||
let configuration = <ILanguageConfiguration>parse(contents.value.toString(), errors);
|
||||
if (errors.length) {
|
||||
console.error(nls.localize('parseErrors', "Errors parsing {0}: {1}", configFileLocation.toString(), errors.map(e => (`[${e.offset}, ${e.length}] ${getParseErrorMessage(e.error)}`)).join('\n')));
|
||||
}
|
||||
if (getNodeType(configuration) !== 'object') {
|
||||
console.error(nls.localize('formatError', "{0}: Invalid format, JSON object expected.", configFileLocation.toString()));
|
||||
configuration = {};
|
||||
}
|
||||
this._handleConfig(languageIdentifier, configuration);
|
||||
}, (err) => {
|
||||
console.error(err);
|
||||
|
|
|
@ -57,7 +57,7 @@ export class CommentNode extends Disposable {
|
|||
protected toolbar: ToolBar | undefined;
|
||||
private _commentFormActions: CommentFormActions | null = null;
|
||||
|
||||
private readonly _onDidDelete = new Emitter<CommentNode>();
|
||||
private readonly _onDidClick = new Emitter<CommentNode>();
|
||||
|
||||
public get domNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
|
@ -89,7 +89,7 @@ export class CommentNode extends Disposable {
|
|||
this._contextKeyService = contextKeyService.createScoped(this._domNode);
|
||||
this._commentContextValue = this._contextKeyService.createKey('comment', comment.contextValue);
|
||||
|
||||
this._domNode.tabIndex = 0;
|
||||
this._domNode.tabIndex = -1;
|
||||
const avatar = dom.append(this._domNode, dom.$('div.avatar-container'));
|
||||
if (comment.userIconPath) {
|
||||
const img = <HTMLImageElement>dom.append(avatar, dom.$('img.avatar'));
|
||||
|
@ -111,10 +111,12 @@ export class CommentNode extends Disposable {
|
|||
this._domNode.setAttribute('aria-label', `${comment.userName}, ${comment.body.value}`);
|
||||
this._domNode.setAttribute('role', 'treeitem');
|
||||
this._clearTimeout = null;
|
||||
|
||||
this._register(dom.addDisposableListener(this._domNode, dom.EventType.CLICK, () => this.isEditing || this._onDidClick.fire(this)));
|
||||
}
|
||||
|
||||
public get onDidDelete(): Event<CommentNode> {
|
||||
return this._onDidDelete.event;
|
||||
public get onDidClick(): Event<CommentNode> {
|
||||
return this._onDidClick.event;
|
||||
}
|
||||
|
||||
private createHeader(commentDetailsContainer: HTMLElement): void {
|
||||
|
@ -430,19 +432,31 @@ export class CommentNode extends Disposable {
|
|||
this._commentFormActions.setActions(menu);
|
||||
}
|
||||
|
||||
setFocus(focused: boolean, visible: boolean = false) {
|
||||
if (focused) {
|
||||
this._domNode.focus();
|
||||
this._actionsToolbarContainer.classList.remove('hidden');
|
||||
this._actionsToolbarContainer.classList.add('tabfocused');
|
||||
this._domNode.tabIndex = 0;
|
||||
} else {
|
||||
if (this._actionsToolbarContainer.classList.contains('tabfocused') && !this._actionsToolbarContainer.classList.contains('mouseover')) {
|
||||
this._actionsToolbarContainer.classList.add('hidden');
|
||||
this._domNode.tabIndex = -1;
|
||||
}
|
||||
this._actionsToolbarContainer.classList.remove('tabfocused');
|
||||
}
|
||||
}
|
||||
|
||||
private registerActionBarListeners(actionsContainer: HTMLElement): void {
|
||||
this._register(dom.addDisposableListener(this._domNode, 'mouseenter', () => {
|
||||
actionsContainer.classList.remove('hidden');
|
||||
actionsContainer.classList.add('mouseover');
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(this._domNode, 'focus', () => {
|
||||
actionsContainer.classList.remove('hidden');
|
||||
}));
|
||||
|
||||
this._register(dom.addDisposableListener(this._domNode, 'mouseleave', () => {
|
||||
if (!this._domNode.contains(document.activeElement)) {
|
||||
if (actionsContainer.classList.contains('mouseover') && !actionsContainer.classList.contains('tabfocused')) {
|
||||
actionsContainer.classList.add('hidden');
|
||||
}
|
||||
actionsContainer.classList.remove('mouseover');
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/comme
|
|||
import { SimpleCommentEditor } from './simpleCommentEditor';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
|
||||
export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration';
|
||||
const COLLAPSE_ACTION_CLASS = 'expand-review-action';
|
||||
|
@ -84,6 +86,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
|||
private _commentEditorIsEmpty!: IContextKey<boolean>;
|
||||
private _commentFormActions!: CommentFormActions;
|
||||
private _scopedInstatiationService: IInstantiationService;
|
||||
private _focusedComment: number | undefined = undefined;
|
||||
|
||||
public get owner(): string {
|
||||
return this._owner;
|
||||
|
@ -268,6 +271,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
|||
}
|
||||
|
||||
public collapse(): Promise<void> {
|
||||
this._commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Collapsed;
|
||||
if (this._commentThread.comments && this._commentThread.comments.length === 0) {
|
||||
this.deleteCommentThread();
|
||||
return Promise.resolve();
|
||||
|
@ -286,11 +290,13 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
|||
|
||||
toggleExpand(lineNumber: number) {
|
||||
if (this._isExpanded) {
|
||||
this._commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Collapsed;
|
||||
this.hide();
|
||||
if (!this._commentThread.comments || !this._commentThread.comments.length) {
|
||||
this.deleteCommentThread();
|
||||
}
|
||||
} else {
|
||||
this._commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Expanded;
|
||||
this.show({ lineNumber: lineNumber, column: 1 }, 2);
|
||||
}
|
||||
}
|
||||
|
@ -379,6 +385,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
|||
} else {
|
||||
this._commentThreadContextValue.reset();
|
||||
}
|
||||
|
||||
this.setFocusedComment(this._focusedComment);
|
||||
}
|
||||
|
||||
protected _onWidth(widthInPixel: number): void {
|
||||
|
@ -401,6 +409,21 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
|||
|
||||
this._commentsElement = dom.append(this._bodyElement, dom.$('div.comments-container'));
|
||||
this._commentsElement.setAttribute('role', 'presentation');
|
||||
this._commentsElement.tabIndex = 0;
|
||||
|
||||
this._disposables.add(dom.addDisposableListener(this._commentsElement, dom.EventType.KEY_DOWN, (e) => {
|
||||
let event = new StandardKeyboardEvent(e as KeyboardEvent);
|
||||
if (event.equals(KeyCode.UpArrow) || event.equals(KeyCode.DownArrow)) {
|
||||
const moveFocusWithinBounds = (change: number): number => {
|
||||
if (this._focusedComment === undefined && change >= 0) { return 0; }
|
||||
if (this._focusedComment === undefined && change < 0) { return this._commentElements.length - 1; }
|
||||
let newIndex = this._focusedComment! + change;
|
||||
return Math.min(Math.max(0, newIndex), this._commentElements.length - 1);
|
||||
};
|
||||
|
||||
this.setFocusedComment(event.equals(KeyCode.UpArrow) ? moveFocusWithinBounds(-1) : moveFocusWithinBounds(1));
|
||||
}
|
||||
}));
|
||||
|
||||
this._commentElements = [];
|
||||
if (this._commentThread.comments) {
|
||||
|
@ -565,6 +588,19 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
|||
}));
|
||||
}
|
||||
|
||||
private setFocusedComment(value: number | undefined) {
|
||||
if (this._focusedComment !== undefined) {
|
||||
this._commentElements[this._focusedComment]?.setFocus(false);
|
||||
}
|
||||
|
||||
if (this._commentElements.length === 0 || value === undefined) {
|
||||
this._focusedComment = undefined;
|
||||
} else {
|
||||
this._focusedComment = Math.min(value, this._commentElements.length - 1);
|
||||
this._commentElements[this._focusedComment].setFocus(true);
|
||||
}
|
||||
}
|
||||
|
||||
private getActiveComment(): CommentNode | ReviewZoneWidget {
|
||||
return this._commentElements.filter(node => node.isEditing)[0] || this;
|
||||
}
|
||||
|
@ -613,25 +649,9 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
|
|||
this._markdownRenderer);
|
||||
|
||||
this._disposables.add(newCommentNode);
|
||||
this._disposables.add(newCommentNode.onDidDelete(deletedNode => {
|
||||
const deletedNodeId = deletedNode.comment.uniqueIdInThread;
|
||||
const deletedElementIndex = arrays.firstIndex(this._commentElements, commentNode => commentNode.comment.uniqueIdInThread === deletedNodeId);
|
||||
if (deletedElementIndex > -1) {
|
||||
this._commentElements.splice(deletedElementIndex, 1);
|
||||
}
|
||||
|
||||
const deletedCommentIndex = arrays.firstIndex(this._commentThread.comments!, comment => comment.uniqueIdInThread === deletedNodeId);
|
||||
if (deletedCommentIndex > -1) {
|
||||
this._commentThread.comments!.splice(deletedCommentIndex, 1);
|
||||
}
|
||||
|
||||
this._commentsElement.removeChild(deletedNode.domNode);
|
||||
deletedNode.dispose();
|
||||
|
||||
if (this._commentThread.comments!.length === 0) {
|
||||
this.dispose();
|
||||
}
|
||||
}));
|
||||
this._disposables.add(newCommentNode.onDidClick(clickedNode =>
|
||||
this.setFocusedComment(arrays.firstIndex(this._commentElements, commentNode => commentNode.comment.uniqueIdInThread === clickedNode.comment.uniqueIdInThread))
|
||||
));
|
||||
|
||||
return newCommentNode;
|
||||
}
|
||||
|
|
|
@ -2101,7 +2101,7 @@ export abstract class AbstractConfigureRecommendedExtensionsAction extends Actio
|
|||
protected getWorkspaceFolderExtensionsConfigContent(extensionsFileResource: URI): Promise<IExtensionsConfigContent> {
|
||||
return Promise.resolve(this.fileService.readFile(extensionsFileResource))
|
||||
.then(content => {
|
||||
return (<IExtensionsConfigContent>json.parse(content.value.toString()));
|
||||
return (<IExtensionsConfigContent>json.parse(content.value.toString()) || {});
|
||||
}, err => ({ recommendations: [], unwantedRecommendations: [] }));
|
||||
}
|
||||
|
||||
|
|
|
@ -172,7 +172,7 @@ class HelpItem implements IHelpItem {
|
|||
const action = await this.quickInputService.pick(actions, { placeHolder: nls.localize('pickRemoteExtension', "Select url to open") });
|
||||
|
||||
if (action) {
|
||||
await this.openerService.open(URI.parse(action.label));
|
||||
await this.openerService.open(URI.parse(action.description));
|
||||
}
|
||||
} else {
|
||||
await this.openerService.open(URI.parse(this.values[0].url));
|
||||
|
|
|
@ -114,7 +114,11 @@ export class SCMStatusController implements IWorkbenchContribution {
|
|||
this.disposables.push(disposable);
|
||||
|
||||
if (!this.focusedRepository) {
|
||||
this.onDidFocusRepository(repository);
|
||||
if (this.editorService.activeEditor) {
|
||||
this.onDidActiveEditorChange();
|
||||
} else {
|
||||
this.onDidFocusRepository(repository);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { parse as jsonParse } from 'vs/base/common/json';
|
||||
import { parse as jsonParse, getNodeType } from 'vs/base/common/json';
|
||||
import { forEach } from 'vs/base/common/collections';
|
||||
import { localize } from 'vs/nls';
|
||||
import { extname, basename } from 'vs/base/common/path';
|
||||
|
@ -203,7 +203,7 @@ export class SnippetFile {
|
|||
if (!this._loadPromise) {
|
||||
this._loadPromise = Promise.resolve(this._fileService.readFile(this.location)).then(content => {
|
||||
const data = <JsonSerializedSnippets>jsonParse(content.value.toString());
|
||||
if (typeof data === 'object') {
|
||||
if (getNodeType(data) === 'object') {
|
||||
forEach(data, entry => {
|
||||
const { key: name, value: scopeOrTemplate } = entry;
|
||||
if (isJsonSerializedSnippet(scopeOrTemplate)) {
|
||||
|
|
|
@ -14,6 +14,7 @@ import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/termina
|
|||
const SHELL_EXECUTABLES = [
|
||||
'cmd.exe',
|
||||
'powershell.exe',
|
||||
'pwsh.exe',
|
||||
'bash.exe',
|
||||
'wsl.exe',
|
||||
'ubuntu.exe',
|
||||
|
|
|
@ -8,14 +8,21 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
|||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution } from 'vs/workbench/contrib/update/browser/update';
|
||||
import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, CheckForVSCodeUpdateAction, CONTEXT_UPDATE_STATE } from 'vs/workbench/contrib/update/browser/update';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { StateType } from 'vs/platform/update/common/update';
|
||||
|
||||
const workbench = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
|
||||
workbench.registerWorkbenchContribution(ProductContribution, LifecyclePhase.Restored);
|
||||
workbench.registerWorkbenchContribution(UpdateContribution, LifecyclePhase.Restored);
|
||||
|
||||
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
|
||||
// Editor
|
||||
Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions)
|
||||
.registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), 'Show Release Notes');
|
||||
actionRegistry
|
||||
.registerWorkbenchAction(new SyncActionDescriptor(ShowCurrentReleaseNotesAction, ShowCurrentReleaseNotesAction.ID, ShowCurrentReleaseNotesAction.LABEL), `${product.nameShort}: Show Release Notes`, product.nameShort);
|
||||
|
||||
actionRegistry
|
||||
.registerWorkbenchAction(new SyncActionDescriptor(CheckForVSCodeUpdateAction, CheckForVSCodeUpdateAction.ID, CheckForVSCodeUpdateAction.LABEL), `${product.nameShort}: Check for Update`, product.nameShort, CONTEXT_UPDATE_STATE.isEqualTo(StateType.Idle));
|
||||
|
|
|
@ -26,11 +26,11 @@ import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/cont
|
|||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { FalseContext } from 'vs/platform/contextkey/common/contextkeys';
|
||||
import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update';
|
||||
import { ShowCurrentReleaseNotesActionId, CheckForVSCodeUpdateActionId } from 'vs/workbench/contrib/update/common/update';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
|
||||
const CONTEXT_UPDATE_STATE = new RawContextKey<string>('updateState', StateType.Uninitialized);
|
||||
export const CONTEXT_UPDATE_STATE = new RawContextKey<string>('updateState', StateType.Idle);
|
||||
|
||||
let releaseNotesManager: ReleaseNotesManager | undefined = undefined;
|
||||
|
||||
|
@ -469,3 +469,23 @@ export class UpdateContribution extends Disposable implements IWorkbenchContribu
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class CheckForVSCodeUpdateAction extends Action {
|
||||
|
||||
static readonly ID = CheckForVSCodeUpdateActionId;
|
||||
static LABEL = nls.localize('checkForUpdates', "Check for Updates...");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||
@IUpdateService private readonly updateService: IUpdateService,
|
||||
) {
|
||||
super(id, label, undefined, true);
|
||||
}
|
||||
|
||||
run(): Promise<void> {
|
||||
return this.updateService.checkForUpdates(this.workbenchEnvironmentService.configuration.sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,4 +3,5 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export const ShowCurrentReleaseNotesActionId = 'update.showCurrentReleaseNotes';
|
||||
export const ShowCurrentReleaseNotesActionId = 'update.showCurrentReleaseNotes';
|
||||
export const CheckForVSCodeUpdateActionId = 'update.checkForVSCodeUpdate';
|
|
@ -121,7 +121,7 @@ export class TrustedDomainsFileSystemProvider implements IFileSystemProvider, IW
|
|||
this.storageService.store('http.linkProtectionTrustedDomainsContent', trustedDomainsContent, StorageScope.GLOBAL);
|
||||
this.storageService.store(
|
||||
'http.linkProtectionTrustedDomains',
|
||||
JSON.stringify(trustedDomains),
|
||||
JSON.stringify(trustedDomains) || '',
|
||||
StorageScope.GLOBAL
|
||||
);
|
||||
} catch (err) { }
|
||||
|
|
|
@ -409,7 +409,7 @@ export class ConfigurationEditingService {
|
|||
return false;
|
||||
}
|
||||
const parseErrors: json.ParseError[] = [];
|
||||
json.parse(model.getValue(), parseErrors);
|
||||
json.parse(model.getValue(), parseErrors, { allowTrailingComma: true, allowEmptyContent: true });
|
||||
return parseErrors.length > 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ export class JSONEditingService implements IJSONEditingService {
|
|||
|
||||
private hasParseErrors(model: ITextModel): boolean {
|
||||
const parseErrors: json.ParseError[] = [];
|
||||
json.parse(model.getValue(), parseErrors);
|
||||
json.parse(model.getValue(), parseErrors, { allowTrailingComma: true, allowEmptyContent: true });
|
||||
return parseErrors.length > 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment
|
|||
@memoize
|
||||
get webviewExternalEndpoint(): string {
|
||||
// TODO: get fallback from product.json
|
||||
return (this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}').replace('{{commit}}', product.commit || 'c58aaab8a1cc22a7139b761166a0d4f37d41e998');
|
||||
return (this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}').replace('{{commit}}', product.commit || 'b53811e67e65c6a564a80e1c412ca2b13de02907');
|
||||
}
|
||||
|
||||
@memoize
|
||||
|
|
|
@ -21,7 +21,7 @@ export class NativeWorkbenchEnvironmentService extends EnvironmentService implem
|
|||
get webviewExternalEndpoint(): string {
|
||||
const baseEndpoint = 'https://{{uuid}}.vscode-webview-test.com/{{commit}}';
|
||||
|
||||
return baseEndpoint.replace('{{commit}}', product.commit || 'c58aaab8a1cc22a7139b761166a0d4f37d41e998');
|
||||
return baseEndpoint.replace('{{commit}}', product.commit || 'b53811e67e65c6a564a80e1c412ca2b13de02907');
|
||||
}
|
||||
|
||||
@memoize
|
||||
|
|
|
@ -51,7 +51,7 @@ class ExtensionManifestParser extends ExtensionManifestHandler {
|
|||
return pfs.readFile(this._absoluteManifestPath).then((manifestContents) => {
|
||||
const errors: json.ParseError[] = [];
|
||||
const manifest = json.parse(manifestContents.toString(), errors);
|
||||
if (!!manifest && errors.length === 0) {
|
||||
if (errors.length === 0 && json.getNodeType(manifest) === 'object') {
|
||||
if (manifest.__metadata) {
|
||||
manifest.uuid = manifest.__metadata.id;
|
||||
}
|
||||
|
@ -104,6 +104,9 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler {
|
|||
this._log.error(this._absoluteFolderPath, nls.localize('jsonsParseReportErrors', "Failed to parse {0}: {1}.", localized, getParseErrorMessage(error.error)));
|
||||
});
|
||||
};
|
||||
const reportInvalidFormat = (localized: string | null): void => {
|
||||
this._log.error(this._absoluteFolderPath, nls.localize('jsonInvalidFormat', "Invalid format {0}: JSON object expected.", localized));
|
||||
};
|
||||
|
||||
let extension = path.extname(this._absoluteManifestPath);
|
||||
let basename = this._absoluteManifestPath.substr(0, this._absoluteManifestPath.length - extension.length);
|
||||
|
@ -118,6 +121,9 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler {
|
|||
if (errors.length > 0) {
|
||||
reportErrors(translationPath, errors);
|
||||
return { values: undefined, default: `${basename}.nls.json` };
|
||||
} else if (json.getNodeType(translationBundle) !== 'object') {
|
||||
reportInvalidFormat(translationPath);
|
||||
return { values: undefined, default: `${basename}.nls.json` };
|
||||
} else {
|
||||
let values = translationBundle.contents ? translationBundle.contents.package : undefined;
|
||||
return { values: values, default: `${basename}.nls.json` };
|
||||
|
@ -140,6 +146,9 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler {
|
|||
if (errors.length > 0) {
|
||||
reportErrors(messageBundle.localized, errors);
|
||||
return { values: undefined, default: messageBundle.original };
|
||||
} else if (json.getNodeType(messages) !== 'object') {
|
||||
reportInvalidFormat(messageBundle.localized);
|
||||
return { values: undefined, default: messageBundle.original };
|
||||
}
|
||||
return { values: messages, default: messageBundle.original };
|
||||
}, (err) => {
|
||||
|
@ -161,6 +170,9 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler {
|
|||
if (errors.length > 0) {
|
||||
reportErrors(localizedMessages.default, errors);
|
||||
return extensionDescription;
|
||||
} else if (json.getNodeType(localizedMessages) !== 'object') {
|
||||
reportInvalidFormat(localizedMessages.default);
|
||||
return extensionDescription;
|
||||
}
|
||||
const localized = localizedMessages.values || Object.create(null);
|
||||
ExtensionManifestNLSReplacer._replaceNLStrings(this._nlsConfig, extensionDescription, localized, defaults, this._log, this._absoluteFolderPath);
|
||||
|
|
|
@ -19,7 +19,7 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { parse } from 'vs/base/common/json';
|
||||
import { parse, getNodeType } from 'vs/base/common/json';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
|
@ -482,9 +482,13 @@ class UserKeyboardLayout extends Disposable {
|
|||
try {
|
||||
const content = await this.fileService.readFile(this.keyboardLayoutResource);
|
||||
const value = parse(content.value.toString());
|
||||
const layoutInfo = value.layout;
|
||||
const mappings = value.rawMapping;
|
||||
this._keyboardLayout = KeymapInfo.createKeyboardLayoutFromDebugInfo(layoutInfo, mappings, true);
|
||||
if (getNodeType(value) === 'object') {
|
||||
const layoutInfo = value.layout;
|
||||
const mappings = value.rawMapping;
|
||||
this._keyboardLayout = KeymapInfo.createKeyboardLayoutFromDebugInfo(layoutInfo, mappings, true);
|
||||
} else {
|
||||
this._keyboardLayout = null;
|
||||
}
|
||||
} catch (e) {
|
||||
this._keyboardLayout = null;
|
||||
}
|
||||
|
|
|
@ -189,8 +189,10 @@ function _loadIconThemeDocument(fileService: IFileService, location: URI): Promi
|
|||
return fileService.readFile(location).then((content) => {
|
||||
let errors: Json.ParseError[] = [];
|
||||
let contentValue = Json.parse(content.value.toString(), errors);
|
||||
if (errors.length > 0 || !contentValue) {
|
||||
if (errors.length > 0) {
|
||||
return Promise.reject(new Error(nls.localize('error.cannotparseicontheme', "Problems parsing file icons file: {0}", errors.map(e => getParseErrorMessage(e.error)).join(', '))));
|
||||
} else if (Json.getNodeType(contentValue) !== 'object') {
|
||||
return Promise.reject(new Error(nls.localize('error.invalidformat', "Invalid format for file icons theme file: Object expected.")));
|
||||
}
|
||||
return Promise.resolve(contentValue);
|
||||
});
|
||||
|
|
|
@ -302,6 +302,8 @@ function _loadColorTheme(fileService: IFileService, themeLocation: URI, resultRu
|
|||
let contentValue = Json.parse(content.value.toString(), errors);
|
||||
if (errors.length > 0) {
|
||||
return Promise.reject(new Error(nls.localize('error.cannotparsejson', "Problems parsing JSON theme file: {0}", errors.map(e => getParseErrorMessage(e.error)).join(', '))));
|
||||
} else if (Json.getNodeType(contentValue) !== 'object') {
|
||||
return Promise.reject(new Error(nls.localize('error.invalidformat', "Invalid format for JSON theme file: Object expected.")));
|
||||
}
|
||||
let includeCompletes: Promise<any> = Promise.resolve(null);
|
||||
if (contentValue.include) {
|
||||
|
|
|
@ -856,37 +856,4 @@ suite('ExtHostLanguageFeatureCommands', function () {
|
|||
assert.equal(value.length, 1);
|
||||
assert.ok(value[0].parent);
|
||||
});
|
||||
|
||||
// --- call hierarcht
|
||||
|
||||
test('Call Hierarchy, back and forth', async function () {
|
||||
|
||||
disposables.push(extHost.registerCallHierarchyProvider(nullExtensionDescription, defaultSelector, new class implements vscode.CallHierarchyItemProvider {
|
||||
prepareCallHierarchy(document: vscode.TextDocument) {
|
||||
return new types.CallHierarchyItem(types.SymbolKind.Array, 'ROOT', '', document.uri, new types.Range(0, 0, 2, 0), new types.Range(0, 0, 2, 0));
|
||||
}
|
||||
provideCallHierarchyIncomingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CallHierarchyIncomingCall[]> {
|
||||
return [
|
||||
new types.CallHierarchyIncomingCall(new types.CallHierarchyItem(types.SymbolKind.Array, 'IN', '', item.uri, new types.Range(0, 0, 2, 0), new types.Range(0, 0, 2, 0)), [new types.Range(0, 0, 0, 0)]),
|
||||
];
|
||||
}
|
||||
provideCallHierarchyOutgoingCalls(item: vscode.CallHierarchyItem, token: vscode.CancellationToken): vscode.ProviderResult<vscode.CallHierarchyOutgoingCall[]> {
|
||||
return [
|
||||
new types.CallHierarchyOutgoingCall(new types.CallHierarchyItem(types.SymbolKind.Array, 'OUT', '', item.uri, new types.Range(0, 0, 2, 0), new types.Range(0, 0, 2, 0)), [new types.Range(0, 0, 0, 0)]),
|
||||
];
|
||||
}
|
||||
}));
|
||||
|
||||
await rpcProtocol.sync();
|
||||
|
||||
// let incoming = await commands.executeCommand<vscode.CallHierarchyIncomingCall[]>('vscode.executeCallHierarchyProviderIncomingCalls', model.uri, new types.Position(0, 10));
|
||||
// assert.equal(incoming.length, 1);
|
||||
// assert.ok(incoming[0].from instanceof types.CallHierarchyItem);
|
||||
// assert.equal(incoming[0].from.name, 'IN');
|
||||
|
||||
// let outgoing = await commands.executeCommand<vscode.CallHierarchyOutgoingCall[]>('vscode.executeCallHierarchyProviderOutgoingCalls', model.uri, new types.Position(0, 10));
|
||||
// assert.equal(outgoing.length, 1);
|
||||
// assert.ok(outgoing[0].to instanceof types.CallHierarchyItem);
|
||||
// assert.equal(outgoing[0].to.name, 'OUT');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8510,10 +8510,10 @@ typescript-formatter@7.1.0:
|
|||
commandpost "^1.0.0"
|
||||
editorconfig "^0.15.0"
|
||||
|
||||
typescript@3.7.0-dev.20191017:
|
||||
version "3.7.0-dev.20191017"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.0-dev.20191017.tgz#e61440dd445edea6d7b9a699e7c5d5fbcd1906f2"
|
||||
integrity sha512-Yi0lCPEN0cn9Gp8TEEkPpgKNR5SWAmx9Hmzzz+oEuivw6amURqRGynaLyFZkMA9iMsvYG5LLqhdlFO3uu5ZT/w==
|
||||
typescript@3.7.1-rc:
|
||||
version "3.7.1-rc"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.1-rc.tgz#2054b872d67f8dc732e36c1df397f9327f37ada0"
|
||||
integrity sha512-2rMtWppLsaPvmpXsoIAXWDBQVnJMw1ITGGSnidMuayLj9iCmMRT69ncKZw/Mk5rXfJkilApKucWQZxproALoRw==
|
||||
|
||||
typescript@^2.6.2:
|
||||
version "2.6.2"
|
||||
|
|
Loading…
Reference in a new issue