mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-13 15:35:20 +01:00
merge master
This commit is contained in:
@@ -69,7 +69,6 @@ function autoFixSettingsJSON(willSaveEvent: vscode.TextDocumentWillSaveEvent): v
|
||||
|
||||
onError(error: ParseErrorCode, offset: number, length: number): void {
|
||||
if (error === ParseErrorCode.CommaExpected && lastEndOfSomething > -1) {
|
||||
|
||||
const fixPosition = document.positionAt(lastEndOfSomething);
|
||||
edit.insert(document.uri, fixPosition, ',');
|
||||
}
|
||||
@@ -104,31 +103,6 @@ function registerSettingsCompletions(): vscode.Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
function provideContributedLocalesProposals(range: vscode.Range): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
|
||||
const contributedLocales: string[] = [];
|
||||
for (const extension of vscode.extensions.all) {
|
||||
if (extension.packageJSON && extension.packageJSON['contributes'] && extension.packageJSON['contributes']['localizations'] && extension.packageJSON['contributes']['localizations'].length) {
|
||||
const localizations: { languageId: string }[] = extension.packageJSON['contributes']['localizations'];
|
||||
for (const localization of localizations) {
|
||||
if (contributedLocales.indexOf(localization.languageId) === -1) {
|
||||
contributedLocales.push(localization.languageId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return contributedLocales.map(locale => {
|
||||
const text = `"${locale}"`;
|
||||
const item = new vscode.CompletionItem(text);
|
||||
item.kind = vscode.CompletionItemKind.Value;
|
||||
item.insertText = text;
|
||||
item.range = range;
|
||||
item.filterText = text;
|
||||
return item;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
interface IExtensionsContent {
|
||||
recommendations: string[];
|
||||
}
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
"lib": [
|
||||
"es2015"
|
||||
],
|
||||
"strict": true
|
||||
"strict": true,
|
||||
"noUnusedLocals": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -715,7 +715,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-languageclient": "^4.0.0-next.9",
|
||||
"vscode-languageclient": "4.0.0-next.9",
|
||||
"vscode-nls": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"dependencies": {
|
||||
"vscode-css-languageservice": "^3.0.6",
|
||||
"vscode-emmet-helper": "^1.1.34",
|
||||
"vscode-languageserver": "^4.0.0-next.4"
|
||||
"vscode-languageserver": "4.0.0-next.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "2.2.33",
|
||||
|
||||
@@ -48,7 +48,7 @@ vscode-languageserver-types@^3.6.0-next.1:
|
||||
version "3.6.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.6.0-next.1.tgz#98e488d3f87b666b4ee1a3d89f0023e246d358f3"
|
||||
|
||||
vscode-languageserver@^4.0.0-next.4:
|
||||
vscode-languageserver@4.0.0-next.4:
|
||||
version "4.0.0-next.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-4.0.0-next.4.tgz#162440b15bedaab07e1676f046e4d9b8578b3d92"
|
||||
dependencies:
|
||||
|
||||
@@ -10,7 +10,7 @@ vscode-jsonrpc@^3.6.0-next.1:
|
||||
version "3.6.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.6.0-next.1.tgz#3cb463dffe5842d6aec16718ca9252708cd6aabe"
|
||||
|
||||
vscode-languageclient@^4.0.0-next.9:
|
||||
vscode-languageclient@4.0.0-next.9:
|
||||
version "4.0.0-next.9"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-4.0.0-next.9.tgz#2a06568f46ee9de3490f85e227d3740a21a03d3a"
|
||||
dependencies:
|
||||
|
||||
@@ -1051,14 +1051,6 @@ export class CommandCenter {
|
||||
value = (await repository.getCommit(repository.HEAD.commit)).message;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
const getPreviousCommitMessage = async () => {
|
||||
//Only return the previous commit message if it's an amend commit and the repo already has a commit
|
||||
if (opts && opts.amend && repository.HEAD && repository.HEAD.commit) {
|
||||
return (await repository.getCommit('HEAD')).message;
|
||||
}
|
||||
};
|
||||
|
||||
return await window.showInputBox({
|
||||
value,
|
||||
placeHolder: localize('commit message', "Commit message"),
|
||||
|
||||
@@ -78,8 +78,7 @@ function _throttle<T>(fn: Function, key: string): Function {
|
||||
|
||||
export const throttle = decorate(_throttle);
|
||||
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
function _sequentialize<T>(fn: Function, key: string): Function {
|
||||
function _sequentialize(fn: Function, key: string): Function {
|
||||
const currentKey = `__$sequence$${key}`;
|
||||
|
||||
return function (this: any, ...args: any[]) {
|
||||
|
||||
@@ -362,8 +362,6 @@ function getGitErrorCode(stderr: string): string | undefined {
|
||||
export class Git {
|
||||
|
||||
private gitPath: string;
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
private version: string;
|
||||
private env: any;
|
||||
|
||||
private _onOutput = new EventEmitter();
|
||||
@@ -371,7 +369,6 @@ export class Git {
|
||||
|
||||
constructor(options: IGitOptions) {
|
||||
this.gitPath = options.gitPath;
|
||||
this.version = options.version;
|
||||
this.env = options.env || {};
|
||||
}
|
||||
|
||||
|
||||
@@ -398,8 +398,7 @@ class ProgressManager {
|
||||
|
||||
private disposable: IDisposable = EmptyDisposable;
|
||||
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
constructor(private repository: Repository) {
|
||||
constructor(repository: Repository) {
|
||||
const start = onceEvent(filterEvent(repository.onDidChangeOperations, () => repository.operations.shouldShowProgress()));
|
||||
const end = onceEvent(filterEvent(debounceEvent(repository.onDidChangeOperations, 300), () => !repository.operations.shouldShowProgress()));
|
||||
|
||||
@@ -791,9 +790,8 @@ export class Repository implements Disposable {
|
||||
async buffer(ref: string, filePath: string): Promise<Buffer> {
|
||||
return await this.run(Operation.Show, async () => {
|
||||
const relativePath = path.relative(this.repository.root, filePath).replace(/\\/g, '/');
|
||||
const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
const encoding = configFiles.get<string>('encoding');
|
||||
// const configFiles = workspace.getConfiguration('files', Uri.file(filePath));
|
||||
// const encoding = configFiles.get<string>('encoding');
|
||||
|
||||
// TODO@joao: REsource config api
|
||||
return await this.repository.buffer(`${ref}:${relativePath}`);
|
||||
@@ -1011,11 +1009,8 @@ export class Repository implements Disposable {
|
||||
case 'UU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_MODIFIED, useIcons));
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
let isModifiedInIndex = false;
|
||||
|
||||
switch (raw.x) {
|
||||
case 'M': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); isModifiedInIndex = true; break;
|
||||
case 'M': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); break;
|
||||
case 'A': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_ADDED, useIcons)); break;
|
||||
case 'D': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_DELETED, useIcons)); break;
|
||||
case 'R': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_RENAMED, useIcons, renameUri)); break;
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"strict": true,
|
||||
"experimentalDecorators": true
|
||||
"experimentalDecorators": true,
|
||||
"noUnusedLocals": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
|
||||
@@ -229,7 +229,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-extension-telemetry": "0.0.13",
|
||||
"vscode-languageclient": "^4.0.0-next.9",
|
||||
"vscode-languageclient": "4.0.0-next.9",
|
||||
"vscode-nls": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"vscode-css-languageservice": "^3.0.6",
|
||||
"vscode-emmet-helper": "^1.1.34",
|
||||
"vscode-html-languageservice": "^2.0.16",
|
||||
"vscode-languageserver": "^4.0.0-next.4",
|
||||
"vscode-languageserver": "4.0.0-next.4",
|
||||
"vscode-languageserver-types": "^3.6.0-next.1",
|
||||
"vscode-nls": "^3.2.1",
|
||||
"vscode-uri": "^1.0.1"
|
||||
|
||||
@@ -56,7 +56,7 @@ vscode-languageserver-types@^3.6.0-next.1:
|
||||
version "3.6.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.6.0-next.1.tgz#98e488d3f87b666b4ee1a3d89f0023e246d358f3"
|
||||
|
||||
vscode-languageserver@^4.0.0-next.4:
|
||||
vscode-languageserver@4.0.0-next.4:
|
||||
version "4.0.0-next.4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-4.0.0-next.4.tgz#162440b15bedaab07e1676f046e4d9b8578b3d92"
|
||||
dependencies:
|
||||
|
||||
@@ -38,7 +38,7 @@ vscode-jsonrpc@^3.6.0-next.1:
|
||||
version "3.6.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.6.0-next.1.tgz#3cb463dffe5842d6aec16718ca9252708cd6aabe"
|
||||
|
||||
vscode-languageclient@^4.0.0-next.9:
|
||||
vscode-languageclient@4.0.0-next.9:
|
||||
version "4.0.0-next.9"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-4.0.0-next.9.tgz#2a06568f46ee9de3490f85e227d3740a21a03d3a"
|
||||
dependencies:
|
||||
|
||||
@@ -8,8 +8,8 @@ import * as path from 'path';
|
||||
import * as nls from 'vscode-nls';
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
import { workspace, languages, ExtensionContext, extensions, Uri, LanguageConfiguration } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification } from 'vscode-languageclient';
|
||||
import { workspace, languages, ExtensionContext, extensions, Uri, LanguageConfiguration, TextDocument, FoldingRangeList as VSFoldingRangeList, FoldingRange as VSFoldingRange } from 'vscode';
|
||||
import { LanguageClient, LanguageClientOptions, RequestType, ServerOptions, TransportKind, NotificationType, DidChangeConfigurationNotification, TextDocumentIdentifier } from 'vscode-languageclient';
|
||||
import TelemetryReporter from 'vscode-extension-telemetry';
|
||||
|
||||
import { hash } from './utils/hash';
|
||||
@@ -30,6 +30,57 @@ namespace SchemaAssociationNotification {
|
||||
export const type: NotificationType<ISchemaAssociations, any> = new NotificationType('json/schemaAssociations');
|
||||
}
|
||||
|
||||
interface FoldingRangeList {
|
||||
/**
|
||||
* The folding ranges.
|
||||
*/
|
||||
ranges: FoldingRange[];
|
||||
}
|
||||
|
||||
export enum FoldingRangeType {
|
||||
/**
|
||||
* Folding range for a comment
|
||||
*/
|
||||
Comment = 'comment',
|
||||
/**
|
||||
* Folding range for a imports or includes
|
||||
*/
|
||||
Imports = 'imports',
|
||||
/**
|
||||
* Folding range for a region (e.g. `#region`)
|
||||
*/
|
||||
Region = 'region'
|
||||
}
|
||||
|
||||
interface FoldingRange {
|
||||
|
||||
/**
|
||||
* The start line number
|
||||
*/
|
||||
startLine: number;
|
||||
|
||||
/**
|
||||
* The end line number
|
||||
*/
|
||||
endLine: number;
|
||||
|
||||
/**
|
||||
* The actual color value for this color range.
|
||||
*/
|
||||
type?: FoldingRangeType;
|
||||
}
|
||||
|
||||
interface FoldingRangeRequest {
|
||||
/**
|
||||
* The text document.
|
||||
*/
|
||||
textDocument: TextDocumentIdentifier;
|
||||
}
|
||||
|
||||
namespace FoldingRangesRequest {
|
||||
export const type: RequestType<FoldingRangeRequest, FoldingRangeList | null, any, any> = new RequestType('textDocument/foldingRanges');
|
||||
}
|
||||
|
||||
interface IPackageInfo {
|
||||
name: string;
|
||||
version: string;
|
||||
@@ -124,6 +175,17 @@ export function activate(context: ExtensionContext) {
|
||||
toDispose.push(workspace.onDidCloseTextDocument(d => handleContentChange(d.uri)));
|
||||
|
||||
client.sendNotification(SchemaAssociationNotification.type, getSchemaAssociation(context));
|
||||
|
||||
languages.registerFoldingProvider(documentSelector, {
|
||||
provideFoldingRanges(document: TextDocument) {
|
||||
return client.sendRequest(FoldingRangesRequest.type, { textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(document) }).then(res => {
|
||||
if (res && Array.isArray(res.ranges)) {
|
||||
return new VSFoldingRangeList(res.ranges.map(r => new VSFoldingRange(r.startLine, r.endLine, r.type)));
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let languageConfiguration: LanguageConfiguration = {
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"vscode-extension-telemetry": "0.0.13",
|
||||
"vscode-languageclient": "^4.0.0-next.9",
|
||||
"vscode-languageclient": "4.0.0-next.9",
|
||||
"vscode-nls": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"jsonc-parser": "^1.0.1",
|
||||
"request-light": "^0.2.2",
|
||||
"vscode-json-languageservice": "^3.0.7",
|
||||
"vscode-languageserver": "^4.0.0-next.3",
|
||||
"vscode-languageserver": "4.0.0-next.3",
|
||||
"vscode-nls": "^3.2.1",
|
||||
"vscode-uri": "^1.0.1"
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import {
|
||||
createConnection, IConnection,
|
||||
TextDocuments, TextDocument, InitializeParams, InitializeResult, NotificationType, RequestType,
|
||||
DocumentRangeFormattingRequest, Disposable, ServerCapabilities
|
||||
DocumentRangeFormattingRequest, Disposable, ServerCapabilities, TextDocumentIdentifier
|
||||
} from 'vscode-languageserver';
|
||||
|
||||
import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities, ColorPresentationRequest } from 'vscode-languageserver-protocol/lib/protocol.colorProvider.proposed';
|
||||
@@ -20,6 +20,7 @@ import Strings = require('./utils/strings');
|
||||
import { formatError, runSafe, runSafeAsync } from './utils/errors';
|
||||
import { JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration } from 'vscode-json-languageservice';
|
||||
import { getLanguageModelCache } from './languageModelCache';
|
||||
import { createScanner, SyntaxKind } from 'jsonc-parser';
|
||||
|
||||
interface ISchemaAssociations {
|
||||
[pattern: string]: string[];
|
||||
@@ -37,6 +38,57 @@ namespace SchemaContentChangeNotification {
|
||||
export const type: NotificationType<string, any> = new NotificationType('json/schemaContent');
|
||||
}
|
||||
|
||||
interface FoldingRangeList {
|
||||
/**
|
||||
* The folding ranges.
|
||||
*/
|
||||
ranges: FoldingRange[];
|
||||
}
|
||||
|
||||
export enum FoldingRangeType {
|
||||
/**
|
||||
* Folding range for a comment
|
||||
*/
|
||||
Comment = 'comment',
|
||||
/**
|
||||
* Folding range for a imports or includes
|
||||
*/
|
||||
Imports = 'imports',
|
||||
/**
|
||||
* Folding range for a region (e.g. `#region`)
|
||||
*/
|
||||
Region = 'region'
|
||||
}
|
||||
|
||||
interface FoldingRange {
|
||||
|
||||
/**
|
||||
* The start line number
|
||||
*/
|
||||
startLine: number;
|
||||
|
||||
/**
|
||||
* The end line number
|
||||
*/
|
||||
endLine: number;
|
||||
|
||||
/**
|
||||
* The actual color value for this color range.
|
||||
*/
|
||||
type?: FoldingRangeType | string;
|
||||
}
|
||||
|
||||
interface FoldingRangeRequest {
|
||||
/**
|
||||
* The text document.
|
||||
*/
|
||||
textDocument: TextDocumentIdentifier;
|
||||
}
|
||||
|
||||
namespace FoldingRangesRequest {
|
||||
export const type: RequestType<FoldingRangeRequest, FoldingRangeList | null, any, any> = new RequestType('textDocument/foldingRanges');
|
||||
}
|
||||
|
||||
// Create a connection for the server
|
||||
let connection: IConnection = createConnection();
|
||||
|
||||
@@ -347,7 +399,83 @@ connection.onRequest(ColorPresentationRequest.type, params => {
|
||||
return languageService.getColorPresentations(document, jsonDocument, params.color, params.range);
|
||||
}
|
||||
return [];
|
||||
}, [], `Error while computing color presentationsd for ${params.textDocument.uri}`);
|
||||
}, [], `Error while computing color presentations for ${params.textDocument.uri}`);
|
||||
});
|
||||
|
||||
connection.onRequest(FoldingRangesRequest.type, params => {
|
||||
return runSafe(() => {
|
||||
let document = documents.get(params.textDocument.uri);
|
||||
if (document) {
|
||||
let ranges: FoldingRange[] = [];
|
||||
let stack: FoldingRange[] = [];
|
||||
let prevStart = -1;
|
||||
let scanner = createScanner(document.getText(), false);
|
||||
let token = scanner.scan();
|
||||
while (token !== SyntaxKind.EOF) {
|
||||
switch (token) {
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
case SyntaxKind.OpenBracketToken: {
|
||||
let startLine = document.positionAt(scanner.getTokenOffset()).line;
|
||||
let range = { startLine, endLine: startLine, type: token === SyntaxKind.OpenBraceToken ? 'object' : 'array' };
|
||||
stack.push(range);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.CloseBraceToken:
|
||||
case SyntaxKind.CloseBracketToken: {
|
||||
let type = token === SyntaxKind.CloseBraceToken ? 'object' : 'array';
|
||||
if (stack.length > 0 && stack[stack.length - 1].type === type) {
|
||||
let range = stack.pop();
|
||||
let line = document.positionAt(scanner.getTokenOffset()).line;
|
||||
if (range && line > range.startLine + 1 && prevStart !== range.startLine) {
|
||||
range.endLine = line - 1;
|
||||
ranges.push(range);
|
||||
prevStart = range.startLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.BlockCommentTrivia: {
|
||||
let startLine = document.positionAt(scanner.getTokenOffset()).line;
|
||||
let endLine = document.positionAt(scanner.getTokenOffset() + scanner.getTokenLength()).line;
|
||||
if (startLine < endLine) {
|
||||
ranges.push({ startLine, endLine, type: FoldingRangeType.Comment });
|
||||
prevStart = startLine;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.LineCommentTrivia: {
|
||||
let text = document.getText().substr(scanner.getTokenOffset(), scanner.getTokenLength());
|
||||
let m = text.match(/^\/\/\s*#(region\b)|(endregion\b)/);
|
||||
if (m) {
|
||||
let line = document.positionAt(scanner.getTokenOffset()).line;
|
||||
if (m[1]) { // start pattern match
|
||||
let range = { startLine: line, endLine: line, type: FoldingRangeType.Region };
|
||||
stack.push(range);
|
||||
} else {
|
||||
let i = stack.length - 1;
|
||||
while (i >= 0 && stack[i].type !== FoldingRangeType.Region) {
|
||||
i--;
|
||||
}
|
||||
if (i >= 0) {
|
||||
let range = stack[i];
|
||||
stack.length = i;
|
||||
if (line > range.startLine && prevStart !== range.startLine) {
|
||||
range.endLine = line;
|
||||
ranges.push(range);
|
||||
prevStart = range.startLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
token = scanner.scan();
|
||||
}
|
||||
return <FoldingRangeList>{ ranges };
|
||||
}
|
||||
return null;
|
||||
}, null, `Error while computing folding ranges for ${params.textDocument.uri}`);
|
||||
});
|
||||
|
||||
// Listen on the connection
|
||||
|
||||
@@ -88,7 +88,7 @@ vscode-languageserver-types@^3.6.0-next.1:
|
||||
version "3.6.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.6.0-next.1.tgz#98e488d3f87b666b4ee1a3d89f0023e246d358f3"
|
||||
|
||||
vscode-languageserver@^4.0.0-next.3:
|
||||
vscode-languageserver@4.0.0-next.3:
|
||||
version "4.0.0-next.3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-4.0.0-next.3.tgz#89a9ce5078e3a86a78e3551c3766194ce4295611"
|
||||
dependencies:
|
||||
|
||||
@@ -38,7 +38,7 @@ vscode-jsonrpc@^3.6.0-next.1:
|
||||
version "3.6.0-next.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.6.0-next.1.tgz#3cb463dffe5842d6aec16718ca9252708cd6aabe"
|
||||
|
||||
vscode-languageclient@^4.0.0-next.9:
|
||||
vscode-languageclient@4.0.0-next.9:
|
||||
version "4.0.0-next.9"
|
||||
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-4.0.0-next.9.tgz#2a06568f46ee9de3490f85e227d3740a21a03d3a"
|
||||
dependencies:
|
||||
|
||||
@@ -24,11 +24,6 @@
|
||||
}
|
||||
],
|
||||
"grammars": [
|
||||
{
|
||||
"language": "Log",
|
||||
"scopeName": "text.log",
|
||||
"path": "./syntaxes/log.tmLanguage.json"
|
||||
},
|
||||
{
|
||||
"language": "log",
|
||||
"scopeName": "text.log",
|
||||
|
||||
@@ -27,10 +27,9 @@
|
||||
if (!unloadedStyles.length) {
|
||||
return;
|
||||
}
|
||||
const args = [unloadedStyles];
|
||||
window.parent.postMessage({
|
||||
command: 'did-click-link',
|
||||
data: `command:_markdown.onPreviewStyleLoadError?${encodeURIComponent(JSON.stringify(args))}`
|
||||
command: '_markdown.onPreviewStyleLoadError',
|
||||
args: [unloadedStyles]
|
||||
}, '*');
|
||||
});
|
||||
}());
|
||||
@@ -354,7 +354,10 @@ export class MarkdownPreviewWebviewManager {
|
||||
const view = vscode.window.createWebview(
|
||||
localize('previewTitle', 'Preview {0}', path.basename(resource.fsPath)),
|
||||
viewColumn,
|
||||
{ enableScripts: true });
|
||||
{
|
||||
enableScripts: true,
|
||||
localResourceRoots: this.getLocalResourceRoots(resource)
|
||||
});
|
||||
|
||||
this.contentProvider.provideTextDocumentContent(resource, this.previewConfigurations).then(x => view.html = x);
|
||||
|
||||
@@ -373,4 +376,19 @@ export class MarkdownPreviewWebviewManager {
|
||||
this.webviews.set(resource.fsPath, view);
|
||||
return view;
|
||||
}
|
||||
|
||||
private getLocalResourceRoots(
|
||||
resource: vscode.Uri
|
||||
): vscode.Uri[] {
|
||||
const folder = vscode.workspace.getWorkspaceFolder(resource);
|
||||
if (folder) {
|
||||
return [folder.uri];
|
||||
}
|
||||
|
||||
if (!resource.scheme || resource.scheme === 'file') {
|
||||
return [vscode.Uri.parse(path.dirname(resource.fsPath))];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
//tslint:disable
|
||||
'use strict';
|
||||
|
||||
import * as path from 'path';
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@
|
||||
"vscode-debugprotocol": "1.25.0",
|
||||
"vscode-ripgrep": "^0.7.1-patch.1.5",
|
||||
"vscode-textmate": "^3.2.0",
|
||||
"vscode-xterm": "3.2.0-beta3",
|
||||
"vscode-xterm": "3.2.0-beta4",
|
||||
"yauzl": "2.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -120,6 +120,11 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
this.scrollableElement.onScroll(this.onScroll, this, this.disposables);
|
||||
domEvent(this.rowsContainer, TouchEventType.Change)(this.onTouchChange, this, this.disposables);
|
||||
|
||||
// Prevent the monaco-scrollable-element from scrolling
|
||||
// https://github.com/Microsoft/vscode/issues/44181
|
||||
domEvent(this.scrollableElement.getDomNode(), 'scroll')
|
||||
(e => (e.target as HTMLElement).scrollTop = 0, null, this.disposables);
|
||||
|
||||
const onDragOver = mapEvent(domEvent(this.rowsContainer, 'dragover'), e => new DragMouseEvent(e));
|
||||
onDragOver(this.onDragOver, this, this.disposables);
|
||||
|
||||
@@ -150,7 +155,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
const removeRange = intersect(previousRenderRange, deleteRange);
|
||||
|
||||
for (let i = removeRange.start; i < removeRange.end; i++) {
|
||||
this.removeItemFromDOM(this.items[i]);
|
||||
this.removeItemFromDOM(i);
|
||||
}
|
||||
|
||||
const previousRestRange: IRange = { start: start + deleteCount, end: this.items.length };
|
||||
@@ -183,19 +188,20 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
const removeRange = removeRanges[r];
|
||||
|
||||
for (let i = removeRange.start; i < removeRange.end; i++) {
|
||||
this.removeItemFromDOM(this.items[i]);
|
||||
this.removeItemFromDOM(i);
|
||||
}
|
||||
}
|
||||
|
||||
const unrenderedRestRanges = previousUnrenderedRestRanges.map(r => shift(r, delta));
|
||||
const elementsRange = { start, end: start + elements.length };
|
||||
const insertRanges = [elementsRange, ...unrenderedRestRanges].map(r => intersect(renderRange, r));
|
||||
const beforeElement = this.getNextToLastElement(insertRanges);
|
||||
|
||||
for (let r = 0; r < insertRanges.length; r++) {
|
||||
const insertRange = insertRanges[r];
|
||||
|
||||
for (let i = insertRange.start; i < insertRange.end; i++) {
|
||||
this.insertItemInDOM(this.items[i], i);
|
||||
this.insertItemInDOM(i, beforeElement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,16 +260,17 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
const rangesToInsert = relativeComplement(renderRange, previousRenderRange);
|
||||
const rangesToRemove = relativeComplement(previousRenderRange, renderRange);
|
||||
const beforeElement = this.getNextToLastElement(rangesToInsert);
|
||||
|
||||
for (const range of rangesToInsert) {
|
||||
for (let i = range.start; i < range.end; i++) {
|
||||
this.insertItemInDOM(this.items[i], i);
|
||||
this.insertItemInDOM(i, beforeElement);
|
||||
}
|
||||
}
|
||||
|
||||
for (const range of rangesToRemove) {
|
||||
for (let i = range.start; i < range.end; i++) {
|
||||
this.removeItemFromDOM(this.items[i], );
|
||||
this.removeItemFromDOM(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,28 +288,38 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
// DOM operations
|
||||
|
||||
private insertItemInDOM(item: IItem<T>, index: number): void {
|
||||
private insertItemInDOM(index: number, beforeElement: HTMLElement | null): void {
|
||||
const item = this.items[index];
|
||||
|
||||
if (!item.row) {
|
||||
item.row = this.cache.alloc(item.templateId);
|
||||
}
|
||||
|
||||
if (!item.row.domNode.parentElement) {
|
||||
this.rowsContainer.appendChild(item.row.domNode);
|
||||
if (beforeElement) {
|
||||
this.rowsContainer.insertBefore(item.row.domNode, beforeElement);
|
||||
} else {
|
||||
this.rowsContainer.appendChild(item.row.domNode);
|
||||
}
|
||||
}
|
||||
|
||||
const renderer = this.renderers.get(item.templateId);
|
||||
item.row.domNode.style.top = `${this.elementTop(index)}px`;
|
||||
item.row.domNode.style.height = `${item.size}px`;
|
||||
item.row.domNode.setAttribute('data-index', `${index}`);
|
||||
this.updateItemInDOM(item, index);
|
||||
|
||||
const renderer = this.renderers.get(item.templateId);
|
||||
renderer.renderElement(item.element, index, item.row.templateData);
|
||||
}
|
||||
|
||||
private updateItemInDOM(item: IItem<T>, index: number): void {
|
||||
item.row.domNode.style.top = `${this.elementTop(index)}px`;
|
||||
item.row.domNode.setAttribute('data-index', `${index}`);
|
||||
item.row.domNode.setAttribute('data-last-element', index === this.length - 1 ? 'true' : 'false');
|
||||
item.row.domNode.setAttribute('aria-setsize', `${this.length}`);
|
||||
item.row.domNode.setAttribute('aria-posinset', `${index + 1}`);
|
||||
}
|
||||
|
||||
private removeItemFromDOM(item: IItem<T>): void {
|
||||
private removeItemFromDOM(index: number): void {
|
||||
const item = this.items[index];
|
||||
this.cache.release(item.row);
|
||||
item.row = null;
|
||||
}
|
||||
@@ -450,6 +467,26 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
};
|
||||
}
|
||||
|
||||
private getNextToLastElement(ranges: IRange[]): HTMLElement | null {
|
||||
const lastRange = ranges[ranges.length - 1];
|
||||
|
||||
if (!lastRange) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const nextToLastItem = this.items[lastRange.end];
|
||||
|
||||
if (!nextToLastItem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!nextToLastItem.row) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return nextToLastItem.row.domNode;
|
||||
}
|
||||
|
||||
// Dispose
|
||||
|
||||
dispose() {
|
||||
|
||||
@@ -21,6 +21,7 @@ import { Color } from 'vs/base/common/color';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { clamp } from 'vs/base/common/numbers';
|
||||
|
||||
export interface IIdentityProvider<T> {
|
||||
(element: T): string;
|
||||
@@ -203,32 +204,6 @@ class FocusTrait<T> extends Trait<T> {
|
||||
}
|
||||
}
|
||||
|
||||
class Aria<T> implements IRenderer<T, HTMLElement>, ISpliceable<T> {
|
||||
|
||||
private length = 0;
|
||||
|
||||
get templateId(): string {
|
||||
return 'aria';
|
||||
}
|
||||
|
||||
splice(start: number, deleteCount: number, elements: T[]): void {
|
||||
this.length += elements.length - deleteCount;
|
||||
}
|
||||
|
||||
renderTemplate(container: HTMLElement): HTMLElement {
|
||||
return container;
|
||||
}
|
||||
|
||||
renderElement(element: T, index: number, container: HTMLElement): void {
|
||||
container.setAttribute('aria-setsize', `${this.length}`);
|
||||
container.setAttribute('aria-posinset', `${index + 1}`);
|
||||
}
|
||||
|
||||
disposeTemplate(container: HTMLElement): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The TraitSpliceable is used as a util class to be able
|
||||
* to preserve traits across splice calls, given an identity
|
||||
@@ -781,13 +756,12 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
renderers: IRenderer<T, any>[],
|
||||
options: IListOptions<T> = DefaultOptions
|
||||
) {
|
||||
const aria = new Aria();
|
||||
this.focus = new FocusTrait(i => this.getElementDomId(i));
|
||||
this.selection = new Trait('selected');
|
||||
|
||||
mixin(options, defaultStyles, false);
|
||||
|
||||
renderers = renderers.map(r => new PipelineRenderer(r.templateId, [aria, this.focus.renderer, this.selection.renderer, r]));
|
||||
renderers = renderers.map(r => new PipelineRenderer(r.templateId, [this.focus.renderer, this.selection.renderer, r]));
|
||||
|
||||
this.view = new ListView(container, delegate, renderers, options);
|
||||
this.view.domNode.setAttribute('role', 'tree');
|
||||
@@ -797,7 +771,6 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
this.styleElement = DOM.createStyleSheet(this.view.domNode);
|
||||
|
||||
this.spliceable = new CombinedSpliceable([
|
||||
aria,
|
||||
new TraitSpliceable(this.focus, this.view, options.identityProvider),
|
||||
new TraitSpliceable(this.selection, this.view, options.identityProvider),
|
||||
this.view
|
||||
@@ -980,12 +953,9 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
const elementHeight = this.view.elementHeight(index);
|
||||
|
||||
if (isNumber(relativeTop)) {
|
||||
relativeTop = relativeTop < 0 ? 0 : relativeTop;
|
||||
relativeTop = relativeTop > 1 ? 1 : relativeTop;
|
||||
|
||||
// y = mx + b
|
||||
const m = elementHeight - this.view.renderHeight;
|
||||
this.view.setScrollTop(m * relativeTop + elementTop);
|
||||
this.view.setScrollTop(m * clamp(relativeTop, 0, 1) + elementTop);
|
||||
} else {
|
||||
const viewItemBottom = elementTop + elementHeight;
|
||||
const wrapperBottom = scrollTop + this.view.renderHeight;
|
||||
@@ -998,6 +968,24 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the relative position of an element rendered in the list.
|
||||
* Returns `null` if the element isn't *entirely* in the visible viewport.
|
||||
*/
|
||||
getRelativeTop(index: number): number | null {
|
||||
const scrollTop = this.view.getScrollTop();
|
||||
const elementTop = this.view.elementTop(index);
|
||||
const elementHeight = this.view.elementHeight(index);
|
||||
|
||||
if (elementTop < scrollTop || elementTop + elementHeight > scrollTop + this.view.renderHeight) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// y = mx + b
|
||||
const m = elementHeight - this.view.renderHeight;
|
||||
return Math.abs((scrollTop - elementTop) / m);
|
||||
}
|
||||
|
||||
private getElementDomId(index: number): string {
|
||||
return `${this.idPrefix}_${index}`;
|
||||
}
|
||||
@@ -1097,6 +1085,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
if (focus.length > 0) {
|
||||
this.view.domNode.setAttribute('aria-activedescendant', this.getElementDomId(focus[0]));
|
||||
console.log(this.getRelativeTop(focus[0]));
|
||||
} else {
|
||||
this.view.domNode.removeAttribute('aria-activedescendant');
|
||||
}
|
||||
|
||||
@@ -49,6 +49,10 @@ export abstract class Panel implements IView {
|
||||
private _onDidChange = new Emitter<number | undefined>();
|
||||
readonly onDidChange: Event<number | undefined> = this._onDidChange.event;
|
||||
|
||||
get element(): HTMLElement {
|
||||
return this.el;
|
||||
}
|
||||
|
||||
get draggableElement(): HTMLElement {
|
||||
return this.header;
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ export class Delayer<T> {
|
||||
private timeout: number;
|
||||
private completionPromise: Promise;
|
||||
private onSuccess: ValueCallback;
|
||||
private task: ITask<T>;
|
||||
private task: ITask<T | TPromise<T>>;
|
||||
|
||||
constructor(public defaultDelay: number) {
|
||||
this.timeout = null;
|
||||
@@ -189,7 +189,7 @@ export class Delayer<T> {
|
||||
this.task = null;
|
||||
}
|
||||
|
||||
trigger(task: ITask<T>, delay: number = this.defaultDelay): TPromise<T> {
|
||||
trigger(task: ITask<T | TPromise<T>>, delay: number = this.defaultDelay): TPromise<T> {
|
||||
this.task = task;
|
||||
this.cancelTimeout();
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import strings = require('vs/base/common/strings');
|
||||
import extfs = require('vs/base/node/extfs');
|
||||
import { onError } from 'vs/base/test/common/utils';
|
||||
import { Readable } from 'stream';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { isLinux, isWindows } from 'vs/base/common/platform';
|
||||
|
||||
const ignore = () => { };
|
||||
|
||||
@@ -75,6 +75,11 @@ suite('Extfs', () => {
|
||||
});
|
||||
|
||||
test('stat link', function (done: () => void) {
|
||||
if (isWindows) {
|
||||
// Symlinks are not the same on win, and we can not create them programitically without admin privileges
|
||||
return done();
|
||||
}
|
||||
|
||||
const id1 = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id1);
|
||||
const directory = path.join(parentDir, 'extfs', id1);
|
||||
|
||||
@@ -356,8 +356,7 @@ export class IssueReporter extends Disposable {
|
||||
|
||||
const disableExtensions = document.getElementById('disableExtensions');
|
||||
disableExtensions.addEventListener('click', () => {
|
||||
ipcRenderer.send('workbenchCommand', 'workbench.extensions.action.disableAll');
|
||||
ipcRenderer.send('workbenchCommand', 'workbench.action.reloadWindow');
|
||||
ipcRenderer.send('workbenchCommand', 'workbench.action.reloadWindowWithExtensionsDisabled');
|
||||
});
|
||||
|
||||
disableExtensions.addEventListener('keydown', (e) => {
|
||||
|
||||
@@ -262,6 +262,7 @@ input:disabled {
|
||||
.workbenchCommand {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.workbenchCommand:disabled {
|
||||
color: #868e96;
|
||||
cursor: default
|
||||
|
||||
@@ -555,6 +555,10 @@ export class CodeWindow implements ICodeWindow {
|
||||
configuration['extensions-dir'] = cli['extensions-dir'];
|
||||
}
|
||||
|
||||
if (cli) {
|
||||
configuration['disable-extensions'] = cli['disable-extensions'];
|
||||
}
|
||||
|
||||
configuration.isInitialStartup = false; // since this is a reload
|
||||
|
||||
// Load config
|
||||
|
||||
@@ -826,6 +826,67 @@ export interface DocumentColorProvider {
|
||||
provideColorPresentations(model: model.ITextModel, colorInfo: IColorInformation, token: CancellationToken): IColorPresentation[] | Thenable<IColorPresentation[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A provider of colors for editor models.
|
||||
*/
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface FoldingProvider {
|
||||
/**
|
||||
* Provides the color ranges for a specific model.
|
||||
*/
|
||||
provideFoldingRanges(model: model.ITextModel, token: CancellationToken): IFoldingRangeList | Thenable<IFoldingRangeList>;
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface IFoldingRangeList {
|
||||
|
||||
ranges: IFoldingRange[];
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface IFoldingRange {
|
||||
|
||||
/**
|
||||
* The start line number
|
||||
*/
|
||||
startLineNumber: number;
|
||||
|
||||
/**
|
||||
* The end line number
|
||||
*/
|
||||
endLineNumber: number;
|
||||
|
||||
/**
|
||||
* The optional type of the folding range
|
||||
*/
|
||||
type?: FoldingRangeType | string;
|
||||
|
||||
// auto-collapse
|
||||
// header span
|
||||
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export enum FoldingRangeType {
|
||||
/**
|
||||
* Folding range for a comment
|
||||
*/
|
||||
Comment = 'comment',
|
||||
/**
|
||||
* Folding range for a imports or includes
|
||||
*/
|
||||
Imports = 'imports',
|
||||
/**
|
||||
* Folding range for a region (e.g. `#region`)
|
||||
*/
|
||||
Region = 'region'
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@@ -971,6 +1032,11 @@ export const LinkProviderRegistry = new LanguageFeatureRegistry<LinkProvider>();
|
||||
*/
|
||||
export const ColorProviderRegistry = new LanguageFeatureRegistry<DocumentColorProvider>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const FoldingProviderRegistry = new LanguageFeatureRegistry<FoldingProvider>();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
||||
@@ -19,17 +19,24 @@ import { registerEditorAction, registerEditorContribution, ServicesAccessor, Edi
|
||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { FoldingDecorationProvider } from './foldingDecorations';
|
||||
import { FoldingRegions } from './foldingRanges';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
|
||||
import { IMarginData, IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget';
|
||||
import { HiddenRangeModel } from 'vs/editor/contrib/folding/hiddenRangeModel';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { computeRanges as computeIndentRanges } from 'vs/editor/contrib/folding/indentRangeProvider';
|
||||
import { IndentRangeProvider } from 'vs/editor/contrib/folding/indentRangeProvider';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { FoldingProviderRegistry } from 'vs/editor/common/modes';
|
||||
import { SyntaxRangeProvider } from './syntaxRangeProvider';
|
||||
|
||||
export const ID = 'editor.contrib.folding';
|
||||
|
||||
export interface RangeProvider {
|
||||
compute(editorModel: ITextModel): TPromise<FoldingRegions>;
|
||||
}
|
||||
|
||||
export class FoldingController implements IEditorContribution {
|
||||
|
||||
static MAX_FOLDING_REGIONS = 5000;
|
||||
@@ -48,6 +55,8 @@ export class FoldingController implements IEditorContribution {
|
||||
private foldingModel: FoldingModel;
|
||||
private hiddenRangeModel: HiddenRangeModel;
|
||||
|
||||
private rangeProvider: RangeProvider;
|
||||
|
||||
private foldingModelPromise: TPromise<FoldingModel>;
|
||||
private updateScheduler: Delayer<FoldingModel>;
|
||||
|
||||
@@ -69,6 +78,7 @@ export class FoldingController implements IEditorContribution {
|
||||
this.foldingDecorationProvider.autoHideFoldingControls = this._autoHideFoldingControls;
|
||||
|
||||
this.globalToDispose.push(this.editor.onDidChangeModel(() => this.onModelChanged()));
|
||||
this.globalToDispose.push(FoldingProviderRegistry.onDidChange(() => this.onModelChanged()));
|
||||
|
||||
this.globalToDispose.push(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => {
|
||||
if (e.contribInfo) {
|
||||
@@ -167,17 +177,22 @@ export class FoldingController implements IEditorContribution {
|
||||
this.foldingModelPromise = null;
|
||||
this.hiddenRangeModel = null;
|
||||
this.cursorChangedScheduler = null;
|
||||
this.rangeProvider = null;
|
||||
}
|
||||
});
|
||||
this.onModelContentChanged();
|
||||
}
|
||||
|
||||
private computeRanges(editorModel: ITextModel) {
|
||||
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editorModel.getLanguageIdentifier().id);
|
||||
let offSide = foldingRules && foldingRules.offSide;
|
||||
let markers = foldingRules && foldingRules.markers;
|
||||
let ranges = computeIndentRanges(editorModel, offSide, markers);
|
||||
return ranges;
|
||||
private getRangeProvider(): RangeProvider {
|
||||
if (!this.rangeProvider) {
|
||||
let foldingProviders = FoldingProviderRegistry.ordered(this.foldingModel.textModel);
|
||||
if (foldingProviders.length) {
|
||||
this.rangeProvider = new SyntaxRangeProvider(foldingProviders);
|
||||
} else {
|
||||
this.rangeProvider = new IndentRangeProvider();
|
||||
}
|
||||
}
|
||||
return this.rangeProvider;
|
||||
}
|
||||
|
||||
public getFoldingModel() {
|
||||
@@ -191,9 +206,12 @@ export class FoldingController implements IEditorContribution {
|
||||
// some cursors might have moved into hidden regions, make sure they are in expanded regions
|
||||
let selections = this.editor.getSelections();
|
||||
let selectionLineNumbers = selections ? selections.map(s => s.startLineNumber) : [];
|
||||
this.foldingModel.update(this.computeRanges(this.foldingModel.textModel), selectionLineNumbers);
|
||||
return this.getRangeProvider().compute(this.foldingModel.textModel).then(foldingRanges => {
|
||||
this.foldingModel.update(foldingRanges, selectionLineNumbers);
|
||||
return this.foldingModel;
|
||||
});
|
||||
}
|
||||
return this.foldingModel;
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { ITextModel, IModelDecorationOptions, IModelDeltaDecoration, IModelDecorationsChangeAccessor } from 'vs/editor/common/model';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { FoldingRanges, ILineRange, FoldingRegion } from './foldingRanges';
|
||||
import { FoldingRegions, ILineRange, FoldingRegion } from './foldingRanges';
|
||||
|
||||
export interface IDecorationProvider {
|
||||
getDecorationOption(isCollapsed: boolean): IModelDecorationOptions;
|
||||
@@ -24,13 +24,13 @@ export class FoldingModel {
|
||||
private _textModel: ITextModel;
|
||||
private _decorationProvider: IDecorationProvider;
|
||||
|
||||
private _ranges: FoldingRanges;
|
||||
private _regions: FoldingRegions;
|
||||
private _editorDecorationIds: string[];
|
||||
private _isInitialized: boolean;
|
||||
|
||||
private _updateEventEmitter = new Emitter<FoldingModelChangeEvent>();
|
||||
|
||||
public get ranges(): FoldingRanges { return this._ranges; }
|
||||
public get regions(): FoldingRegions { return this._regions; }
|
||||
public get onDidChange(): Event<FoldingModelChangeEvent> { return this._updateEventEmitter.event; }
|
||||
public get textModel() { return this._textModel; }
|
||||
public get isInitialized() { return this._isInitialized; }
|
||||
@@ -38,7 +38,7 @@ export class FoldingModel {
|
||||
constructor(textModel: ITextModel, decorationProvider: IDecorationProvider) {
|
||||
this._textModel = textModel;
|
||||
this._decorationProvider = decorationProvider;
|
||||
this._ranges = new FoldingRanges(new Uint32Array(0), new Uint32Array(0));
|
||||
this._regions = new FoldingRegions(new Uint32Array(0), new Uint32Array(0));
|
||||
this._editorDecorationIds = [];
|
||||
this._isInitialized = false;
|
||||
}
|
||||
@@ -54,8 +54,8 @@ export class FoldingModel {
|
||||
let editorDecorationId = this._editorDecorationIds[index];
|
||||
if (editorDecorationId && !processed[editorDecorationId]) {
|
||||
processed[editorDecorationId] = true;
|
||||
let newCollapseState = !this._ranges.isCollapsed(index);
|
||||
this._ranges.setCollapsed(index, newCollapseState);
|
||||
let newCollapseState = !this._regions.isCollapsed(index);
|
||||
this._regions.setCollapsed(index, newCollapseState);
|
||||
accessor.changeDecorationOptions(editorDecorationId, this._decorationProvider.getDecorationOption(newCollapseState));
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ export class FoldingModel {
|
||||
this._updateEventEmitter.fire({ model: this, collapseStateChanged: regions });
|
||||
}
|
||||
|
||||
public update(newRanges: FoldingRanges, blockedLineNumers: number[] = []): void {
|
||||
public update(newRegions: FoldingRegions, blockedLineNumers: number[] = []): void {
|
||||
let newEditorDecorations = [];
|
||||
|
||||
let isBlocked = (startLineNumber, endLineNumber) => {
|
||||
@@ -76,11 +76,11 @@ export class FoldingModel {
|
||||
};
|
||||
|
||||
let initRange = (index: number, isCollapsed: boolean) => {
|
||||
let startLineNumber = newRanges.getStartLineNumber(index);
|
||||
if (isCollapsed && isBlocked(startLineNumber, newRanges.getEndLineNumber(index))) {
|
||||
let startLineNumber = newRegions.getStartLineNumber(index);
|
||||
if (isCollapsed && isBlocked(startLineNumber, newRegions.getEndLineNumber(index))) {
|
||||
isCollapsed = false;
|
||||
}
|
||||
newRanges.setCollapsed(index, isCollapsed);
|
||||
newRegions.setCollapsed(index, isCollapsed);
|
||||
let maxColumn = this._textModel.getLineMaxColumn(startLineNumber);
|
||||
let decorationRange = {
|
||||
startLineNumber: startLineNumber,
|
||||
@@ -93,8 +93,8 @@ export class FoldingModel {
|
||||
|
||||
let i = 0;
|
||||
let nextCollapsed = () => {
|
||||
while (i < this._ranges.length) {
|
||||
let isCollapsed = this._ranges.isCollapsed(i);
|
||||
while (i < this._regions.length) {
|
||||
let isCollapsed = this._regions.isCollapsed(i);
|
||||
i++;
|
||||
if (isCollapsed) {
|
||||
return i - 1;
|
||||
@@ -105,14 +105,14 @@ export class FoldingModel {
|
||||
|
||||
let k = 0;
|
||||
let collapsedIndex = nextCollapsed();
|
||||
while (collapsedIndex !== -1 && k < newRanges.length) {
|
||||
while (collapsedIndex !== -1 && k < newRegions.length) {
|
||||
// get the latest range
|
||||
let decRange = this._textModel.getDecorationRange(this._editorDecorationIds[collapsedIndex]);
|
||||
if (decRange) {
|
||||
let collapsedStartLineNumber = decRange.startLineNumber;
|
||||
if (this._textModel.getLineMaxColumn(collapsedStartLineNumber) === decRange.startColumn) { // test that the decoration is still at the end otherwise it got deleted
|
||||
while (k < newRanges.length) {
|
||||
let startLineNumber = newRanges.getStartLineNumber(k);
|
||||
while (k < newRegions.length) {
|
||||
let startLineNumber = newRegions.getStartLineNumber(k);
|
||||
if (collapsedStartLineNumber >= startLineNumber) {
|
||||
initRange(k, collapsedStartLineNumber === startLineNumber);
|
||||
k++;
|
||||
@@ -124,13 +124,13 @@ export class FoldingModel {
|
||||
}
|
||||
collapsedIndex = nextCollapsed();
|
||||
}
|
||||
while (k < newRanges.length) {
|
||||
while (k < newRegions.length) {
|
||||
initRange(k, false);
|
||||
k++;
|
||||
}
|
||||
|
||||
this._editorDecorationIds = this._decorationProvider.deltaDecorations(this._editorDecorationIds, newEditorDecorations);
|
||||
this._ranges = newRanges;
|
||||
this._regions = newRegions;
|
||||
this._isInitialized = true;
|
||||
this._updateEventEmitter.fire({ model: this });
|
||||
}
|
||||
@@ -140,12 +140,12 @@ export class FoldingModel {
|
||||
*/
|
||||
public getMemento(): CollapseMemento {
|
||||
let collapsedRanges: ILineRange[] = [];
|
||||
for (let i = 0; i < this._ranges.length; i++) {
|
||||
if (this._ranges.isCollapsed(i)) {
|
||||
for (let i = 0; i < this._regions.length; i++) {
|
||||
if (this._regions.isCollapsed(i)) {
|
||||
let range = this._textModel.getDecorationRange(this._editorDecorationIds[i]);
|
||||
if (range) {
|
||||
let startLineNumber = range.startLineNumber;
|
||||
let endLineNumber = range.endLineNumber + this._ranges.getEndLineNumber(i) - this._ranges.getStartLineNumber(i);
|
||||
let endLineNumber = range.endLineNumber + this._regions.getEndLineNumber(i) - this._regions.getStartLineNumber(i);
|
||||
collapsedRanges.push({ startLineNumber, endLineNumber });
|
||||
}
|
||||
}
|
||||
@@ -179,11 +179,11 @@ export class FoldingModel {
|
||||
|
||||
getAllRegionsAtLine(lineNumber: number, filter?: (r: FoldingRegion, level: number) => boolean): FoldingRegion[] {
|
||||
let result: FoldingRegion[] = [];
|
||||
if (this._ranges) {
|
||||
let index = this._ranges.findRange(lineNumber);
|
||||
if (this._regions) {
|
||||
let index = this._regions.findRange(lineNumber);
|
||||
let level = 1;
|
||||
while (index >= 0) {
|
||||
let current = this._ranges.toRegion(index);
|
||||
let current = this._regions.toRegion(index);
|
||||
if (!filter || filter(current, level)) {
|
||||
result.push(current);
|
||||
}
|
||||
@@ -195,10 +195,10 @@ export class FoldingModel {
|
||||
}
|
||||
|
||||
getRegionAtLine(lineNumber: number): FoldingRegion {
|
||||
if (this._ranges) {
|
||||
let index = this._ranges.findRange(lineNumber);
|
||||
if (this._regions) {
|
||||
let index = this._regions.findRange(lineNumber);
|
||||
if (index >= 0) {
|
||||
return this._ranges.toRegion(index);
|
||||
return this._regions.toRegion(index);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -210,9 +210,9 @@ export class FoldingModel {
|
||||
let levelStack: FoldingRegion[] = trackLevel ? [] : null;
|
||||
let index = region ? region.regionIndex + 1 : 0;
|
||||
let endLineNumber = region ? region.endLineNumber : Number.MAX_VALUE;
|
||||
for (let i = index, len = this._ranges.length; i < len; i++) {
|
||||
let current = this._ranges.toRegion(i);
|
||||
if (this._ranges.getStartLineNumber(i) < endLineNumber) {
|
||||
for (let i = index, len = this._regions.length; i < len; i++) {
|
||||
let current = this._regions.toRegion(i);
|
||||
if (this._regions.getStartLineNumber(i) < endLineNumber) {
|
||||
if (trackLevel) {
|
||||
while (levelStack.length > 0 && !current.containedBy(levelStack[levelStack.length - 1])) {
|
||||
levelStack.pop();
|
||||
@@ -296,13 +296,13 @@ export function setCollapseStateAtLevel(foldingModel: FoldingModel, foldLevel: n
|
||||
*/
|
||||
export function setCollapseStateForMatchingLines(foldingModel: FoldingModel, regExp: RegExp, doCollapse: boolean): void {
|
||||
let editorModel = foldingModel.textModel;
|
||||
let ranges = foldingModel.ranges;
|
||||
let regions = foldingModel.regions;
|
||||
let toToggle = [];
|
||||
for (let i = ranges.length - 1; i >= 0; i--) {
|
||||
if (doCollapse !== ranges.isCollapsed(i)) {
|
||||
let startLineNumber = ranges.getStartLineNumber(i);
|
||||
for (let i = regions.length - 1; i >= 0; i--) {
|
||||
if (doCollapse !== regions.isCollapsed(i)) {
|
||||
let startLineNumber = regions.getStartLineNumber(i);
|
||||
if (regExp.test(editorModel.getLineContent(startLineNumber))) {
|
||||
toToggle.push(ranges.toRegion(i));
|
||||
toToggle.push(regions.toRegion(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export const MAX_LINE_NUMBER = 0xFFFFFF;
|
||||
|
||||
const MASK_INDENT = 0xFF000000;
|
||||
|
||||
export class FoldingRanges {
|
||||
export class FoldingRegions {
|
||||
private _startIndexes: Uint32Array;
|
||||
private _endIndexes: Uint32Array;
|
||||
private _collapseStates: Uint32Array;
|
||||
@@ -138,7 +138,7 @@ export class FoldingRanges {
|
||||
|
||||
export class FoldingRegion {
|
||||
|
||||
constructor(private ranges: FoldingRanges, private index: number) {
|
||||
constructor(private ranges: FoldingRegions, private index: number) {
|
||||
}
|
||||
|
||||
public get startLineNumber() {
|
||||
|
||||
@@ -23,7 +23,7 @@ export class HiddenRangeModel {
|
||||
this._foldingModel = model;
|
||||
this._foldingModelListener = model.onDidChange(_ => this.updateHiddenRanges());
|
||||
this._hiddenRanges = [];
|
||||
if (model.ranges.length) {
|
||||
if (model.regions.length) {
|
||||
this.updateHiddenRanges();
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ export class HiddenRangeModel {
|
||||
let lastCollapsedStart = Number.MAX_VALUE;
|
||||
let lastCollapsedEnd = -1;
|
||||
|
||||
let ranges = this._foldingModel.ranges;
|
||||
let ranges = this._foldingModel.regions;
|
||||
for (; i < ranges.length; i++) {
|
||||
if (!ranges.isCollapsed(i)) {
|
||||
continue;
|
||||
|
||||
@@ -7,25 +7,37 @@
|
||||
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { FoldingRanges, MAX_LINE_NUMBER } from 'vs/editor/contrib/folding/foldingRanges';
|
||||
import { FoldingRegions, MAX_LINE_NUMBER } from 'vs/editor/contrib/folding/foldingRanges';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { RangeProvider } from './folding';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
|
||||
const MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT = 5000;
|
||||
|
||||
export class IndentRangeProvider implements RangeProvider {
|
||||
compute(editorModel: ITextModel): TPromise<FoldingRegions> {
|
||||
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editorModel.getLanguageIdentifier().id);
|
||||
let offSide = foldingRules && foldingRules.offSide;
|
||||
let markers = foldingRules && foldingRules.markers;
|
||||
return TPromise.as(computeRanges(editorModel, offSide, markers));
|
||||
}
|
||||
}
|
||||
|
||||
// public only for testing
|
||||
export class RangesCollector {
|
||||
private _startIndexes: number[];
|
||||
private _endIndexes: number[];
|
||||
private _indentOccurrences: number[];
|
||||
private _length: number;
|
||||
private _FoldingRangesLimit: number;
|
||||
private _foldingRangesLimit: number;
|
||||
|
||||
constructor(FoldingRangesLimit: number) {
|
||||
constructor(foldingRangesLimit: number) {
|
||||
this._startIndexes = [];
|
||||
this._endIndexes = [];
|
||||
this._indentOccurrences = [];
|
||||
this._length = 0;
|
||||
this._FoldingRangesLimit = FoldingRangesLimit;
|
||||
this._foldingRangesLimit = foldingRangesLimit;
|
||||
}
|
||||
|
||||
public insertFirst(startLineNumber: number, endLineNumber: number, indent: number) {
|
||||
@@ -42,7 +54,7 @@ export class RangesCollector {
|
||||
}
|
||||
|
||||
public toIndentRanges(model: ITextModel) {
|
||||
if (this._length <= this._FoldingRangesLimit) {
|
||||
if (this._length <= this._foldingRangesLimit) {
|
||||
// reverse and create arrays of the exact length
|
||||
let startIndexes = new Uint32Array(this._length);
|
||||
let endIndexes = new Uint32Array(this._length);
|
||||
@@ -50,14 +62,14 @@ export class RangesCollector {
|
||||
startIndexes[k] = this._startIndexes[i];
|
||||
endIndexes[k] = this._endIndexes[i];
|
||||
}
|
||||
return new FoldingRanges(startIndexes, endIndexes);
|
||||
return new FoldingRegions(startIndexes, endIndexes);
|
||||
} else {
|
||||
let entries = 0;
|
||||
let maxIndent = this._indentOccurrences.length;
|
||||
for (let i = 0; i < this._indentOccurrences.length; i++) {
|
||||
let n = this._indentOccurrences[i];
|
||||
if (n) {
|
||||
if (n + entries > this._FoldingRangesLimit) {
|
||||
if (n + entries > this._foldingRangesLimit) {
|
||||
maxIndent = i;
|
||||
break;
|
||||
}
|
||||
@@ -78,7 +90,7 @@ export class RangesCollector {
|
||||
k++;
|
||||
}
|
||||
}
|
||||
return new FoldingRanges(startIndexes, endIndexes);
|
||||
return new FoldingRegions(startIndexes, endIndexes);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -87,9 +99,9 @@ export class RangesCollector {
|
||||
|
||||
interface PreviousRegion { indent: number; line: number; marker: boolean; }
|
||||
|
||||
export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldingMarkers, FoldingRangesLimit = MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT): FoldingRanges {
|
||||
export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldingMarkers, foldingRangesLimit = MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT): FoldingRegions {
|
||||
const tabSize = model.getOptions().tabSize;
|
||||
let result = new RangesCollector(FoldingRangesLimit);
|
||||
let result = new RangesCollector(foldingRangesLimit);
|
||||
|
||||
let pattern = void 0;
|
||||
if (markers) {
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { FoldingProvider, IFoldingRange } from 'vs/editor/common/modes';
|
||||
import { onUnexpectedExternalError } from 'vs/base/common/errors';
|
||||
import { asWinJsPromise } from 'vs/base/common/async';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { RangeProvider } from './folding';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { MAX_LINE_NUMBER, FoldingRegions } from './foldingRanges';
|
||||
|
||||
const MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT = 5000;
|
||||
|
||||
export interface IFoldingRangeData extends IFoldingRange {
|
||||
rank: number;
|
||||
}
|
||||
|
||||
export class SyntaxRangeProvider implements RangeProvider {
|
||||
|
||||
constructor(private providers: FoldingProvider[]) {
|
||||
}
|
||||
|
||||
compute(model: ITextModel): TPromise<FoldingRegions> {
|
||||
return collectSyntaxRanges(this.providers, model).then(ranges => {
|
||||
return sanitizeRanges(ranges);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function collectSyntaxRanges(providers: FoldingProvider[], model: ITextModel): TPromise<IFoldingRangeData[]> {
|
||||
const rangeData: IFoldingRangeData[] = [];
|
||||
let promises = providers.map((provider, rank) => asWinJsPromise(token => provider.provideFoldingRanges(model, token)).then(list => {
|
||||
if (list && Array.isArray(list.ranges)) {
|
||||
for (let r of list.ranges) {
|
||||
rangeData.push({ startLineNumber: r.startLineNumber, endLineNumber: r.endLineNumber, rank, type: r.type });
|
||||
}
|
||||
}
|
||||
}, onUnexpectedExternalError));
|
||||
|
||||
return TPromise.join(promises).then(() => {
|
||||
return rangeData;
|
||||
});
|
||||
}
|
||||
|
||||
export class RangesCollector {
|
||||
private _startIndexes: number[];
|
||||
private _endIndexes: number[];
|
||||
private _nestingLevels: number[];
|
||||
private _nestingLevelCounts: number[];
|
||||
private _length: number;
|
||||
private _foldingRangesLimit: number;
|
||||
|
||||
constructor(foldingRangesLimit: number) {
|
||||
this._startIndexes = [];
|
||||
this._endIndexes = [];
|
||||
this._nestingLevels = [];
|
||||
this._nestingLevelCounts = [];
|
||||
this._length = 0;
|
||||
this._foldingRangesLimit = foldingRangesLimit;
|
||||
}
|
||||
|
||||
public add(startLineNumber: number, endLineNumber: number, nestingLevel: number) {
|
||||
if (startLineNumber > MAX_LINE_NUMBER || endLineNumber > MAX_LINE_NUMBER) {
|
||||
return;
|
||||
}
|
||||
let index = this._length;
|
||||
this._startIndexes[index] = startLineNumber;
|
||||
this._endIndexes[index] = endLineNumber;
|
||||
this._nestingLevels[index] = nestingLevel;
|
||||
this._length++;
|
||||
if (nestingLevel < 30) {
|
||||
this._nestingLevelCounts[nestingLevel] = (this._nestingLevelCounts[nestingLevel] || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public toIndentRanges() {
|
||||
if (this._length <= this._foldingRangesLimit) {
|
||||
let startIndexes = new Uint32Array(this._length);
|
||||
let endIndexes = new Uint32Array(this._length);
|
||||
for (let i = 0; i < this._length; i++) {
|
||||
startIndexes[i] = this._startIndexes[i];
|
||||
endIndexes[i] = this._endIndexes[i];
|
||||
}
|
||||
return new FoldingRegions(startIndexes, endIndexes);
|
||||
} else {
|
||||
let entries = 0;
|
||||
let maxLevel = this._nestingLevelCounts.length;
|
||||
for (let i = 0; i < this._nestingLevelCounts.length; i++) {
|
||||
let n = this._nestingLevelCounts[i];
|
||||
if (n) {
|
||||
if (n + entries > this._foldingRangesLimit) {
|
||||
maxLevel = i;
|
||||
break;
|
||||
}
|
||||
entries += n;
|
||||
}
|
||||
}
|
||||
let startIndexes = new Uint32Array(entries);
|
||||
let endIndexes = new Uint32Array(entries);
|
||||
for (let i = 0, k = 0; i < this._length; i++) {
|
||||
let level = this._nestingLevels[i];
|
||||
if (level < maxLevel) {
|
||||
startIndexes[k] = this._startIndexes[i];
|
||||
endIndexes[k] = this._endIndexes[i];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
return new FoldingRegions(startIndexes, endIndexes);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export function sanitizeRanges(rangeData: IFoldingRangeData[]): FoldingRegions {
|
||||
|
||||
let sorted = rangeData.sort((d1, d2) => {
|
||||
let diff = d1.startLineNumber - d2.startLineNumber;
|
||||
if (diff === 0) {
|
||||
diff = d1.rank - d2.rank;
|
||||
}
|
||||
return diff;
|
||||
});
|
||||
let collector = new RangesCollector(MAX_FOLDING_REGIONS_FOR_INDENT_LIMIT);
|
||||
|
||||
let top: IFoldingRangeData = null;
|
||||
let previous = [];
|
||||
for (let entry of sorted) {
|
||||
if (!top) {
|
||||
top = entry;
|
||||
collector.add(entry.startLineNumber, entry.endLineNumber, previous.length);
|
||||
} else {
|
||||
if (entry.startLineNumber > top.startLineNumber) {
|
||||
if (entry.endLineNumber <= top.endLineNumber) {
|
||||
previous.push(top);
|
||||
top = entry;
|
||||
collector.add(entry.startLineNumber, entry.endLineNumber, previous.length);
|
||||
} else if (entry.startLineNumber > top.endLineNumber) {
|
||||
do {
|
||||
top = previous.pop();
|
||||
} while (top && entry.startLineNumber > top.endLineNumber);
|
||||
previous.push(top);
|
||||
top = entry;
|
||||
collector.add(entry.startLineNumber, entry.endLineNumber, previous.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return collector.toIndentRanges();
|
||||
}
|
||||
@@ -61,7 +61,7 @@ suite('Folding Model', () => {
|
||||
|
||||
function assertFoldedRanges(foldingModel: FoldingModel, expectedRegions: ExpectedRegion[], message?: string) {
|
||||
let actualRanges = [];
|
||||
let actual = foldingModel.ranges;
|
||||
let actual = foldingModel.regions;
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
if (actual.isCollapsed(i)) {
|
||||
actualRanges.push(r(actual.getStartLineNumber(i), actual.getEndLineNumber(i)));
|
||||
@@ -72,7 +72,7 @@ suite('Folding Model', () => {
|
||||
|
||||
function assertRanges(foldingModel: FoldingModel, expectedRegions: ExpectedRegion[], message?: string) {
|
||||
let actualRanges = [];
|
||||
let actual = foldingModel.ranges;
|
||||
let actual = foldingModel.regions;
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
actualRanges.push(r(actual.getStartLineNumber(i), actual.getEndLineNumber(i), actual.isCollapsed(i)));
|
||||
}
|
||||
|
||||
@@ -389,6 +389,14 @@ export function registerColorProvider(languageId: string, provider: modes.Docume
|
||||
return modes.ColorProviderRegistry.register(languageId, provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a folding provider
|
||||
*/
|
||||
/*export function registerFoldingProvider(languageId: string, provider: modes.FoldingProvider): IDisposable {
|
||||
return modes.FoldingProviderRegistry.register(languageId, provider);
|
||||
}*/
|
||||
|
||||
|
||||
/**
|
||||
* Contains additional diagnostic information about the context in which
|
||||
* a [code action](#CodeActionProvider.provideCodeActions) is run.
|
||||
|
||||
Vendored
+3
@@ -4047,6 +4047,9 @@ declare module monaco.languages {
|
||||
*/
|
||||
export function registerColorProvider(languageId: string, provider: DocumentColorProvider): IDisposable;
|
||||
|
||||
/**
|
||||
* Register a folding provider
|
||||
*/
|
||||
/**
|
||||
* Contains additional diagnostic information about the context in which
|
||||
* a [code action](#CodeActionProvider.provideCodeActions) is run.
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { fork, ChildProcess } from 'child_process';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { join } from 'vs/base/common/paths';
|
||||
import { Limiter } from 'vs/base/common/async';
|
||||
import { fromNodeEventEmitter, anyEvent, mapEvent, debounceEvent } from 'vs/base/common/event';
|
||||
|
||||
export class ExtensionsLifecycle extends Disposable {
|
||||
|
||||
private processesLimiter: Limiter<void> = new Limiter(5); // Run max 5 processes in parallel
|
||||
|
||||
constructor(
|
||||
@ILogService private logService: ILogService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
uninstall(extension: ILocalExtension): TPromise<void> {
|
||||
const uninstallScript = this.parseUninstallScript(extension);
|
||||
if (uninstallScript) {
|
||||
this.logService.info(extension.identifier.id, 'Running Uninstall hook');
|
||||
return this.processesLimiter.queue(() =>
|
||||
this.runUninstallHook(uninstallScript.uninstallHook, uninstallScript.args, extension)
|
||||
.then(() => this.logService.info(extension.identifier.id, 'Finished running uninstall hook'), err => this.logService.error(extension.identifier.id, `Failed to run uninstall hook: ${err}`)));
|
||||
}
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
private parseUninstallScript(extension: ILocalExtension): { uninstallHook: string, args: string[] } {
|
||||
if (extension.manifest && extension.manifest['scripts'] && typeof extension.manifest['scripts']['vscode:uninstall'] === 'string') {
|
||||
const uninstallScript = (<string>extension.manifest['scripts']['vscode:uninstall']).split(' ');
|
||||
if (uninstallScript.length < 2 || uninstallScript[0] !== 'node' || !uninstallScript[1]) {
|
||||
this.logService.warn(extension.identifier.id, 'Uninstall script should be a node script');
|
||||
return null;
|
||||
}
|
||||
return { uninstallHook: join(extension.path, uninstallScript[1]), args: uninstallScript.slice(2) || [] };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private runUninstallHook(lifecycleHook: string, args: string[], extension: ILocalExtension): TPromise<void> {
|
||||
return new TPromise((c, e) => {
|
||||
|
||||
const extensionLifecycleProcess = this.start(lifecycleHook, args, extension);
|
||||
let timeoutHandler;
|
||||
|
||||
const onexit = (error?: string) => {
|
||||
clearTimeout(timeoutHandler);
|
||||
timeoutHandler = null;
|
||||
if (error) {
|
||||
e(error);
|
||||
} else {
|
||||
c(null);
|
||||
}
|
||||
};
|
||||
|
||||
// on error
|
||||
extensionLifecycleProcess.on('error', (err) => {
|
||||
if (timeoutHandler) {
|
||||
onexit(toErrorMessage(err) || 'Unknown');
|
||||
}
|
||||
});
|
||||
|
||||
// on exit
|
||||
extensionLifecycleProcess.on('exit', (code: number, signal: string) => {
|
||||
if (timeoutHandler) {
|
||||
onexit(code ? `Process exited with code ${code}` : void 0);
|
||||
}
|
||||
});
|
||||
|
||||
// timeout: kill process after waiting for 5s
|
||||
timeoutHandler = setTimeout(() => {
|
||||
timeoutHandler = null;
|
||||
extensionLifecycleProcess.kill();
|
||||
e('timed out');
|
||||
}, 5000);
|
||||
});
|
||||
}
|
||||
|
||||
private start(uninstallHook: string, args: string[], extension: ILocalExtension): ChildProcess {
|
||||
const opts = {
|
||||
silent: true,
|
||||
execArgv: <string[]>undefined
|
||||
};
|
||||
const extensionUninstallProcess = fork(uninstallHook, ['--type=extensionUninstall', ...args], opts);
|
||||
|
||||
// Catch all output coming from the process
|
||||
type Output = { data: string, format: string[] };
|
||||
extensionUninstallProcess.stdout.setEncoding('utf8');
|
||||
extensionUninstallProcess.stderr.setEncoding('utf8');
|
||||
const onStdout = fromNodeEventEmitter<string>(extensionUninstallProcess.stdout, 'data');
|
||||
const onStderr = fromNodeEventEmitter<string>(extensionUninstallProcess.stderr, 'data');
|
||||
const onOutput = anyEvent(
|
||||
mapEvent(onStdout, o => ({ data: `%c${o}`, format: [''] })),
|
||||
mapEvent(onStderr, o => ({ data: `%c${o}`, format: ['color: red'] }))
|
||||
);
|
||||
|
||||
// Debounce all output, so we can render it in the Chrome console as a group
|
||||
const onDebouncedOutput = debounceEvent<Output>(onOutput, (r, o) => {
|
||||
return r
|
||||
? { data: r.data + o.data, format: [...r.format, ...o.format] }
|
||||
: { data: o.data, format: o.format };
|
||||
}, 100);
|
||||
|
||||
// Print out extension host output
|
||||
onDebouncedOutput(data => {
|
||||
console.group(extension.identifier.id);
|
||||
console.log(data.data, ...data.format);
|
||||
console.groupEnd();
|
||||
});
|
||||
|
||||
return extensionUninstallProcess;
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ExtensionsManifestCache } from 'vs/platform/extensionManagement/node/extensionsManifestCache';
|
||||
import { IChoiceService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { ExtensionsLifecycle } from 'vs/platform/extensionManagement/node/extensionLifecycle';
|
||||
|
||||
const SystemExtensionsRoot = path.normalize(path.join(URI.parse(require.toUrl('')).fsPath, '..', 'extensions'));
|
||||
const ERROR_SCANNING_SYS_EXTENSIONS = 'scanningSystem';
|
||||
@@ -110,6 +111,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||
private lastReportTimestamp = 0;
|
||||
private readonly installingExtensions: Map<string, TPromise<ILocalExtension>> = new Map<string, TPromise<ILocalExtension>>();
|
||||
private readonly manifestCache: ExtensionsManifestCache;
|
||||
private readonly extensionLifecycle: ExtensionsLifecycle;
|
||||
|
||||
private readonly _onInstallExtension = new Emitter<InstallExtensionEvent>();
|
||||
readonly onInstallExtension: Event<InstallExtensionEvent> = this._onInstallExtension.event;
|
||||
@@ -135,6 +137,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||
this.uninstalledFileLimiter = new Limiter(1);
|
||||
this._register(toDisposable(() => this.installingExtensions.clear()));
|
||||
this.manifestCache = this._register(new ExtensionsManifestCache(environmentService, this));
|
||||
this.extensionLifecycle = this._register(new ExtensionsLifecycle(this.logService));
|
||||
}
|
||||
|
||||
install(zipPath: string): TPromise<void> {
|
||||
@@ -708,24 +711,43 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
||||
}
|
||||
|
||||
removeDeprecatedExtensions(): TPromise<any> {
|
||||
return this.removeUninstalledExtensions()
|
||||
.then(() => this.removeOutdatedExtensions());
|
||||
}
|
||||
|
||||
private removeUninstalledExtensions(): TPromise<void> {
|
||||
return this.getUninstalledExtensions()
|
||||
.then(uninstalled => this.scanExtensions(this.extensionsPath, LocalExtensionType.User) // All user extensions
|
||||
.then(extensions => {
|
||||
const toRemove: { path: string, id: string }[] = [];
|
||||
// Uninstalled extensions
|
||||
toRemove.push(...extensions.filter(e => uninstalled[e.identifier.id]).map(e => ({ path: e.path, id: e.identifier.id })));
|
||||
|
||||
// Outdated extensions
|
||||
const byExtension: ILocalExtension[][] = groupByExtension(extensions, e => ({ id: getGalleryExtensionIdFromLocal(e), uuid: e.identifier.uuid }));
|
||||
toRemove.push(...flatten(byExtension.map(p => p.sort((a, b) => semver.rcompare(a.manifest.version, b.manifest.version)).slice(1)))
|
||||
.map(e => ({ path: e.path, id: e.identifier.id })));
|
||||
|
||||
return TPromise.join(distinct(toRemove, e => e.path).map(({ path, id }) => {
|
||||
return pfs.rimraf(path)
|
||||
.then(() => this.withUninstalledExtensions(uninstalled => delete uninstalled[id]));
|
||||
}));
|
||||
const toRemove: ILocalExtension[] = extensions.filter(e => uninstalled[e.identifier.id]);
|
||||
return TPromise.join(toRemove.map(e => this.removeUninstalledExtension(e)));
|
||||
})
|
||||
);
|
||||
).then(() => null);
|
||||
}
|
||||
|
||||
private removeOutdatedExtensions(): TPromise<void> {
|
||||
return this.scanExtensions(this.extensionsPath, LocalExtensionType.User) // All user extensions
|
||||
.then(extensions => {
|
||||
const toRemove: ILocalExtension[] = [];
|
||||
|
||||
// Outdated extensions
|
||||
const byExtension: ILocalExtension[][] = groupByExtension(extensions, e => ({ id: getGalleryExtensionIdFromLocal(e), uuid: e.identifier.uuid }));
|
||||
toRemove.push(...flatten(byExtension.map(p => p.sort((a, b) => semver.rcompare(a.manifest.version, b.manifest.version)).slice(1))));
|
||||
|
||||
return TPromise.join(toRemove.map(extension => this.removeExtension(extension, 'outdated')));
|
||||
}).then(() => null);
|
||||
}
|
||||
|
||||
private removeUninstalledExtension(extension: ILocalExtension): TPromise<void> {
|
||||
return this.extensionLifecycle.uninstall(extension)
|
||||
.then(() => this.removeExtension(extension, 'uninstalled'))
|
||||
.then(() => this.withUninstalledExtensions(uninstalled => delete uninstalled[extension.identifier.id]))
|
||||
.then(() => null);
|
||||
}
|
||||
|
||||
private removeExtension(extension: ILocalExtension, type: string): TPromise<void> {
|
||||
this.logService.trace(extension.identifier.id, 'Deleting from disk', type);
|
||||
return pfs.rimraf(extension.path).then(() => this.logService.info(extension.identifier.id, 'Deleted from disk'));
|
||||
}
|
||||
|
||||
private isUninstalled(id: string): TPromise<boolean> {
|
||||
|
||||
@@ -264,6 +264,10 @@ const schema: IJSONSchema = {
|
||||
'vscode:prepublish': {
|
||||
description: nls.localize('vscode.extension.scripts.prepublish', 'Script executed before the package is published as a VS Code extension.'),
|
||||
type: 'string'
|
||||
},
|
||||
'vscode:uninstall': {
|
||||
description: nls.localize('vscode.extension.scripts.uninstall', 'Script executed after the extension is uninstalled from VS Code. Only Node script is supported.'),
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -51,6 +51,11 @@ export interface IStatusbarEntry {
|
||||
* An optional extension ID if this entry is provided from an extension.
|
||||
*/
|
||||
extensionId?: string;
|
||||
|
||||
/**
|
||||
* Wether to show a beak above the status bar entry.
|
||||
*/
|
||||
showBeak?: boolean;
|
||||
}
|
||||
|
||||
export interface IStatusbarService {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { readFile } from 'vs/base/node/pfs';
|
||||
|
||||
export function resolveCommonProperties(commit: string, version: string, machineId: string, installSourcePath: string): TPromise<{ [name: string]: string; }> {
|
||||
const result: { [name: string]: string; } = Object.create(null);
|
||||
// __GDPR__COMMON__ "common.machineId" : { "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" }
|
||||
// __GDPR__COMMON__ "common.machineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" }
|
||||
result['common.machineId'] = machineId;
|
||||
// __GDPR__COMMON__ "sessionID" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
result['sessionID'] = uuid.generateUuid() + Date.now();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import product from 'vs/platform/node/product';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
|
||||
import { IRequestService } from 'vs/platform/request/node/request';
|
||||
@@ -76,7 +77,13 @@ export class LinuxUpdateService extends AbstractUpdateService {
|
||||
}
|
||||
|
||||
protected doDownloadUpdate(state: AvailableForDownload): TPromise<void> {
|
||||
shell.openExternal(state.update.url);
|
||||
// Use the download URL if available as we don't currently detect the package type that was
|
||||
// installed and the website download page is more useful than the tarball generally.
|
||||
if (product.downloadUrl && product.downloadUrl.length > 0) {
|
||||
shell.openExternal(product.downloadUrl);
|
||||
} else {
|
||||
shell.openExternal(state.update.url);
|
||||
}
|
||||
this.setState(State.Idle);
|
||||
|
||||
return TPromise.as(null);
|
||||
|
||||
@@ -108,7 +108,7 @@ export interface IWindowsService {
|
||||
showSaveDialog(windowId: number, options: SaveDialogOptions): TPromise<string>;
|
||||
showOpenDialog(windowId: number, options: OpenDialogOptions): TPromise<string[]>;
|
||||
|
||||
reloadWindow(windowId: number): TPromise<void>;
|
||||
reloadWindow(windowId: number, args?: ParsedArgs): TPromise<void>;
|
||||
openDevTools(windowId: number): TPromise<void>;
|
||||
toggleDevTools(windowId: number): TPromise<void>;
|
||||
closeWorkspace(windowId: number): TPromise<void>;
|
||||
@@ -183,7 +183,7 @@ export interface IWindowService {
|
||||
pickFileAndOpen(options: INativeOpenDialogOptions): TPromise<void>;
|
||||
pickFolderAndOpen(options: INativeOpenDialogOptions): TPromise<void>;
|
||||
pickWorkspaceAndOpen(options: INativeOpenDialogOptions): TPromise<void>;
|
||||
reloadWindow(): TPromise<void>;
|
||||
reloadWindow(args?: ParsedArgs): TPromise<void>;
|
||||
openDevTools(): TPromise<void>;
|
||||
toggleDevTools(): TPromise<void>;
|
||||
closeWorkspace(): TPromise<void>;
|
||||
|
||||
@@ -13,6 +13,7 @@ import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceFolde
|
||||
import { IRecentlyOpened } from 'vs/platform/history/common/history';
|
||||
import { ICommandAction } from 'vs/platform/actions/common/actions';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
|
||||
export interface IWindowsChannel extends IChannel {
|
||||
call(command: 'event:onWindowOpen'): TPromise<number>;
|
||||
@@ -25,7 +26,7 @@ export interface IWindowsChannel extends IChannel {
|
||||
call(command: 'showMessageBox', arg: [number, MessageBoxOptions]): TPromise<IMessageBoxResult>;
|
||||
call(command: 'showSaveDialog', arg: [number, SaveDialogOptions]): TPromise<string>;
|
||||
call(command: 'showOpenDialog', arg: [number, OpenDialogOptions]): TPromise<string[]>;
|
||||
call(command: 'reloadWindow', arg: number): TPromise<void>;
|
||||
call(command: 'reloadWindow', arg: [number, ParsedArgs]): TPromise<void>;
|
||||
call(command: 'toggleDevTools', arg: number): TPromise<void>;
|
||||
call(command: 'closeWorkspace', arg: number): TPromise<void>;
|
||||
call(command: 'createAndEnterWorkspace', arg: [number, IWorkspaceFolderCreationData[], string]): TPromise<IEnterWorkspaceResult>;
|
||||
@@ -91,7 +92,7 @@ export class WindowsChannel implements IWindowsChannel {
|
||||
case 'showMessageBox': return this.service.showMessageBox(arg[0], arg[1]);
|
||||
case 'showSaveDialog': return this.service.showSaveDialog(arg[0], arg[1]);
|
||||
case 'showOpenDialog': return this.service.showOpenDialog(arg[0], arg[1]);
|
||||
case 'reloadWindow': return this.service.reloadWindow(arg);
|
||||
case 'reloadWindow': return this.service.reloadWindow(arg[0], arg[1]);
|
||||
case 'openDevTools': return this.service.openDevTools(arg);
|
||||
case 'toggleDevTools': return this.service.toggleDevTools(arg);
|
||||
case 'closeWorkspace': return this.service.closeWorkspace(arg);
|
||||
@@ -192,8 +193,8 @@ export class WindowsChannelClient implements IWindowsService {
|
||||
return this.channel.call('showOpenDialog', [windowId, options]);
|
||||
}
|
||||
|
||||
reloadWindow(windowId: number): TPromise<void> {
|
||||
return this.channel.call('reloadWindow', windowId);
|
||||
reloadWindow(windowId: number, args?: ParsedArgs): TPromise<void> {
|
||||
return this.channel.call('reloadWindow', [windowId, args]);
|
||||
}
|
||||
|
||||
openDevTools(windowId: number): TPromise<void> {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { IWindowService, IWindowsService, INativeOpenDialogOptions, IEnterWorksp
|
||||
import { IRecentlyOpened } from 'vs/platform/history/common/history';
|
||||
import { ICommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
|
||||
export class WindowService implements IWindowService {
|
||||
|
||||
@@ -60,8 +61,8 @@ export class WindowService implements IWindowService {
|
||||
return this.windowsService.pickWorkspaceAndOpen(options);
|
||||
}
|
||||
|
||||
reloadWindow(): TPromise<void> {
|
||||
return this.windowsService.reloadWindow(this.windowId);
|
||||
reloadWindow(args?: ParsedArgs): TPromise<void> {
|
||||
return this.windowsService.reloadWindow(this.windowId, args);
|
||||
}
|
||||
|
||||
openDevTools(): TPromise<void> {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { assign } from 'vs/base/common/objects';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import product from 'vs/platform/node/product';
|
||||
import { IWindowsService, OpenContext, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult } from 'vs/platform/windows/common/windows';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { shell, crashReporter, app, Menu, clipboard } from 'electron';
|
||||
import Event, { chain, fromNodeEventEmitter } from 'vs/base/common/event';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
@@ -107,12 +107,12 @@ export class WindowsService implements IWindowsService, IDisposable {
|
||||
return this.windowsMainService.showOpenDialog(options, codeWindow);
|
||||
}
|
||||
|
||||
reloadWindow(windowId: number): TPromise<void> {
|
||||
reloadWindow(windowId: number, args: ParsedArgs): TPromise<void> {
|
||||
this.logService.trace('windowsService#reloadWindow', windowId);
|
||||
const codeWindow = this.windowsMainService.getWindowById(windowId);
|
||||
|
||||
if (codeWindow) {
|
||||
this.windowsMainService.reload(codeWindow);
|
||||
this.windowsMainService.reload(codeWindow, args);
|
||||
}
|
||||
|
||||
return TPromise.as(null);
|
||||
|
||||
Vendored
+84
-1
@@ -7,6 +7,63 @@
|
||||
|
||||
declare module 'vscode' {
|
||||
|
||||
export class FoldingRangeList {
|
||||
|
||||
/**
|
||||
* The folding ranges.
|
||||
*/
|
||||
ranges: FoldingRange[];
|
||||
|
||||
/**
|
||||
* Creates mew folding range list.
|
||||
*
|
||||
* @param ranges The folding ranges
|
||||
*/
|
||||
constructor(ranges: FoldingRange[]);
|
||||
}
|
||||
|
||||
|
||||
export class FoldingRange {
|
||||
|
||||
/**
|
||||
* The start line number (0-based)
|
||||
*/
|
||||
startLine: number;
|
||||
|
||||
/**
|
||||
* The end line number (0-based)
|
||||
*/
|
||||
endLine: number;
|
||||
|
||||
/**
|
||||
* The actual color value for this color range.
|
||||
*/
|
||||
type?: FoldingRangeType | string;
|
||||
|
||||
/**
|
||||
* Creates a new folding range.
|
||||
*
|
||||
* @param startLineNumber The first line of the fold
|
||||
* @param type The last line of the fold
|
||||
*/
|
||||
constructor(startLineNumber: number, endLineNumber: number, type?: FoldingRangeType);
|
||||
}
|
||||
|
||||
export enum FoldingRangeType {
|
||||
/**
|
||||
* Folding range for a comment
|
||||
*/
|
||||
Comment = 'comment',
|
||||
/**
|
||||
* Folding range for a imports or includes
|
||||
*/
|
||||
Imports = 'imports',
|
||||
/**
|
||||
* Folding range for a region (e.g. `#region`)
|
||||
*/
|
||||
Region = 'region'
|
||||
}
|
||||
|
||||
// export enum FileErrorCodes {
|
||||
// /**
|
||||
// * Not owner.
|
||||
@@ -340,10 +397,27 @@ declare module 'vscode' {
|
||||
}
|
||||
|
||||
export namespace languages {
|
||||
|
||||
/**
|
||||
* Register a folding provider.
|
||||
*
|
||||
* Multiple folding can be registered for a language. In that case providers are sorted
|
||||
* by their [score](#languages.match) and the best-matching provider is used. Failure
|
||||
* of the selected provider will cause a failure of the whole operation.
|
||||
*
|
||||
* @param selector A selector that defines the documents this provider is applicable to.
|
||||
* @param provider A folding provider.
|
||||
* @return A [disposable](#Disposable) that unregisters this provider when being disposed.
|
||||
*/
|
||||
export function registerFoldingProvider(selector: DocumentSelector, provider: FoldingProvider): Disposable;
|
||||
|
||||
export interface RenameProvider2 extends RenameProvider {
|
||||
resolveInitialRenameValue?(document: TextDocument, position: Position, token: CancellationToken): ProviderResult<RenameInitialValue>;
|
||||
}
|
||||
}
|
||||
export interface FoldingProvider {
|
||||
provideFoldingRanges(document: TextDocument, token: CancellationToken): ProviderResult<FoldingRangeList>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the validation type of the Source Control input.
|
||||
@@ -396,7 +470,7 @@ declare module 'vscode' {
|
||||
*/
|
||||
export interface WebviewOptions {
|
||||
/**
|
||||
* Should scripts be enabled in the webview contetn?
|
||||
* Should scripts be enabled in the webview content?
|
||||
*
|
||||
* Defaults to false (scripts-disabled).
|
||||
*/
|
||||
@@ -423,6 +497,15 @@ declare module 'vscode' {
|
||||
* webview content cannot be quickly saved and restored.
|
||||
*/
|
||||
readonly keepAlive?: boolean;
|
||||
|
||||
/**
|
||||
* Root paths from which the webview can load local (filesystem) resources using the `vscode-workspace-resource:` scheme.
|
||||
*
|
||||
* Default to the root folders of the current workspace.
|
||||
*
|
||||
* Pass in an empty array to disallow access to any local resources.
|
||||
*/
|
||||
readonly localResourceRoots?: Uri[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -346,6 +346,17 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
});
|
||||
}
|
||||
|
||||
// --- folding
|
||||
|
||||
$registerFoldingProvider(handle: number, selector: vscode.DocumentSelector): void {
|
||||
const proxy = this._proxy;
|
||||
this._registrations[handle] = modes.FoldingProviderRegistry.register(toLanguageSelector(selector), <modes.FoldingProvider>{
|
||||
provideFoldingRanges: (model, token) => {
|
||||
return wireCancellationToken(token, proxy.$provideFoldingRanges(handle, model.uri));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- configuration
|
||||
|
||||
private static _reviveRegExp(regExp: ISerializedRegExp): RegExp {
|
||||
|
||||
@@ -151,14 +151,8 @@ class WebviewEditor extends BaseWebviewEditor {
|
||||
public layout(dimension: Dimension): void {
|
||||
if (this._webview) {
|
||||
this.doUpdateContainer();
|
||||
this._webview.layout();
|
||||
}
|
||||
}
|
||||
|
||||
public focus() {
|
||||
if (this._webview) {
|
||||
this._webview.focus();
|
||||
}
|
||||
super.layout(dimension);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
@@ -207,10 +201,11 @@ class WebviewEditor extends BaseWebviewEditor {
|
||||
|
||||
this.webview.options = {
|
||||
allowScripts: input.options.enableScripts,
|
||||
enableWrappedPostMessage: true
|
||||
enableWrappedPostMessage: true,
|
||||
useSameOriginForRoot: false,
|
||||
localResourceRoots: (input && input.options.localResourceRoots) || this._contextService.getWorkspace().folders.map(x => x.uri)
|
||||
};
|
||||
this.webview.contents = input.html;
|
||||
this.webview.style(this.themeService.getTheme());
|
||||
}
|
||||
|
||||
private get webview(): Webview {
|
||||
@@ -220,26 +215,18 @@ class WebviewEditor extends BaseWebviewEditor {
|
||||
this._webview = new Webview(
|
||||
this.webviewContent,
|
||||
this._partService.getContainer(Parts.EDITOR_PART),
|
||||
this.themeService,
|
||||
this._environmentService,
|
||||
this._contextService,
|
||||
this._contextViewService,
|
||||
this.contextKey,
|
||||
this.findInputFocusContextKey,
|
||||
{
|
||||
enableWrappedPostMessage: true
|
||||
},
|
||||
false);
|
||||
this.webview.style(this.themeService.getTheme());
|
||||
enableWrappedPostMessage: true,
|
||||
useSameOriginForRoot: false
|
||||
});
|
||||
|
||||
this._webview.onDidClickLink(this.onDidClickLink, this, this._contentDisposables);
|
||||
|
||||
|
||||
this.themeService.onThemeChange(theme => {
|
||||
if (this._webview) {
|
||||
this._webview.style(theme);
|
||||
}
|
||||
}, null, this._contentDisposables);
|
||||
|
||||
this._webview.onMessage(message => {
|
||||
if (this.input) {
|
||||
(this.input as WebviewInput).events.onMessage(message);
|
||||
|
||||
@@ -292,6 +292,9 @@ export function createApiFactory(
|
||||
registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerColorProvider(selector, provider);
|
||||
},
|
||||
registerFoldingProvider: proposedApiFunction(extension, (selector: vscode.DocumentSelector, provider: vscode.FoldingProvider): vscode.Disposable => {
|
||||
return extHostLanguageFeatures.registerFoldingProvider(selector, provider);
|
||||
}),
|
||||
setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => {
|
||||
return extHostLanguageFeatures.setLanguageConfiguration(language, configuration);
|
||||
}
|
||||
@@ -634,7 +637,10 @@ export function createApiFactory(
|
||||
RelativePattern: extHostTypes.RelativePattern,
|
||||
|
||||
FileChangeType: extHostTypes.FileChangeType,
|
||||
FileType: extHostTypes.FileType
|
||||
FileType: extHostTypes.FileType,
|
||||
FoldingRangeList: extHostTypes.FoldingRangeList,
|
||||
FoldingRange: extHostTypes.FoldingRange,
|
||||
FoldingRangeType: extHostTypes.FoldingRangeType
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -282,6 +282,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
$registerSignatureHelpProvider(handle: number, selector: vscode.DocumentSelector, triggerCharacter: string[]): void;
|
||||
$registerDocumentLinkProvider(handle: number, selector: vscode.DocumentSelector): void;
|
||||
$registerDocumentColorProvider(handle: number, selector: vscode.DocumentSelector): void;
|
||||
$registerFoldingProvider(handle: number, selector: vscode.DocumentSelector): void;
|
||||
$setLanguageConfiguration(handle: number, languageId: string, configuration: ISerializedLanguageConfiguration): void;
|
||||
}
|
||||
|
||||
@@ -692,6 +693,7 @@ export interface ExtHostLanguageFeaturesShape {
|
||||
$resolveDocumentLink(handle: number, link: modes.ILink): TPromise<modes.ILink>;
|
||||
$provideDocumentColors(handle: number, resource: UriComponents): TPromise<IRawColorInfo[]>;
|
||||
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: IRawColorInfo): TPromise<modes.IColorPresentation[]>;
|
||||
$provideFoldingRanges(handle: number, resource: UriComponents): TPromise<modes.IFoldingRangeList>;
|
||||
}
|
||||
|
||||
export interface ExtHostQuickOpenShape {
|
||||
|
||||
@@ -804,10 +804,29 @@ class ColorProviderAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
class FoldingProviderAdapter {
|
||||
|
||||
constructor(
|
||||
private _documents: ExtHostDocuments,
|
||||
private _provider: vscode.FoldingProvider
|
||||
) { }
|
||||
|
||||
provideFoldingRanges(resource: URI): TPromise<modes.IFoldingRangeList> {
|
||||
const doc = this._documents.getDocumentData(resource).document;
|
||||
return asWinJsPromise(token => this._provider.provideFoldingRanges(doc, token)).then(list => {
|
||||
if (!Array.isArray(list.ranges)) {
|
||||
return void 0;
|
||||
}
|
||||
return TypeConverters.FoldingRangeList.from(list);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
type Adapter = OutlineAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
|
||||
| DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter
|
||||
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
|
||||
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter | ColorProviderAdapter;
|
||||
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter
|
||||
| ColorProviderAdapter | FoldingProviderAdapter;
|
||||
|
||||
export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
|
||||
@@ -1108,6 +1127,16 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape {
|
||||
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo));
|
||||
}
|
||||
|
||||
registerFoldingProvider(selector: vscode.DocumentSelector, provider: vscode.FoldingProvider): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new FoldingProviderAdapter(this._documents, provider));
|
||||
this._proxy.$registerFoldingProvider(handle, selector);
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideFoldingRanges(handle: number, resource: UriComponents): TPromise<modes.IFoldingRangeList> {
|
||||
return this._withAdapter(handle, FoldingProviderAdapter, adapter => adapter.provideFoldingRanges(URI.revive(resource)));
|
||||
}
|
||||
|
||||
// --- configuration
|
||||
|
||||
private static _serializeRegExp(regExp: RegExp): ISerializedRegExp {
|
||||
|
||||
@@ -586,6 +586,14 @@ export namespace ProgressLocation {
|
||||
}
|
||||
}
|
||||
|
||||
export namespace FoldingRangeList {
|
||||
export function from(rangeList: vscode.FoldingRangeList): modes.IFoldingRangeList {
|
||||
return {
|
||||
ranges: rangeList.ranges.map(r => ({ startLineNumber: r.startLine + 1, endLineNumber: r.endLine + 1 }))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function toTextEditorOptions(options?: vscode.TextDocumentShowOptions): ITextEditorOptions {
|
||||
if (options) {
|
||||
return {
|
||||
|
||||
@@ -1659,3 +1659,46 @@ export enum FileType {
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region folding api
|
||||
|
||||
export class FoldingRangeList {
|
||||
|
||||
ranges: FoldingRange[];
|
||||
|
||||
constructor(ranges: FoldingRange[]) {
|
||||
this.ranges = ranges;
|
||||
}
|
||||
}
|
||||
|
||||
export class FoldingRange {
|
||||
|
||||
startLine: number;
|
||||
|
||||
endLine: number;
|
||||
|
||||
type?: FoldingRangeType;
|
||||
|
||||
constructor(startLine: number, endLine: number, type?: FoldingRangeType) {
|
||||
this.startLine = startLine;
|
||||
this.endLine = endLine;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
export enum FoldingRangeType {
|
||||
/**
|
||||
* Folding range for a comment
|
||||
*/
|
||||
Comment = 'comment',
|
||||
/**
|
||||
* Folding range for a imports or includes
|
||||
*/
|
||||
Imports = 'imports',
|
||||
/**
|
||||
* Folding range for a region (e.g. `#region`)
|
||||
*/
|
||||
Region = 'region'
|
||||
}
|
||||
|
||||
//#endregion
|
||||
@@ -11,6 +11,11 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-silo.centered > .container > .title .title-label {
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .title-label a,
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .tabs-container > .tab .tab-label a {
|
||||
text-decoration: none;
|
||||
@@ -104,4 +109,4 @@
|
||||
.vs-dark .monaco-workbench .show-group-editors-action,
|
||||
.hc-black .monaco-workbench .show-group-editors-action {
|
||||
background: url('stackview-inverse.svg') center center no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
right: 8px;
|
||||
bottom: 30px; /* above status bar */
|
||||
bottom: 31px;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-workbench.nostatusbar > .notifications-center {
|
||||
right: 12px;
|
||||
bottom: 12px;
|
||||
bottom: 8px;
|
||||
}
|
||||
|
||||
.monaco-workbench > .notifications-center.visible {
|
||||
|
||||
@@ -14,6 +14,16 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.monaco-workbench .notifications-list-container .notification-offset-helper {
|
||||
opacity: 0;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 35px; /* 5px padding and 30px severity icon */
|
||||
margin-right: 77px; /* 5px padding and (3 * 24px) toolbar */
|
||||
position: absolute;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
/** Notification: Main Row */
|
||||
|
||||
.monaco-workbench .notifications-list-container .notification-list-item > .notification-list-item-main-row {
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
right: 3px;
|
||||
bottom: 28px; /* above status bar */
|
||||
bottom: 26px;
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-workbench.nostatusbar > .notifications-toasts {
|
||||
right: 12px;
|
||||
bottom: 12px;
|
||||
bottom: 3px;
|
||||
}
|
||||
|
||||
.monaco-workbench > .notifications-toasts.visible {
|
||||
|
||||
@@ -23,7 +23,7 @@ import { localize } from 'vs/nls';
|
||||
|
||||
export class NotificationsCenter extends Themable {
|
||||
|
||||
private static MAX_DIMENSIONS = new Dimension(600, 400);
|
||||
private static MAX_DIMENSIONS = new Dimension(450, 400);
|
||||
|
||||
private notificationsCenterContainer: HTMLElement;
|
||||
private notificationsList: NotificationsList;
|
||||
@@ -75,7 +75,10 @@ export class NotificationsCenter extends Themable {
|
||||
this.notificationsCenterContainer = document.createElement('div');
|
||||
addClass(this.notificationsCenterContainer, 'notifications-center');
|
||||
|
||||
this.notificationsList = this.instantiationService.createInstance(NotificationsList, this.notificationsCenterContainer, { ariaLabel: localize('notificationsList', "Notifications List") });
|
||||
this.notificationsList = this.instantiationService.createInstance(NotificationsList, this.notificationsCenterContainer, {
|
||||
ariaLabel: localize('notificationsList', "Notifications List"),
|
||||
useShadows: false
|
||||
});
|
||||
|
||||
this.container.appendChild(this.notificationsCenterContainer);
|
||||
}
|
||||
@@ -166,7 +169,7 @@ export class NotificationsCenter extends Themable {
|
||||
protected updateStyles(): void {
|
||||
if (this.notificationsCenterContainer) {
|
||||
const widgetShadowColor = this.getColor(widgetShadow);
|
||||
this.notificationsCenterContainer.style.boxShadow = widgetShadowColor ? `0 5px 8px ${widgetShadowColor}` : null;
|
||||
this.notificationsCenterContainer.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,6 +222,6 @@ export class NotificationsCenter extends Themable {
|
||||
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
||||
const notificationBorderColor = theme.getColor(NOTIFICATIONS_BORDER);
|
||||
if (notificationBorderColor) {
|
||||
collector.addRule(`.monaco-workbench > .notifications-center .notifications-list-container .notification-list-item { border-bottom: 1px solid ${notificationBorderColor}; }`);
|
||||
collector.addRule(`.monaco-workbench > .notifications-center .notifications-list-container .monaco-list-row[data-last-element="false"] > .notification-list-item { border-bottom: 1px solid ${notificationBorderColor}; }`);
|
||||
}
|
||||
});
|
||||
@@ -18,10 +18,6 @@ import { NotificationsListDelegate, NotificationRenderer } from 'vs/workbench/br
|
||||
import { NotificationActionRunner } from 'vs/workbench/browser/parts/notifications/notificationsActions';
|
||||
import { NotificationFocusedContext } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
|
||||
|
||||
export interface INotificationsListOptions {
|
||||
ariaLabel: string;
|
||||
}
|
||||
|
||||
export class NotificationsList extends Themable {
|
||||
private listContainer: HTMLElement;
|
||||
private list: WorkbenchList<INotificationViewItem>;
|
||||
@@ -30,7 +26,7 @@ export class NotificationsList extends Themable {
|
||||
|
||||
constructor(
|
||||
private container: HTMLElement,
|
||||
private options: INotificationsListOptions,
|
||||
private options: IListOptions<INotificationViewItem>,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IThemeService themeService: IThemeService
|
||||
) {
|
||||
@@ -77,9 +73,7 @@ export class NotificationsList extends Themable {
|
||||
this.listContainer,
|
||||
new NotificationsListDelegate(this.listContainer),
|
||||
[renderer],
|
||||
{
|
||||
ariaLabel: this.options.ariaLabel
|
||||
} as IListOptions<INotificationViewItem>
|
||||
this.options
|
||||
);
|
||||
this.toUnbind.push(this.list);
|
||||
|
||||
|
||||
@@ -72,7 +72,8 @@ export class NotificationsStatus {
|
||||
this.statusItem = this.statusbarService.addEntry({
|
||||
text: this.counter === 0 ? '$(megaphone)' : `$(megaphone) ${this.counter}`,
|
||||
command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER_COMMAND_ID : this.model.notifications.length > 0 ? SHOW_NOTIFICATIONS_CENTER_COMMAND_ID : void 0,
|
||||
tooltip: this.getTooltip()
|
||||
tooltip: this.getTooltip(),
|
||||
showBeak: this.isNotificationsCenterVisible
|
||||
}, StatusbarAlignment.RIGHT, -1000 /* towards the far end of the right hand side */);
|
||||
}
|
||||
|
||||
@@ -81,14 +82,14 @@ export class NotificationsStatus {
|
||||
return localize('hideNotifications', "Hide Notifications");
|
||||
}
|
||||
|
||||
if (this.counter === 0) {
|
||||
return localize('noNotifications', "No New Notifications");
|
||||
}
|
||||
|
||||
if (this.model.notifications.length === 0) {
|
||||
return localize('zeroNotifications', "No Notifications");
|
||||
}
|
||||
|
||||
if (this.counter === 0) {
|
||||
return localize('noNotifications', "No New Notifications");
|
||||
}
|
||||
|
||||
if (this.counter === 1) {
|
||||
return localize('oneNotification', "1 new notification");
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { NotificationsToastsVisibleContext } from 'vs/workbench/browser/parts/no
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
|
||||
interface INotificationToast {
|
||||
list: NotificationsList;
|
||||
@@ -106,7 +107,10 @@ export class NotificationsToasts extends Themable {
|
||||
itemDisposeables.push(toDisposable(() => this.notificationsToastsContainer.removeChild(notificationToastContainer)));
|
||||
|
||||
// Create toast with item and show
|
||||
const notificationList = this.instantiationService.createInstance(NotificationsList, notificationToastContainer, { ariaLabel: localize('notificationsToast', "Notification Toast") });
|
||||
const notificationList = this.instantiationService.createInstance(NotificationsList, notificationToastContainer, {
|
||||
ariaLabel: localize('notificationsToast', "Notification Toast"),
|
||||
verticalScrollMode: ScrollbarVisibility.Hidden
|
||||
});
|
||||
itemDisposeables.push(notificationList);
|
||||
this.mapNotificationToToast.set(item, { list: notificationList, container: notificationToastContainer, disposeables: itemDisposeables });
|
||||
|
||||
@@ -299,7 +303,7 @@ export class NotificationsToasts extends Themable {
|
||||
protected updateStyles(): void {
|
||||
this.mapNotificationToToast.forEach(toast => {
|
||||
const widgetShadowColor = this.getColor(widgetShadow);
|
||||
toast.container.style.boxShadow = widgetShadowColor ? `0 2px 8px ${widgetShadowColor}` : null;
|
||||
toast.container.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : null;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -42,11 +42,7 @@ export class NotificationsListDelegate implements IDelegate<INotificationViewIte
|
||||
|
||||
private createOffsetHelper(container: HTMLElement): HTMLElement {
|
||||
const offsetHelper = document.createElement('div');
|
||||
offsetHelper.style.opacity = '0';
|
||||
offsetHelper.style.position = 'absolute'; // do not mess with the visual layout
|
||||
offsetHelper.style.width = '100%'; // ensure to fill contauner to measure true width
|
||||
offsetHelper.style.overflow = 'hidden'; // do not overflow
|
||||
offsetHelper.style.whiteSpace = 'nowrap'; // do not wrap to measure true width
|
||||
addClass(offsetHelper, 'notification-offset-helper');
|
||||
|
||||
container.appendChild(offsetHelper);
|
||||
|
||||
@@ -63,7 +59,7 @@ export class NotificationsListDelegate implements IDelegate<INotificationViewIte
|
||||
}
|
||||
|
||||
// Dynamic height: if message overflows
|
||||
const preferredMessageHeight = this.computePreferredRows(notification) * NotificationsListDelegate.LINE_HEIGHT;
|
||||
const preferredMessageHeight = this.computePreferredHeight(notification);
|
||||
const messageOverflows = NotificationsListDelegate.LINE_HEIGHT < preferredMessageHeight;
|
||||
if (messageOverflows) {
|
||||
const overflow = preferredMessageHeight - NotificationsListDelegate.LINE_HEIGHT;
|
||||
@@ -75,26 +71,28 @@ export class NotificationsListDelegate implements IDelegate<INotificationViewIte
|
||||
expandedHeight += NotificationsListDelegate.ROW_HEIGHT;
|
||||
}
|
||||
|
||||
// If the expanded height is same as collapsed, unset the expanded state
|
||||
// but skip events because there is no change that has visual impact
|
||||
if (expandedHeight === NotificationsListDelegate.ROW_HEIGHT) {
|
||||
notification.collapse(true /* skip events, no change in height */);
|
||||
}
|
||||
|
||||
return expandedHeight;
|
||||
}
|
||||
|
||||
private computePreferredRows(notification: INotificationViewItem): number {
|
||||
private computePreferredHeight(notification: INotificationViewItem): number {
|
||||
|
||||
// Render message markdown into offset helper
|
||||
const renderedMessage = NotificationMessageMarkdownRenderer.render(notification.message);
|
||||
this.offsetHelper.appendChild(renderedMessage);
|
||||
|
||||
// Compute message width taking overflow into account
|
||||
const messageWidth = Math.max(renderedMessage.scrollWidth, renderedMessage.offsetWidth);
|
||||
|
||||
// One row per exceeding the total width of the container
|
||||
const availableWidth = this.offsetHelper.offsetWidth - (20 /* paddings */ + 22 /* severity */ + (24 * 3) /* toolbar */);
|
||||
const preferredRows = Math.ceil(messageWidth / availableWidth);
|
||||
// Compute height
|
||||
const preferredHeight = Math.max(this.offsetHelper.offsetHeight, this.offsetHelper.scrollHeight);
|
||||
|
||||
// Always clear offset helper after use
|
||||
clearNode(this.offsetHelper);
|
||||
|
||||
return preferredRows;
|
||||
return preferredHeight;
|
||||
}
|
||||
|
||||
public getTemplateId(element: INotificationViewItem): string {
|
||||
|
||||
@@ -7,12 +7,11 @@ import 'vs/css!./media/sidebarpart';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import nls = require('vs/nls');
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { CompositePart } from 'vs/workbench/browser/parts/compositePart';
|
||||
import { Viewlet, ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IPartService, Parts, Position as SideBarPosition } from 'vs/workbench/services/part/common/partService';
|
||||
import { IViewlet } from 'vs/workbench/common/viewlet';
|
||||
@@ -26,7 +25,6 @@ import Event from 'vs/base/common/event';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { SIDE_BAR_TITLE_FOREGROUND, SIDE_BAR_BACKGROUND, SIDE_BAR_FOREGROUND, SIDE_BAR_BORDER } from 'vs/workbench/common/theme';
|
||||
import { ToggleSidebarVisibilityAction } from 'vs/workbench/browser/actions/toggleSidebarVisibility';
|
||||
import { Dimension } from 'vs/base/browser/builder';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
@@ -134,25 +132,6 @@ export class SidebarPart extends CompositePart<Viewlet> {
|
||||
|
||||
return super.layout(dimension);
|
||||
}
|
||||
|
||||
protected getTitleAreaContextMenuActions(): IAction[] {
|
||||
const contextMenuActions = super.getTitleAreaContextMenuActions();
|
||||
if (contextMenuActions.length) {
|
||||
contextMenuActions.push(new Separator());
|
||||
}
|
||||
contextMenuActions.push(this.createHideSideBarAction());
|
||||
return contextMenuActions;
|
||||
}
|
||||
|
||||
private createHideSideBarAction(): IAction {
|
||||
return <IAction>{
|
||||
id: ToggleSidebarVisibilityAction.ID,
|
||||
label: nls.localize('compositePart.hideSideBarLabel', "Hide Side Bar"),
|
||||
enabled: true,
|
||||
run: () => this.partService.setSideBarHidden(true)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FocusSideBarAction extends Action {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
height: 22px;
|
||||
font-size: 12px;
|
||||
padding: 0 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.statusbar > .statusbar-item {
|
||||
@@ -19,6 +18,21 @@
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.statusbar > .statusbar-item.has-beak {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.statusbar > .statusbar-item.has-beak:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 11px;
|
||||
top: -5px;
|
||||
border-bottom-width: 5px;
|
||||
border-bottom-style: solid;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.statusbar > .statusbar-item.left > :first-child {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/
|
||||
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { isThemeColor } from 'vs/editor/common/editorCommon';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { addClass, EventHelper } from 'vs/base/browser/dom';
|
||||
import { addClass, EventHelper, createStyleSheet } from 'vs/base/browser/dom';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
export class StatusbarPart extends Part implements IStatusbarService {
|
||||
@@ -42,6 +42,8 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
private statusItemsContainer: Builder;
|
||||
private statusMsgDispose: IDisposable;
|
||||
|
||||
private styleElement: HTMLStyleElement;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@@ -60,7 +62,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
public addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IDisposable {
|
||||
|
||||
// Render entry in status bar
|
||||
const el = this.doCreateStatusItem(alignment, priority);
|
||||
const el = this.doCreateStatusItem(alignment, priority, entry.showBeak ? 'has-beak' : void 0);
|
||||
const item = this.instantiationService.createInstance(StatusBarEntryItem, entry);
|
||||
const toDispose = item.render(el);
|
||||
|
||||
@@ -140,18 +142,31 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
|
||||
const container = this.getContainer();
|
||||
|
||||
// Background colors
|
||||
const backgroundColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BACKGROUND : STATUS_BAR_NO_FOLDER_BACKGROUND);
|
||||
container.style('background-color', backgroundColor);
|
||||
container.style('color', this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND));
|
||||
container.style('background-color', this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BACKGROUND : STATUS_BAR_NO_FOLDER_BACKGROUND));
|
||||
|
||||
// Border color
|
||||
const borderColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_BORDER : STATUS_BAR_NO_FOLDER_BORDER) || this.getColor(contrastBorder);
|
||||
container.style('border-top-width', borderColor ? '1px' : null);
|
||||
container.style('border-top-style', borderColor ? 'solid' : null);
|
||||
container.style('border-top-color', borderColor);
|
||||
|
||||
// Notification Beak
|
||||
if (!this.styleElement) {
|
||||
this.styleElement = createStyleSheet(container.getHTMLElement());
|
||||
}
|
||||
|
||||
this.styleElement.innerHTML = `.monaco-workbench > .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor}; }`;
|
||||
}
|
||||
|
||||
private doCreateStatusItem(alignment: StatusbarAlignment, priority: number = 0): HTMLElement {
|
||||
private doCreateStatusItem(alignment: StatusbarAlignment, priority: number = 0, extraClass?: string): HTMLElement {
|
||||
const el = document.createElement('div');
|
||||
addClass(el, 'statusbar-item');
|
||||
if (extraClass) {
|
||||
addClass(el, extraClass);
|
||||
}
|
||||
|
||||
if (alignment === StatusbarAlignment.RIGHT) {
|
||||
addClass(el, 'right');
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ColorIdentifier, contrastBorder } from 'vs/platform/theme/common/colorR
|
||||
import { attachStyler, IColorMapping, IThemable } from 'vs/platform/theme/common/styler';
|
||||
import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND, SIDE_BAR_SECTION_HEADER_FOREGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { Dimension, Builder } from 'vs/base/browser/builder';
|
||||
import { append, $, trackFocus, toggleClass } from 'vs/base/browser/dom';
|
||||
import { append, $, trackFocus, toggleClass, EventType, isAncestor } from 'vs/base/browser/dom';
|
||||
import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { firstIndex } from 'vs/base/common/arrays';
|
||||
import { IAction, IActionRunner } from 'vs/base/common/actions';
|
||||
@@ -26,6 +26,8 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { PanelView, IPanelViewOptions, IPanelOptions, Panel } from 'vs/base/browser/ui/splitview/panelview';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
|
||||
export interface IPanelColors extends IColorMapping {
|
||||
dropBackground?: ColorIdentifier;
|
||||
@@ -165,10 +167,12 @@ export class PanelViewlet extends Viewlet {
|
||||
constructor(
|
||||
id: string,
|
||||
private options: IViewsViewletOptions,
|
||||
@IPartService partService: IPartService,
|
||||
@IContextMenuService protected contextMenuService: IContextMenuService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IThemeService themeService: IThemeService
|
||||
) {
|
||||
super(id, telemetryService, themeService);
|
||||
super(id, partService, telemetryService, themeService);
|
||||
}
|
||||
|
||||
async create(parent: Builder): TPromise<void> {
|
||||
@@ -176,7 +180,26 @@ export class PanelViewlet extends Viewlet {
|
||||
|
||||
const container = parent.getHTMLElement();
|
||||
this.panelview = this._register(new PanelView(container, this.options));
|
||||
this.panelview.onDidDrop(({ from, to }) => this.movePanel(from as ViewletPanel, to as ViewletPanel));
|
||||
this._register(this.panelview.onDidDrop(({ from, to }) => this.movePanel(from as ViewletPanel, to as ViewletPanel)));
|
||||
this._register(parent.on(EventType.CONTEXT_MENU, (e: MouseEvent) => this.showContextMenu(new StandardMouseEvent(e))));
|
||||
}
|
||||
|
||||
private showContextMenu(event: StandardMouseEvent): void {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
for (const panelItem of this.panelItems) {
|
||||
// Do not show context menu if requested from inside panel views
|
||||
if (isAncestor(event.target, panelItem.panel.element)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let anchor: { x: number, y: number } = { x: event.posx, y: event.posy };
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => TPromise.as(this.getContextMenuActions())
|
||||
});
|
||||
}
|
||||
|
||||
getTitle(): string {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
@@ -11,7 +10,7 @@ import { $, Dimension, Builder } from 'vs/base/browser/builder';
|
||||
import { Scope } from 'vs/workbench/common/memento';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IAction, IActionRunner } from 'vs/base/common/actions';
|
||||
import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { firstIndex } from 'vs/base/common/arrays';
|
||||
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
@@ -31,6 +30,8 @@ import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/th
|
||||
import { ITreeConfiguration, ITreeOptions } from 'vs/base/parts/tree/browser/tree';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export interface IViewOptions extends IPanelOptions {
|
||||
id: string;
|
||||
@@ -200,6 +201,7 @@ export class ViewsViewlet extends PanelViewlet implements IViewsViewlet {
|
||||
id: string,
|
||||
private location: ViewLocation,
|
||||
private showHeaderInTitleWhenSingleView: boolean,
|
||||
@IPartService partService: IPartService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService protected storageService: IStorageService,
|
||||
@IInstantiationService protected instantiationService: IInstantiationService,
|
||||
@@ -208,7 +210,7 @@ export class ViewsViewlet extends PanelViewlet implements IViewsViewlet {
|
||||
@IContextMenuService protected contextMenuService: IContextMenuService,
|
||||
@IExtensionService protected extensionService: IExtensionService
|
||||
) {
|
||||
super(id, { showHeaderInTitleWhenSingleView, dnd: true }, telemetryService, themeService);
|
||||
super(id, { showHeaderInTitleWhenSingleView, dnd: true }, partService, contextMenuService, telemetryService, themeService);
|
||||
|
||||
this.viewletSettings = this.getMemento(storageService, Scope.WORKSPACE);
|
||||
}
|
||||
@@ -232,7 +234,8 @@ export class ViewsViewlet extends PanelViewlet implements IViewsViewlet {
|
||||
}
|
||||
|
||||
getContextMenuActions(): IAction[] {
|
||||
return this.getViewDescriptorsFromRegistry(true)
|
||||
const result: IAction[] = [];
|
||||
const viewToggleActions = this.getViewDescriptorsFromRegistry(true)
|
||||
.filter(viewDescriptor => viewDescriptor.canToggleVisibility && this.contextKeyService.contextMatchesRules(viewDescriptor.when))
|
||||
.map(viewDescriptor => (<IAction>{
|
||||
id: `${viewDescriptor.id}.toggleVisibility`,
|
||||
@@ -241,6 +244,13 @@ export class ViewsViewlet extends PanelViewlet implements IViewsViewlet {
|
||||
enabled: true,
|
||||
run: () => this.toggleViewVisibility(viewDescriptor.id)
|
||||
}));
|
||||
result.push(...viewToggleActions);
|
||||
const parentActions = super.getContextMenuActions();
|
||||
if (viewToggleActions.length && parentActions.length) {
|
||||
result.push(new Separator());
|
||||
}
|
||||
result.push(...parentActions);
|
||||
return result;
|
||||
}
|
||||
|
||||
setVisible(visible: boolean): TPromise<void> {
|
||||
@@ -481,9 +491,7 @@ export class ViewsViewlet extends PanelViewlet implements IViewsViewlet {
|
||||
this.viewHeaderContextMenuListeners.push(DOM.addDisposableListener(view.draggableElement, DOM.EventType.CONTEXT_MENU, e => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (viewDescriptor.canToggleVisibility) {
|
||||
this.onContextMenu(new StandardMouseEvent(e), view);
|
||||
}
|
||||
this.onContextMenu(new StandardMouseEvent(e), viewDescriptor);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -498,19 +506,26 @@ export class ViewsViewlet extends PanelViewlet implements IViewsViewlet {
|
||||
}
|
||||
}
|
||||
|
||||
private onContextMenu(event: StandardMouseEvent, view: ViewsViewletPanel): void {
|
||||
private onContextMenu(event: StandardMouseEvent, viewDescriptor: IViewDescriptor): void {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
const actions: IAction[] = [];
|
||||
actions.push(<IAction>{
|
||||
id: `${viewDescriptor.id}.removeView`,
|
||||
label: localize('hideView', "Hide"),
|
||||
enabled: viewDescriptor.canToggleVisibility,
|
||||
run: () => this.toggleViewVisibility(viewDescriptor.id)
|
||||
});
|
||||
const otherActions = this.getContextMenuActions();
|
||||
if (otherActions.length) {
|
||||
actions.push(...[new Separator(), ...otherActions]);
|
||||
}
|
||||
|
||||
let anchor: { x: number, y: number } = { x: event.posx, y: event.posy };
|
||||
this.contextMenuService.showContextMenu({
|
||||
getAnchor: () => anchor,
|
||||
getActions: () => TPromise.as([<IAction>{
|
||||
id: `${view.id}.removeView`,
|
||||
label: nls.localize('hideView', "Hide"),
|
||||
enabled: true,
|
||||
run: () => this.toggleViewVisibility(view.id)
|
||||
}]),
|
||||
getActions: () => TPromise.as(actions)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -610,6 +625,7 @@ export class PersistentViewsViewlet extends ViewsViewlet {
|
||||
location: ViewLocation,
|
||||
private readonly viewletStateStorageId: string,
|
||||
showHeaderInTitleWhenSingleView: boolean,
|
||||
@IPartService partService: IPartService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@@ -619,7 +635,7 @@ export class PersistentViewsViewlet extends ViewsViewlet {
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IExtensionService extensionService: IExtensionService
|
||||
) {
|
||||
super(id, location, showHeaderInTitleWhenSingleView, telemetryService, storageService, instantiationService, themeService, contextKeyService, contextMenuService, extensionService);
|
||||
super(id, location, showHeaderInTitleWhenSingleView, partService, telemetryService, storageService, instantiationService, themeService, contextKeyService, contextMenuService, extensionService);
|
||||
this.hiddenViewsStorageId = `${this.viewletStateStorageId}.hidden`;
|
||||
this._register(this.onDidChangeViewVisibilityState(id => this.onViewVisibilityChanged(id)));
|
||||
}
|
||||
|
||||
@@ -7,19 +7,40 @@ import nls = require('vs/nls');
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import DOM = require('vs/base/browser/dom');
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { ITree } from 'vs/base/parts/tree/browser/tree';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IViewlet } from 'vs/workbench/common/viewlet';
|
||||
import { Composite, CompositeDescriptor, CompositeRegistry } from 'vs/workbench/browser/composite';
|
||||
import { IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ToggleSidebarVisibilityAction } from 'vs/workbench/browser/actions/toggleSidebarVisibility';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
export abstract class Viewlet extends Composite implements IViewlet {
|
||||
|
||||
constructor(id: string,
|
||||
private partService: IPartService,
|
||||
telemetryService: ITelemetryService,
|
||||
themeService: IThemeService
|
||||
) {
|
||||
super(id, telemetryService, themeService);
|
||||
}
|
||||
|
||||
public getOptimalWidth(): number {
|
||||
return null;
|
||||
}
|
||||
|
||||
public getContextMenuActions(): IAction[] {
|
||||
return [<IAction>{
|
||||
id: ToggleSidebarVisibilityAction.ID,
|
||||
label: nls.localize('compositePart.hideSideBarLabel', "Hide Side Bar"),
|
||||
enabled: true,
|
||||
run: () => this.partService.setSideBarHidden(true)
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -197,7 +197,7 @@ export interface INotificationViewItem {
|
||||
readonly onDidLabelChange: Event<INotificationViewItemLabelChangeEvent>;
|
||||
|
||||
expand(): void;
|
||||
collapse(): void;
|
||||
collapse(skipEvents?: boolean): void;
|
||||
toggle(): void;
|
||||
|
||||
hasProgress(): boolean;
|
||||
@@ -494,13 +494,16 @@ export class NotificationViewItem implements INotificationViewItem {
|
||||
this._onDidExpansionChange.fire();
|
||||
}
|
||||
|
||||
public collapse(): void {
|
||||
public collapse(skipEvents?: boolean): void {
|
||||
if (!this._expanded || !this.canCollapse) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._expanded = false;
|
||||
this._onDidExpansionChange.fire();
|
||||
|
||||
if (!skipEvents) {
|
||||
this._onDidExpansionChange.fire();
|
||||
}
|
||||
}
|
||||
|
||||
public toggle(): void {
|
||||
|
||||
@@ -555,6 +555,24 @@ export class ReloadWindowAction extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
export class ReloadWindowWithExtensionsDisabledAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.action.reloadWindowWithExtensionsDisabled';
|
||||
static LABEL = nls.localize('reloadWindowWithExntesionsDisabled', "Reload Window With Extensions Disabled");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IWindowService private windowService: IWindowService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
run(): TPromise<boolean> {
|
||||
return this.windowService.reloadWindow({ _: [], 'disable-extensions': true }).then(() => true);
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class BaseSwitchWindow extends Action {
|
||||
private closeWindowAction: CloseWindowAction;
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ import { MenuService } from 'vs/platform/actions/common/menuService';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
||||
import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar } from 'vs/workbench/electron-browser/actions';
|
||||
import { OpenRecentAction, ToggleDevToolsAction, ReloadWindowAction, ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar, ReloadWindowWithExtensionsDisabledAction } from 'vs/workbench/electron-browser/actions';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
|
||||
import { WorkspaceEditingService } from 'vs/workbench/services/workspace/node/workspaceEditingService';
|
||||
@@ -207,7 +207,7 @@ export class Workbench implements IPartService {
|
||||
private sideBarPosition: Position;
|
||||
private panelPosition: Position;
|
||||
private panelHidden: boolean;
|
||||
private editorBackgroundDelayer: Delayer<void>;
|
||||
private editorBackgroundDelayer: Delayer<any>;
|
||||
private closeEmptyWindowScheduler: RunOnceScheduler;
|
||||
private editorsVisibleContext: IContextKey<boolean>;
|
||||
private inZenMode: IContextKey<boolean>;
|
||||
@@ -418,7 +418,7 @@ export class Workbench implements IPartService {
|
||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyCode.KEY_R } : void 0), 'Reload Window');
|
||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_I } } : void 0), 'Developer: Toggle Developer Tools', localize('developer', "Developer"));
|
||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: isDeveloping ? null : KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', localize('file', "File"));
|
||||
|
||||
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Reload Window Without Extensions');
|
||||
// Actions for macOS native tabs management (only when enabled)
|
||||
const windowConfig = this.configurationService.getValue<IWindowConfiguration>();
|
||||
if (windowConfig && windowConfig.window && windowConfig.window.nativeTabs) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import { ViewLocation } from 'vs/workbench/common/views';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
|
||||
export class DebugViewlet extends PersistentViewsViewlet {
|
||||
|
||||
@@ -35,6 +36,7 @@ export class DebugViewlet extends PersistentViewsViewlet {
|
||||
private panelListeners = new Map<string, IDisposable>();
|
||||
|
||||
constructor(
|
||||
@IPartService partService: IPartService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IProgressService private progressService: IProgressService,
|
||||
@IDebugService private debugService: IDebugService,
|
||||
@@ -46,7 +48,7 @@ export class DebugViewlet extends PersistentViewsViewlet {
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IExtensionService extensionService: IExtensionService
|
||||
) {
|
||||
super(VIEWLET_ID, ViewLocation.Debug, `${VIEWLET_ID}.state`, false, telemetryService, storageService, instantiationService, themeService, contextService, contextKeyService, contextMenuService, extensionService);
|
||||
super(VIEWLET_ID, ViewLocation.Debug, `${VIEWLET_ID}.state`, false, partService, telemetryService, storageService, instantiationService, themeService, contextService, contextKeyService, contextMenuService, extensionService);
|
||||
|
||||
this.progressRunner = null;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IPartService, Parts } from 'vs/workbench/services/part/common/partServi
|
||||
import { IDebugService, State } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_BACKGROUND, Themable, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_BORDER } from 'vs/workbench/common/theme';
|
||||
import { addClass, removeClass } from 'vs/base/browser/dom';
|
||||
import { addClass, removeClass, createStyleSheet } from 'vs/base/browser/dom';
|
||||
|
||||
// colors for theming
|
||||
|
||||
@@ -34,6 +34,7 @@ export const STATUS_BAR_DEBUGGING_BORDER = registerColor('statusBar.debuggingBor
|
||||
}, localize('statusBarDebuggingBorder', "Status bar border color separating to the sidebar and editor when a program is being debugged. The status bar is shown in the bottom of the window"));
|
||||
|
||||
export class StatusBarColorProvider extends Themable implements IWorkbenchContribution {
|
||||
private styleElement: HTMLStyleElement;
|
||||
|
||||
constructor(
|
||||
@IThemeService themeService: IThemeService,
|
||||
@@ -61,13 +62,23 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri
|
||||
removeClass(container, 'debugging');
|
||||
}
|
||||
|
||||
container.style.backgroundColor = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_DEBUGGING_BACKGROUND, STATUS_BAR_BACKGROUND));
|
||||
// Container Colors
|
||||
const backgroundColor = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_DEBUGGING_BACKGROUND, STATUS_BAR_BACKGROUND));
|
||||
container.style.backgroundColor = backgroundColor;
|
||||
container.style.color = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_DEBUGGING_FOREGROUND, STATUS_BAR_FOREGROUND));
|
||||
|
||||
// Border Color
|
||||
const borderColor = this.getColor(this.getColorKey(STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_DEBUGGING_BORDER, STATUS_BAR_BORDER)) || this.getColor(contrastBorder);
|
||||
container.style.borderTopWidth = borderColor ? '1px' : null;
|
||||
container.style.borderTopStyle = borderColor ? 'solid' : null;
|
||||
container.style.borderTopColor = borderColor;
|
||||
|
||||
// Notification Beak
|
||||
if (!this.styleElement) {
|
||||
this.styleElement = createStyleSheet(container);
|
||||
}
|
||||
|
||||
this.styleElement.innerHTML = `.monaco-workbench > .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor} !important; }`;
|
||||
}
|
||||
|
||||
private getColorKey(noFolderColor: string, debuggingColor: string, normalColor: string): string {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { IAction } from 'vs/base/common/actions';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { isFullWidthCharacter, removeAnsiEscapeCodes, endsWith } from 'vs/base/common/strings';
|
||||
import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
@@ -23,6 +23,7 @@ import { CopyAction, CopyAllAction } from 'vs/workbench/parts/debug/electron-bro
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { LinkDetector } from 'vs/workbench/parts/debug/browser/linkDetector';
|
||||
import { CollapseAction } from 'vs/workbench/browser/viewlet';
|
||||
|
||||
const $ = dom.$;
|
||||
|
||||
@@ -437,6 +438,8 @@ export class ReplExpressionsActionProvider implements IActionProvider {
|
||||
const actions: IAction[] = [];
|
||||
actions.push(new CopyAction(CopyAction.ID, CopyAction.LABEL));
|
||||
actions.push(new CopyAllAction(CopyAllAction.ID, CopyAllAction.LABEL, tree));
|
||||
actions.push(new CollapseAction(tree, true, 'explore-action collapse-all'));
|
||||
actions.push(new Separator());
|
||||
actions.push(this.instantiationService.createInstance(ClearReplAction, ClearReplAction.ID, ClearReplAction.LABEL));
|
||||
|
||||
return TPromise.as(actions);
|
||||
|
||||
@@ -56,12 +56,17 @@ export class TerminalSupport {
|
||||
const result = cp.spawnSync('wmic', ['process', 'get', 'ParentProcessId']);
|
||||
if (result.stdout) {
|
||||
const pids = result.stdout.toString().split('\r\n');
|
||||
return pids.some(p => parseInt(p) === t.processId);
|
||||
if (!pids.some(p => parseInt(p) === t.processId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const result = cp.spawnSync('/usr/bin/pgrep', ['-P', String(t.processId)]);
|
||||
const result = cp.spawnSync('/usr/bin/pgrep', ['-lP', String(t.processId)]);
|
||||
if (result.stdout) {
|
||||
return result.stdout.toString().trim().length > 0;
|
||||
const r = result.stdout.toString().trim();
|
||||
if (r.length === 0 || r.indexOf(' tmux') >= 0) { // ignore 'tmux'; see #43683
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ import { Color } from 'vs/base/common/color';
|
||||
import { WorkbenchTree } from 'vs/platform/list/browser/listService';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { assign } from 'vs/base/common/objects';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
|
||||
/** A context key that is set when an extension editor webview has focus. */
|
||||
@@ -183,19 +182,18 @@ export class ExtensionEditor extends BaseEditor {
|
||||
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IViewletService private viewletService: IViewletService,
|
||||
@IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@IViewletService private readonly viewletService: IViewletService,
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IThemeService protected themeService: IThemeService,
|
||||
@IKeybindingService private keybindingService: IKeybindingService,
|
||||
@INotificationService private notificationService: INotificationService,
|
||||
@IOpenerService private openerService: IOpenerService,
|
||||
@IPartService private partService: IPartService,
|
||||
@IContextViewService private contextViewService: IContextViewService,
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@IExtensionTipsService private extensionTipsService: IExtensionTipsService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
@IPartService private readonly partService: IPartService,
|
||||
@IContextViewService private readonly contextViewService: IContextViewService,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService
|
||||
|
||||
) {
|
||||
super(ExtensionEditor.ID, telemetryService, themeService);
|
||||
@@ -421,11 +419,9 @@ export class ExtensionEditor extends BaseEditor {
|
||||
.then<void>(body => {
|
||||
const allowedBadgeProviders = this.extensionsWorkbenchService.allowedBadgeProviders;
|
||||
const webViewOptions = allowedBadgeProviders.length > 0 ? { allowScripts: false, allowSvgs: false, svgWhiteList: allowedBadgeProviders } : {};
|
||||
this.activeWebview = new Webview(this.content, this.partService.getContainer(Parts.EDITOR_PART), this.environmentService, this.contextService, this.contextViewService, this.contextKey, this.findInputFocusContextKey, webViewOptions, false);
|
||||
this.activeWebview = new Webview(this.content, this.partService.getContainer(Parts.EDITOR_PART), this.themeService, this.environmentService, this.contextViewService, this.contextKey, this.findInputFocusContextKey, webViewOptions);
|
||||
const removeLayoutParticipant = arrays.insert(this.layoutParticipants, this.activeWebview);
|
||||
this.contentDisposables.push(toDisposable(removeLayoutParticipant));
|
||||
|
||||
this.activeWebview.style(this.themeService.getTheme());
|
||||
this.activeWebview.contents = body;
|
||||
|
||||
this.activeWebview.onDidClickLink(link => {
|
||||
@@ -434,7 +430,6 @@ export class ExtensionEditor extends BaseEditor {
|
||||
this.openerService.open(link);
|
||||
}
|
||||
}, null, this.contentDisposables);
|
||||
this.themeService.onThemeChange(theme => this.activeWebview.style(theme), null, this.contentDisposables);
|
||||
this.contentDisposables.push(this.activeWebview);
|
||||
})
|
||||
.then(null, () => {
|
||||
|
||||
@@ -1601,7 +1601,7 @@ export class DisableAllAction extends Action {
|
||||
}
|
||||
|
||||
run(): TPromise<any> {
|
||||
return TPromise.join(this.extensionsWorkbenchService.local.map(e => this.extensionsWorkbenchService.setEnablement(e, EnablementState.Disabled)));
|
||||
return TPromise.join(this.extensionsWorkbenchService.local.filter(e => e.type === LocalExtensionType.User).map(e => this.extensionsWorkbenchService.setEnablement(e, EnablementState.Disabled)));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -1633,7 +1633,7 @@ export class DisableAllWorkpsaceAction extends Action {
|
||||
}
|
||||
|
||||
run(): TPromise<any> {
|
||||
return TPromise.join(this.extensionsWorkbenchService.local.map(e => this.extensionsWorkbenchService.setEnablement(e, EnablementState.WorkspaceDisabled)));
|
||||
return TPromise.join(this.extensionsWorkbenchService.local.filter(e => e.type === LocalExtensionType.User).map(e => this.extensionsWorkbenchService.setEnablement(e, EnablementState.WorkspaceDisabled)));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -1645,7 +1645,7 @@ export class DisableAllWorkpsaceAction extends Action {
|
||||
export class EnableAllAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.enableAll';
|
||||
static LABEL = localize('enableAll', "Enable All Installed Extensions");
|
||||
static LABEL = localize('enableAll', "Enable All Extensions");
|
||||
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
@@ -1676,7 +1676,7 @@ export class EnableAllAction extends Action {
|
||||
export class EnableAllWorkpsaceAction extends Action {
|
||||
|
||||
static readonly ID = 'workbench.extensions.action.enableAllWorkspace';
|
||||
static LABEL = localize('enableAllWorkspace', "Enable All Installed Extensions for this Workspace");
|
||||
static LABEL = localize('enableAllWorkspace', "Enable All Extensions for this Workspace");
|
||||
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IChoiceService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
|
||||
interface SearchInputEvent extends Event {
|
||||
target: HTMLInputElement;
|
||||
@@ -88,6 +89,7 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
@IPartService partService: IPartService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IProgressService private progressService: IProgressService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@@ -104,7 +106,7 @@ export class ExtensionsViewlet extends PersistentViewsViewlet implements IExtens
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IExtensionService extensionService: IExtensionService
|
||||
) {
|
||||
super(VIEWLET_ID, ViewLocation.Extensions, `${VIEWLET_ID}.state`, true, telemetryService, storageService, instantiationService, themeService, contextService, contextKeyService, contextMenuService, extensionService);
|
||||
super(VIEWLET_ID, ViewLocation.Extensions, `${VIEWLET_ID}.state`, true, partService, telemetryService, storageService, instantiationService, themeService, contextService, contextKeyService, contextMenuService, extensionService);
|
||||
|
||||
this.registerViews();
|
||||
this.searchDelayer = new ThrottledDelayer(500);
|
||||
|
||||
@@ -27,10 +27,6 @@
|
||||
height: calc(100% - 38px);
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .extensions-list > .monaco-list {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.extensions-viewlet > .extensions .list-actionbar-container .monaco-action-bar .action-item > .octicon {
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
|
||||
@@ -34,6 +34,7 @@ import { ViewsRegistry, ViewLocation, IViewDescriptor } from 'vs/workbench/commo
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
|
||||
|
||||
export class ExplorerViewletViewsContribution extends Disposable implements IWorkbenchContribution {
|
||||
@@ -150,6 +151,7 @@ export class ExplorerViewlet extends PersistentViewsViewlet implements IExplorer
|
||||
private viewletVisibleContextKey: IContextKey<boolean>;
|
||||
|
||||
constructor(
|
||||
@IPartService partService: IPartService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IWorkspaceContextService protected contextService: IWorkspaceContextService,
|
||||
@IStorageService protected storageService: IStorageService,
|
||||
@@ -162,7 +164,7 @@ export class ExplorerViewlet extends PersistentViewsViewlet implements IExplorer
|
||||
@IContextMenuService contextMenuService: IContextMenuService,
|
||||
@IExtensionService extensionService: IExtensionService
|
||||
) {
|
||||
super(VIEWLET_ID, ViewLocation.Explorer, ExplorerViewlet.EXPLORER_VIEWS_STATE, true, telemetryService, storageService, instantiationService, themeService, contextService, contextKeyService, contextMenuService, extensionService);
|
||||
super(VIEWLET_ID, ViewLocation.Explorer, ExplorerViewlet.EXPLORER_VIEWS_STATE, true, partService, telemetryService, storageService, instantiationService, themeService, contextService, contextKeyService, contextMenuService, extensionService);
|
||||
|
||||
this.viewletState = new FileViewletState();
|
||||
this.viewletVisibleContextKey = ExplorerViewletVisibleContext.bindTo(contextKeyService);
|
||||
|
||||
@@ -799,11 +799,15 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop {
|
||||
|
||||
// In-Explorer DND
|
||||
else {
|
||||
const sources: FileStat[] = data.getData();
|
||||
if (target instanceof Model) {
|
||||
if (sources.length === 1 && sources[0].isRoot) {
|
||||
return DRAG_OVER_ACCEPT_BUBBLE_DOWN(false);
|
||||
}
|
||||
|
||||
return DRAG_OVER_REJECT;
|
||||
}
|
||||
|
||||
const sources: FileStat[] = data.getData();
|
||||
if (!Array.isArray(sources)) {
|
||||
return DRAG_OVER_REJECT;
|
||||
}
|
||||
@@ -864,9 +868,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop {
|
||||
|
||||
// In-Explorer DND (Move/Copy file)
|
||||
else {
|
||||
if (target instanceof FileStat) {
|
||||
promise = this.handleExplorerDrop(tree, data, target, originalEvent);
|
||||
}
|
||||
promise = this.handleExplorerDrop(tree, data, target, originalEvent);
|
||||
}
|
||||
|
||||
promise.done(null, errors.onUnexpectedError);
|
||||
@@ -915,7 +917,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop {
|
||||
});
|
||||
}
|
||||
|
||||
private handleExplorerDrop(tree: ITree, data: IDragAndDropData, target: FileStat, originalEvent: DragMouseEvent): TPromise<void> {
|
||||
private handleExplorerDrop(tree: ITree, data: IDragAndDropData, target: FileStat | Model, originalEvent: DragMouseEvent): TPromise<void> {
|
||||
const sources: FileStat[] = distinctParents(data.getData(), s => s.resource);
|
||||
const isCopy = (originalEvent.ctrlKey && !isMacintosh) || (originalEvent.altKey && isMacintosh);
|
||||
|
||||
@@ -955,19 +957,20 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop {
|
||||
});
|
||||
}
|
||||
|
||||
private doHandleExplorerDrop(tree: ITree, source: FileStat, target: FileStat, isCopy: boolean): TPromise<void> {
|
||||
private doHandleExplorerDrop(tree: ITree, source: FileStat, target: FileStat | Model, isCopy: boolean): TPromise<void> {
|
||||
return tree.expand(target).then(() => {
|
||||
if (source.isRoot) {
|
||||
const folders = this.contextService.getWorkspace().folders;
|
||||
let sourceIndex: number;
|
||||
let targetIndex: number;
|
||||
const workspaceCreationData: IWorkspaceFolderCreationData[] = [];
|
||||
const targetUri = target instanceof FileStat ? target.resource : folders[folders.length - 1].uri;
|
||||
|
||||
for (let index = 0; index < folders.length; index++) {
|
||||
if (folders[index].uri.toString() === source.resource.toString()) {
|
||||
sourceIndex = index;
|
||||
}
|
||||
if (folders[index].uri.toString() === target.resource.toString()) {
|
||||
if (folders[index].uri.toString() === targetUri.toString()) {
|
||||
targetIndex = index;
|
||||
}
|
||||
workspaceCreationData.push({
|
||||
@@ -1004,6 +1007,9 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop {
|
||||
|
||||
return TPromise.join(dirtyMoved.map(d => this.backupFileService.discardResourceBackup(d)));
|
||||
};
|
||||
if (!(target instanceof FileStat)) {
|
||||
return TPromise.as(void 0);
|
||||
}
|
||||
|
||||
// 1. check for dirty files that are being moved and backup to new target
|
||||
const dirty = this.textFileService.getDirty().filter(d => resources.isEqualOrParent(d, source.resource, !isLinux /* ignorecase */));
|
||||
|
||||
@@ -16,7 +16,6 @@ import { HtmlPreviewPart } from 'vs/workbench/parts/html/browser/htmlPreviewPart
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
|
||||
import { MenuRegistry } from 'vs/platform/actions/common/actions';
|
||||
import { IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/common/extensions';
|
||||
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
|
||||
|
||||
@@ -31,6 +30,7 @@ function getActivePreviewsForResource(accessor: ServicesAccessor, resource: URI
|
||||
}
|
||||
|
||||
// --- Register Editor
|
||||
|
||||
(<IEditorRegistry>Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor(
|
||||
HtmlPreviewPart,
|
||||
HtmlPreviewPart.ID,
|
||||
@@ -39,17 +39,11 @@ function getActivePreviewsForResource(accessor: ServicesAccessor, resource: URI
|
||||
|
||||
// --- Register Commands
|
||||
|
||||
const defaultPreviewHtmlOptions: HtmlInputOptions = {
|
||||
allowScripts: true,
|
||||
allowSvgs: true
|
||||
};
|
||||
|
||||
CommandsRegistry.registerCommand('_workbench.previewHtml', function (
|
||||
accessor: ServicesAccessor,
|
||||
resource: URI | string,
|
||||
position?: EditorPosition,
|
||||
label?: string,
|
||||
options?: HtmlInputOptions
|
||||
label?: string
|
||||
) {
|
||||
const uri = resource instanceof URI ? resource : URI.parse(resource);
|
||||
label = label || uri.fsPath;
|
||||
@@ -66,9 +60,13 @@ CommandsRegistry.registerCommand('_workbench.previewHtml', function (
|
||||
}
|
||||
}
|
||||
|
||||
const inputOptions = (Object as any).assign({}, options || defaultPreviewHtmlOptions);
|
||||
const extensionsWorkbenchService = accessor.get(IExtensionsWorkbenchService);
|
||||
inputOptions.svgWhiteList = extensionsWorkbenchService.allowedBadgeProviders;
|
||||
|
||||
const inputOptions: HtmlInputOptions = {
|
||||
allowScripts: true,
|
||||
allowSvgs: true,
|
||||
svgWhiteList: extensionsWorkbenchService.allowedBadgeProviders
|
||||
};
|
||||
|
||||
// Otherwise, create new input and open it
|
||||
if (!input) {
|
||||
@@ -93,19 +91,3 @@ CommandsRegistry.registerCommand('_workbench.htmlPreview.postMessage', function
|
||||
}
|
||||
return activePreviews.length > 0;
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand('_webview.openDevTools', function () {
|
||||
const elements = document.querySelectorAll('webview.ready');
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
try {
|
||||
(elements.item(i) as Electron.WebviewTag).openDevTools();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
MenuRegistry.addCommand({
|
||||
id: '_webview.openDevTools',
|
||||
title: localize('devtools.webview', "Developer: Webview Tools")
|
||||
});
|
||||
|
||||
@@ -26,7 +26,6 @@ import { Webview, WebviewOptions } from './webview';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { WebviewEditor } from './webviewEditor';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
|
||||
/**
|
||||
@@ -55,8 +54,7 @@ export class HtmlPreviewPart extends WebviewEditor {
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
@IPartService private readonly partService: IPartService,
|
||||
@IContextViewService private readonly _contextViewService: IContextViewService,
|
||||
@IEnvironmentService private readonly _environmentService: IEnvironmentService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService
|
||||
@IEnvironmentService private readonly _environmentService: IEnvironmentService
|
||||
) {
|
||||
super(HtmlPreviewPart.ID, telemetryService, themeService, storageService, contextKeyService);
|
||||
}
|
||||
@@ -91,13 +89,15 @@ export class HtmlPreviewPart extends WebviewEditor {
|
||||
this._webview = new Webview(
|
||||
this.content,
|
||||
this.partService.getContainer(Parts.EDITOR_PART),
|
||||
this.themeService,
|
||||
this._environmentService,
|
||||
this._contextService,
|
||||
this._contextViewService,
|
||||
this.contextKey,
|
||||
this.findInputFocusContextKey,
|
||||
webviewOptions,
|
||||
true);
|
||||
{
|
||||
...webviewOptions,
|
||||
useSameOriginForRoot: true
|
||||
});
|
||||
|
||||
if (this.input && this.input instanceof HtmlInput) {
|
||||
const state = this.loadViewState(this.input.getResource());
|
||||
@@ -107,7 +107,6 @@ export class HtmlPreviewPart extends WebviewEditor {
|
||||
const resourceUri = this.input.getResource();
|
||||
this.webview.baseUrl = resourceUri.toString(true);
|
||||
}
|
||||
this.onThemeChange(this.themeService.getTheme());
|
||||
this._webviewDisposables = [
|
||||
this._webview,
|
||||
this._webview.onDidClickLink(uri => this.openerService.open(uri)),
|
||||
@@ -157,13 +156,8 @@ export class HtmlPreviewPart extends WebviewEditor {
|
||||
const { width, height } = dimension;
|
||||
this.content.style.width = `${width}px`;
|
||||
this.content.style.height = `${height}px`;
|
||||
if (this._webview) {
|
||||
this._webview.layout();
|
||||
}
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
this.webview.focus();
|
||||
super.layout(dimension);
|
||||
}
|
||||
|
||||
public clearInput(): void {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ContextKeyExpr, } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
@@ -11,10 +12,12 @@ import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/wor
|
||||
import { KEYBINDING_CONTEXT_WEBVIEWEDITOR_FIND_WIDGET_INPUT_FOCUSED, KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from './webviewEditor';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ShowWebViewEditorFindWidgetAction, ShowWebViewEditorFindTermCommand, HideWebViewEditorFindCommand } from './webviewCommands';
|
||||
import { ShowWebViewEditorFindWidgetAction, ShowWebViewEditorFindTermCommand, HideWebViewEditorFindCommand, OpenWebviewDeveloperToolsAction, ReloadWebviewAction } from './webviewCommands';
|
||||
|
||||
|
||||
const category = 'Webview';
|
||||
const webviewDeveloperCategory = nls.localize('developer', "Developer");
|
||||
|
||||
const actionRegistry = <IWorkbenchActionRegistry>Registry.as(ActionExtensions.WorkbenchActions);
|
||||
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowWebViewEditorFindWidgetAction, ShowWebViewEditorFindWidgetAction.ID, ShowWebViewEditorFindWidgetAction.LABEL, {
|
||||
@@ -52,3 +55,14 @@ const hideCommand = new HideWebViewEditorFindCommand({
|
||||
}
|
||||
});
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule(hideCommand.toCommandAndKeybindingRule(KeybindingsRegistry.WEIGHT.editorContrib()));
|
||||
|
||||
|
||||
actionRegistry.registerWorkbenchAction(
|
||||
new SyncActionDescriptor(OpenWebviewDeveloperToolsAction, OpenWebviewDeveloperToolsAction.ID, OpenWebviewDeveloperToolsAction.LABEL),
|
||||
'Webview Tools',
|
||||
webviewDeveloperCategory);
|
||||
|
||||
actionRegistry.registerWorkbenchAction(
|
||||
new SyncActionDescriptor(ReloadWebviewAction, ReloadWebviewAction.ID, ReloadWebviewAction.LABEL),
|
||||
'Reload Webview',
|
||||
webviewDeveloperCategory);
|
||||
@@ -10,20 +10,21 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { addDisposableListener, addClass } from 'vs/base/browser/dom';
|
||||
import { editorBackground, editorForeground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ITheme, LIGHT, DARK } from 'vs/platform/theme/common/themeService';
|
||||
import { ITheme, LIGHT, DARK, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { WebviewFindWidget } from './webviewFindWidget';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { normalize, nativeSep } from 'vs/base/common/paths';
|
||||
import { startsWith } from 'vs/base/common/strings';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
export interface WebviewOptions {
|
||||
readonly allowScripts?: boolean;
|
||||
readonly allowSvgs?: boolean;
|
||||
readonly svgWhiteList?: string[];
|
||||
readonly enableWrappedPostMessage?: boolean;
|
||||
readonly useSameOriginForRoot?: boolean;
|
||||
readonly localResourceRoots?: URI[];
|
||||
}
|
||||
|
||||
export class Webview {
|
||||
@@ -33,17 +34,17 @@ export class Webview {
|
||||
|
||||
private _webviewFindWidget: WebviewFindWidget;
|
||||
private _findStarted: boolean = false;
|
||||
private _contents: string = '';
|
||||
|
||||
constructor(
|
||||
private readonly parent: HTMLElement,
|
||||
private readonly _styleElement: Element,
|
||||
private readonly _themeService: IThemeService,
|
||||
private readonly _environmentService: IEnvironmentService,
|
||||
private readonly _contextService: IWorkspaceContextService,
|
||||
private readonly _contextViewService: IContextViewService,
|
||||
private readonly _contextKey: IContextKey<boolean>,
|
||||
private readonly _findInputContextKey: IContextKey<boolean>,
|
||||
private _options: WebviewOptions,
|
||||
useSameOriginForRoot: boolean
|
||||
private _options: WebviewOptions
|
||||
) {
|
||||
this._webview = document.createElement('webview');
|
||||
this._webview.setAttribute('partition', this._options.allowSvgs ? 'webview' : `webview${Date.now()}`);
|
||||
@@ -60,7 +61,7 @@ export class Webview {
|
||||
this._webview.style.outline = '0';
|
||||
|
||||
this._webview.preload = require.toUrl('./webview-pre.js');
|
||||
this._webview.src = useSameOriginForRoot ? require.toUrl('./webview.html') : 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%09%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E';
|
||||
this._webview.src = this._options.useSameOriginForRoot ? require.toUrl('./webview.html') : 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%09%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E';
|
||||
|
||||
this._ready = new Promise<this>(resolve => {
|
||||
const subscription = addDisposableListener(this._webview, 'ipc-message', (event) => {
|
||||
@@ -74,7 +75,7 @@ export class Webview {
|
||||
});
|
||||
});
|
||||
|
||||
if (!useSameOriginForRoot) {
|
||||
if (!this._options.useSameOriginForRoot) {
|
||||
let loaded = false;
|
||||
this._disposables.push(addDisposableListener(this._webview, 'did-start-loading', () => {
|
||||
if (loaded) {
|
||||
@@ -84,7 +85,6 @@ export class Webview {
|
||||
|
||||
const contents = this._webview.getWebContents();
|
||||
this.registerFileProtocols(contents);
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -167,22 +167,20 @@ export class Webview {
|
||||
if (this._contextKey) {
|
||||
this._contextKey.set(true);
|
||||
}
|
||||
this._onFocus.fire();
|
||||
}),
|
||||
addDisposableListener(this._webview, 'blur', () => {
|
||||
if (this._contextKey) {
|
||||
this._contextKey.reset();
|
||||
}
|
||||
this._onBlur.fire();
|
||||
}),
|
||||
addDisposableListener(this._webview, 'found-in-page', (event) => {
|
||||
this._onFoundInPageResults.fire(event.result);
|
||||
})
|
||||
);
|
||||
|
||||
this._webviewFindWidget = new WebviewFindWidget(this._contextViewService, this);
|
||||
this._disposables.push(this._webviewFindWidget);
|
||||
|
||||
this.style(this._themeService.getTheme());
|
||||
this._themeService.onThemeChange(this.style, this, this._disposables);
|
||||
|
||||
if (parent) {
|
||||
parent.appendChild(this._webviewFindWidget.getDomNode());
|
||||
parent.appendChild(this._webview);
|
||||
@@ -218,44 +216,36 @@ export class Webview {
|
||||
private readonly _onDidScroll = new Emitter<{ scrollYPercentage: number }>();
|
||||
public readonly onDidScroll: Event<{ scrollYPercentage: number }> = this._onDidScroll.event;
|
||||
|
||||
private readonly _onFoundInPageResults = new Emitter<Electron.FoundInPageResult>();
|
||||
public readonly onFindResults: Event<Electron.FoundInPageResult> = this._onFoundInPageResults.event;
|
||||
|
||||
private readonly _onMessage = new Emitter<any>();
|
||||
public readonly onMessage: Event<any> = this._onMessage.event;
|
||||
|
||||
private readonly _onFocus = new Emitter<void>();
|
||||
public readonly onFocus: Event<void> = this._onFocus.event;
|
||||
|
||||
private readonly _onBlur = new Emitter<void>();
|
||||
public readonly onBlur: Event<void> = this._onBlur.event;
|
||||
|
||||
private _send(channel: string, ...args: any[]): void {
|
||||
this._ready
|
||||
.then(() => this._webview.send(channel, ...args))
|
||||
.catch(err => console.error(err));
|
||||
}
|
||||
|
||||
set initialScrollProgress(value: number) {
|
||||
public set initialScrollProgress(value: number) {
|
||||
this._send('initial-scroll-position', value);
|
||||
}
|
||||
|
||||
set options(value: WebviewOptions) {
|
||||
public set options(value: WebviewOptions) {
|
||||
this._options = value;
|
||||
}
|
||||
|
||||
set contents(value: string) {
|
||||
public set contents(value: string) {
|
||||
this._contents = value;
|
||||
this._send('content', {
|
||||
contents: value,
|
||||
options: this._options
|
||||
});
|
||||
}
|
||||
|
||||
set baseUrl(value: string) {
|
||||
public set baseUrl(value: string) {
|
||||
this._send('baseUrl', value);
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
public focus(): void {
|
||||
this._webview.focus();
|
||||
this._send('focus');
|
||||
}
|
||||
@@ -270,7 +260,7 @@ export class Webview {
|
||||
});
|
||||
}
|
||||
|
||||
style(theme: ITheme): void {
|
||||
private style(theme: ITheme): void {
|
||||
const { fontFamily, fontWeight, fontSize } = window.getComputedStyle(this._styleElement); // TODO@theme avoid styleElement
|
||||
|
||||
const styles = {
|
||||
@@ -330,16 +320,16 @@ export class Webview {
|
||||
return;
|
||||
}
|
||||
|
||||
registerFileProtocol(contents, 'vscode-core-resource', [
|
||||
registerFileProtocol(contents, 'vscode-core-resource', () => [
|
||||
this._environmentService.appRoot
|
||||
]);
|
||||
registerFileProtocol(contents, 'vscode-extension-resource', [
|
||||
registerFileProtocol(contents, 'vscode-extension-resource', () => [
|
||||
this._environmentService.extensionsPath,
|
||||
this._environmentService.appRoot,
|
||||
this._environmentService.extensionDevelopmentPath
|
||||
]);
|
||||
registerFileProtocol(contents, 'vscode-workspace-resource',
|
||||
this._contextService.getWorkspace().folders.map(folder => folder.uri.fsPath)
|
||||
registerFileProtocol(contents, 'vscode-workspace-resource', () =>
|
||||
this._options.localResourceRoots.map(uri => uri.fsPath)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -361,7 +351,6 @@ export class Webview {
|
||||
|
||||
this._findStarted = true;
|
||||
this._webview.findInPage(value, findOptions);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -406,6 +395,10 @@ export class Webview {
|
||||
public showPreviousFindTerm() {
|
||||
this._webviewFindWidget.showPreviousFindTerm();
|
||||
}
|
||||
|
||||
public reload() {
|
||||
this.contents = this._contents;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -430,11 +423,11 @@ namespace ApiThemeClassName {
|
||||
function registerFileProtocol(
|
||||
contents: Electron.WebContents,
|
||||
protocol: string,
|
||||
roots: string[]
|
||||
getRoots: () => string[]
|
||||
) {
|
||||
contents.session.protocol.registerFileProtocol(protocol, (request, callback: any) => {
|
||||
const requestPath = URI.parse(request.url).fsPath;
|
||||
for (const root of roots) {
|
||||
for (const root of getRoots()) {
|
||||
const normalizedPath = normalize(requestPath, true);
|
||||
if (startsWith(normalizedPath, root + nativeSep)) {
|
||||
callback({ path: normalizedPath });
|
||||
|
||||
@@ -82,3 +82,55 @@ export class ShowWebViewEditorFindTermCommand extends Command {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class OpenWebviewDeveloperToolsAction extends Action {
|
||||
static readonly ID = 'workbench.action.webview.openDeveloperTools';
|
||||
static LABEL = nls.localize('openToolsLabel', "Webview Tools");
|
||||
|
||||
public constructor(
|
||||
id: string,
|
||||
label: string
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
const elements = document.querySelectorAll('webview.ready');
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
try {
|
||||
(elements.item(i) as Electron.WebviewTag).openDevTools();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class ReloadWebviewAction extends Action {
|
||||
static readonly ID = 'workbench.action.webview.reloadWebviewAction';
|
||||
static LABEL = nls.localize('refreshWebviewLabel', "Reload Webviews");
|
||||
|
||||
public constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IWorkbenchEditorService private readonly workbenchEditorService: IWorkbenchEditorService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
for (const webview of this.getVisibleWebviews()) {
|
||||
webview.reload();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private getVisibleWebviews() {
|
||||
return this.workbenchEditorService.getVisibleEditors()
|
||||
.filter(c => c && (c as any).isWebviewEditor)
|
||||
.map(e => e as WebviewEditor);
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import { IContextKey, RawContextKey, IContextKeyService } from 'vs/platform/cont
|
||||
|
||||
import { Webview } from './webview';
|
||||
import { Builder } from 'vs/base/browser/builder';
|
||||
import { Dimension } from 'vs/workbench/services/part/common/partService';
|
||||
|
||||
/** A context key that is set when a webview editor has focus. */
|
||||
export const KEYBINDING_CONTEXT_WEBVIEWEDITOR_FOCUS = new RawContextKey<boolean>('webviewEditorFocus', false);
|
||||
@@ -73,15 +74,26 @@ export abstract class WebviewEditor extends BaseWebviewEditor {
|
||||
}
|
||||
}
|
||||
|
||||
public updateStyles() {
|
||||
super.updateStyles();
|
||||
public get isWebviewEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public reload() {
|
||||
if (this._webview) {
|
||||
this._webview.style(this.themeService.getTheme());
|
||||
this._webview.reload();
|
||||
}
|
||||
}
|
||||
|
||||
public get isWebviewEditor() {
|
||||
return true;
|
||||
public layout(dimension: Dimension): void {
|
||||
if (this._webview) {
|
||||
this._webview.layout();
|
||||
}
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
if (this._webview) {
|
||||
this._webview.focus();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract createEditor(parent: Builder): void;
|
||||
|
||||
@@ -22,14 +22,24 @@ export const OUTPUT_MIME = 'text/x-code-output';
|
||||
export const OUTPUT_SCHEME = 'output';
|
||||
|
||||
/**
|
||||
* Output resource scheme.
|
||||
* Id used by the output editor.
|
||||
*/
|
||||
export const OUTPUT_MODE_ID = 'Log';
|
||||
|
||||
/**
|
||||
* Mime type used by the log output editor.
|
||||
*/
|
||||
export const LOG_MIME = 'text/x-code-log-output';
|
||||
|
||||
/**
|
||||
* Log resource scheme.
|
||||
*/
|
||||
export const LOG_SCHEME = 'log';
|
||||
|
||||
/**
|
||||
* Id used by the output editor.
|
||||
* Id used by the log output editor.
|
||||
*/
|
||||
export const OUTPUT_MODE_ID = 'Log';
|
||||
export const LOG_MODE_ID = 'log';
|
||||
|
||||
/**
|
||||
* Output panel id
|
||||
|
||||
@@ -11,7 +11,7 @@ import { RunOnceScheduler, wireCancellationToken } from 'vs/base/common/async';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { LinkProviderRegistry, ILink } from 'vs/editor/common/modes';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { OUTPUT_MODE_ID } from 'vs/workbench/parts/output/common/output';
|
||||
import { OUTPUT_MODE_ID, LOG_MODE_ID } from 'vs/workbench/parts/output/common/output';
|
||||
import { MonacoWebWorker, createWebWorker } from 'vs/editor/common/services/webWorker';
|
||||
import { ICreateData, OutputLinkComputer } from 'vs/workbench/parts/output/common/outputLinkComputer';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
@@ -44,7 +44,7 @@ export class OutputLinkProvider {
|
||||
const folders = this.contextService.getWorkspace().folders;
|
||||
if (folders.length > 0) {
|
||||
if (!this.linkProviderRegistration) {
|
||||
this.linkProviderRegistration = LinkProviderRegistry.register({ language: OUTPUT_MODE_ID, scheme: '*' }, {
|
||||
this.linkProviderRegistration = LinkProviderRegistry.register([{ language: OUTPUT_MODE_ID, scheme: '*' }, { language: LOG_MODE_ID, scheme: '*' }], {
|
||||
provideLinks: (model, token): Thenable<ILink[]> => {
|
||||
return wireCancellationToken(token, this.provideLinks(model.uri));
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { OutputService, LogContentProvider } from 'vs/workbench/parts/output/electron-browser/outputServices';
|
||||
import { ToggleOutputAction, ClearOutputAction } from 'vs/workbench/parts/output/browser/outputActions';
|
||||
import { OUTPUT_MODE_ID, OUTPUT_MIME, OUTPUT_PANEL_ID, IOutputService, CONTEXT_IN_OUTPUT, LOG_SCHEME, COMMAND_OPEN_LOG_VIEWER } from 'vs/workbench/parts/output/common/output';
|
||||
import { OUTPUT_MODE_ID, OUTPUT_MIME, OUTPUT_PANEL_ID, IOutputService, CONTEXT_IN_OUTPUT, LOG_SCHEME, COMMAND_OPEN_LOG_VIEWER, LOG_MODE_ID, LOG_MIME } from 'vs/workbench/parts/output/common/output';
|
||||
import { PanelRegistry, Extensions, PanelDescriptor } from 'vs/workbench/browser/panel';
|
||||
import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands';
|
||||
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -39,6 +39,14 @@ ModesRegistry.registerLanguage({
|
||||
mimetypes: [OUTPUT_MIME]
|
||||
});
|
||||
|
||||
// Register Log Output Mode
|
||||
ModesRegistry.registerLanguage({
|
||||
id: LOG_MODE_ID,
|
||||
extensions: [],
|
||||
aliases: [null],
|
||||
mimetypes: [LOG_MIME]
|
||||
});
|
||||
|
||||
// Register Output Panel
|
||||
Registry.as<PanelRegistry>(Extensions.Panels).registerPanel(new PanelDescriptor(
|
||||
OutputPanel,
|
||||
|
||||
@@ -16,7 +16,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { IOutputChannelIdentifier, IOutputChannel, IOutputService, Extensions, OUTPUT_PANEL_ID, IOutputChannelRegistry, OUTPUT_SCHEME, OUTPUT_MIME, MAX_OUTPUT_LENGTH, LOG_SCHEME } from 'vs/workbench/parts/output/common/output';
|
||||
import { IOutputChannelIdentifier, IOutputChannel, IOutputService, Extensions, OUTPUT_PANEL_ID, IOutputChannelRegistry, OUTPUT_SCHEME, OUTPUT_MIME, MAX_OUTPUT_LENGTH, LOG_SCHEME, LOG_MIME } from 'vs/workbench/parts/output/common/output';
|
||||
import { OutputPanel } from 'vs/workbench/parts/output/browser/outputPanel';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
@@ -134,6 +134,7 @@ abstract class AbstractFileOutputChannel extends Disposable {
|
||||
constructor(
|
||||
protected readonly outputChannelIdentifier: IOutputChannelIdentifier,
|
||||
private readonly modelUri: URI,
|
||||
private mimeType: string,
|
||||
protected fileService: IFileService,
|
||||
protected modelService: IModelService,
|
||||
protected modeService: IModeService,
|
||||
@@ -166,7 +167,7 @@ abstract class AbstractFileOutputChannel extends Disposable {
|
||||
if (this.model) {
|
||||
this.model.setValue(content);
|
||||
} else {
|
||||
this.model = this.modelService.createModel(content, this.modeService.getOrCreateMode(OUTPUT_MIME), this.modelUri);
|
||||
this.model = this.modelService.createModel(content, this.modeService.getOrCreateMode(this.mimeType), this.modelUri);
|
||||
this.onModelCreated(this.model);
|
||||
const disposables: IDisposable[] = [];
|
||||
disposables.push(this.model.onWillDispose(() => {
|
||||
@@ -217,7 +218,7 @@ class OutputChannelBackedByFile extends AbstractFileOutputChannel implements Out
|
||||
@IModeService modeService: IModeService,
|
||||
@ILogService logService: ILogService
|
||||
) {
|
||||
super({ ...outputChannelIdentifier, file: URI.file(paths.join(outputDir, `${outputChannelIdentifier.id}.log`)) }, modelUri, fileService, modelService, modeService);
|
||||
super({ ...outputChannelIdentifier, file: URI.file(paths.join(outputDir, `${outputChannelIdentifier.id}.log`)) }, modelUri, OUTPUT_MIME, fileService, modelService, modeService);
|
||||
|
||||
// Use one rotating file to check for main file reset
|
||||
this.outputWriter = new RotatingLogger(this.id, this.file.fsPath, 1024 * 1024 * 30, 1);
|
||||
@@ -363,7 +364,7 @@ class FileOutputChannel extends AbstractFileOutputChannel implements OutputChann
|
||||
@IModeService modeService: IModeService,
|
||||
@ILogService logService: ILogService,
|
||||
) {
|
||||
super(outputChannelIdentifier, modelUri, fileService, modelService, modeService);
|
||||
super(outputChannelIdentifier, modelUri, LOG_MIME, fileService, modelService, modeService);
|
||||
|
||||
this.fileHandler = this._register(new OutputFileListener(this.file));
|
||||
this._register(this.fileHandler.onDidContentChange(() => this.onDidContentChange()));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user