mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
Merge branch 'master' into joao/spdlog-0.17.0
This commit is contained in:
commit
b75e5daa15
|
@ -3,7 +3,7 @@ phases:
|
|||
condition: eq(variables['VSCODE_BUILD_WIN32'], 'true')
|
||||
queue: Hosted VS2017
|
||||
variables:
|
||||
VSCODE_ARCH: ia32
|
||||
VSCODE_ARCH: x64
|
||||
steps:
|
||||
- template: win32/product-build-win32.yml
|
||||
|
||||
|
|
|
@ -131,9 +131,8 @@ steps:
|
|||
ESRP: 'ESRP CodeSign'
|
||||
|
||||
- powershell: |
|
||||
. build/tfs/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { .\build\tfs\win32\import-esrp-auth-cert.ps1 -AuthCertificateBase64 $(ESRP_AUTH_CERTIFICATE) -AuthCertificateKey $(ESRP_AUTH_CERTIFICATE_KEY) }
|
||||
.\build\tfs\win32\import-esrp-auth-cert.ps1 -AuthCertificateBase64 $(ESRP_AUTH_CERTIFICATE) -AuthCertificateKey $(ESRP_AUTH_CERTIFICATE_KEY)
|
||||
displayName: Import ESRP Auth Certificate
|
||||
|
||||
- powershell: |
|
||||
|
|
|
@ -81,8 +81,6 @@ export async function activate(context: ExtensionContext): Promise<API> {
|
|||
const telemetryReporter = new TelemetryReporter(name, version, aiKey);
|
||||
deactivateTasks.push(() => telemetryReporter.dispose());
|
||||
|
||||
await new Promise(c => setTimeout(c, 10000));
|
||||
|
||||
const config = workspace.getConfiguration('git', null);
|
||||
const enabled = config.get<boolean>('enabled');
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/88217b1c7d36ed5d35adc3099ba7978aabe2531b",
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/d7df3e324468b6535af67573d2956f9a852aa586",
|
||||
"name": "JavaScript (with React support)",
|
||||
"scopeName": "source.js",
|
||||
"patterns": [
|
||||
|
@ -139,6 +139,10 @@
|
|||
"name": "keyword.control.with.js",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(with)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.js",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(package)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
},
|
||||
{
|
||||
"name": "keyword.other.debugger.js",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(debugger)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
|
@ -312,7 +316,7 @@
|
|||
"name": "punctuation.separator.comma.js"
|
||||
}
|
||||
},
|
||||
"end": "(?<!,)((?==|;|}|(\\s+(of|in)\\s+)|^\\s*$))|((?<=\\S)(?=\\s*$))",
|
||||
"end": "(?<!,)(((?==|;|}|(\\s+(of|in)\\s+)|^\\s*$))|((?<=\\S)(?=\\s*$)))",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comment"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/88217b1c7d36ed5d35adc3099ba7978aabe2531b",
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/d7df3e324468b6535af67573d2956f9a852aa586",
|
||||
"name": "JavaScript (with React support)",
|
||||
"scopeName": "source.js.jsx",
|
||||
"patterns": [
|
||||
|
@ -139,6 +139,10 @@
|
|||
"name": "keyword.control.with.js.jsx",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(with)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.js.jsx",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(package)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
},
|
||||
{
|
||||
"name": "keyword.other.debugger.js.jsx",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(debugger)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
|
@ -312,7 +316,7 @@
|
|||
"name": "punctuation.separator.comma.js.jsx"
|
||||
}
|
||||
},
|
||||
"end": "(?<!,)((?==|;|}|(\\s+(of|in)\\s+)|^\\s*$))|((?<=\\S)(?=\\s*$))",
|
||||
"end": "(?<!,)(((?==|;|}|(\\s+(of|in)\\s+)|^\\s*$))|((?<=\\S)(?=\\s*$)))",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comment"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/40288b872220e5c0b844b1de507f1749ed14589b",
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/d7df3e324468b6535af67573d2956f9a852aa586",
|
||||
"name": "TypeScript",
|
||||
"scopeName": "source.ts",
|
||||
"patterns": [
|
||||
|
@ -139,6 +139,10 @@
|
|||
"name": "keyword.control.with.ts",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(with)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.ts",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(package)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
},
|
||||
{
|
||||
"name": "keyword.other.debugger.ts",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(debugger)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
|
@ -309,7 +313,7 @@
|
|||
"name": "punctuation.separator.comma.ts"
|
||||
}
|
||||
},
|
||||
"end": "(?<!,)((?==|;|}|(\\s+(of|in)\\s+)|^\\s*$))|((?<=\\S)(?=\\s*$))",
|
||||
"end": "(?<!,)(((?==|;|}|(\\s+(of|in)\\s+)|^\\s*$))|((?<=\\S)(?=\\s*$)))",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comment"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/88217b1c7d36ed5d35adc3099ba7978aabe2531b",
|
||||
"version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/d7df3e324468b6535af67573d2956f9a852aa586",
|
||||
"name": "TypeScriptReact",
|
||||
"scopeName": "source.tsx",
|
||||
"patterns": [
|
||||
|
@ -139,6 +139,10 @@
|
|||
"name": "keyword.control.with.tsx",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(with)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.tsx",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(package)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
},
|
||||
{
|
||||
"name": "keyword.other.debugger.tsx",
|
||||
"match": "(?<![_$[:alnum:]])(?:(?<=\\.\\.\\.)|(?<!\\.))(debugger)(?![_$[:alnum:]])(?:(?=\\.\\.\\.)|(?!\\.))"
|
||||
|
@ -312,7 +316,7 @@
|
|||
"name": "punctuation.separator.comma.tsx"
|
||||
}
|
||||
},
|
||||
"end": "(?<!,)((?==|;|}|(\\s+(of|in)\\s+)|^\\s*$))|((?<=\\S)(?=\\s*$))",
|
||||
"end": "(?<!,)(((?==|;|}|(\\s+(of|in)\\s+)|^\\s*$))|((?<=\\S)(?=\\s*$)))",
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#comment"
|
||||
|
|
|
@ -11,6 +11,7 @@ import API from '../utils/api';
|
|||
import { Delayer } from '../utils/async';
|
||||
import { disposeAll } from '../utils/dispose';
|
||||
import * as languageModeIds from '../utils/languageModeIds';
|
||||
import * as typeConverters from '../utils/typeConverters';
|
||||
import { ResourceMap } from './resourceMap';
|
||||
|
||||
enum BufferKind {
|
||||
|
@ -18,10 +19,6 @@ enum BufferKind {
|
|||
JavaScript = 2,
|
||||
}
|
||||
|
||||
interface IDiagnosticRequestor {
|
||||
requestDiagnostic(resource: Uri): void;
|
||||
}
|
||||
|
||||
function mode2ScriptKind(mode: string): 'TS' | 'TSX' | 'JS' | 'JSX' | undefined {
|
||||
switch (mode) {
|
||||
case languageModeIds.typescript: return 'TS';
|
||||
|
@ -37,7 +34,6 @@ class SyncedBuffer {
|
|||
constructor(
|
||||
private readonly document: TextDocument,
|
||||
public readonly filepath: string,
|
||||
private readonly diagnosticRequestor: IDiagnosticRequestor,
|
||||
private readonly client: ITypeScriptServiceClient
|
||||
) { }
|
||||
|
||||
|
@ -101,16 +97,11 @@ class SyncedBuffer {
|
|||
public onContentChanged(events: TextDocumentContentChangeEvent[]): void {
|
||||
for (const { range, text } of events) {
|
||||
const args: Proto.ChangeRequestArgs = {
|
||||
file: this.filepath,
|
||||
line: range.start.line + 1,
|
||||
offset: range.start.character + 1,
|
||||
endLine: range.end.line + 1,
|
||||
endOffset: range.end.character + 1,
|
||||
insertString: text
|
||||
insertString: text,
|
||||
...typeConverters.Range.toFormattingRequestArgs(this.filepath, range)
|
||||
};
|
||||
this.client.execute('change', args, false);
|
||||
}
|
||||
this.diagnosticRequestor.requestDiagnostic(this.document.uri);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,9 +114,13 @@ class SyncedBufferMap extends ResourceMap<SyncedBuffer> {
|
|||
public get allBuffers(): Iterable<SyncedBuffer> {
|
||||
return this.values;
|
||||
}
|
||||
}
|
||||
|
||||
public get allResources(): Iterable<string> {
|
||||
return this.keys;
|
||||
class PendingDiagnostics extends ResourceMap<number> {
|
||||
public getFileList(): Set<string> {
|
||||
return new Set(Array.from(this.entries)
|
||||
.sort((a, b) => a[1] - b[1])
|
||||
.map(entry => entry[0]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,8 +133,7 @@ export default class BufferSyncSupport {
|
|||
private readonly modeIds: Set<string>;
|
||||
private readonly disposables: Disposable[] = [];
|
||||
private readonly syncedBuffers: SyncedBufferMap;
|
||||
|
||||
private readonly pendingDiagnostics = new Map<string, number>();
|
||||
private readonly pendingDiagnostics: PendingDiagnostics;
|
||||
private readonly diagnosticDelayer: Delayer<any>;
|
||||
private pendingGetErr: { request: Promise<any>, files: string[], token: CancellationTokenSource } | undefined;
|
||||
private listening: boolean = false;
|
||||
|
@ -153,10 +147,12 @@ export default class BufferSyncSupport {
|
|||
|
||||
this.diagnosticDelayer = new Delayer<any>(300);
|
||||
|
||||
this.syncedBuffers = new SyncedBufferMap(path => this.normalizePath(path));
|
||||
const pathNormalizer = (path: Uri) => this.client.normalizedPath(path);
|
||||
this.syncedBuffers = new SyncedBufferMap(pathNormalizer);
|
||||
this.pendingDiagnostics = new PendingDiagnostics(pathNormalizer);
|
||||
|
||||
this.updateConfiguration();
|
||||
workspace.onDidChangeConfiguration(() => this.updateConfiguration(), null);
|
||||
workspace.onDidChangeConfiguration(this.updateConfiguration, this, this.disposables);
|
||||
}
|
||||
|
||||
private readonly _onDelete = new EventEmitter<Uri>();
|
||||
|
@ -210,10 +206,10 @@ export default class BufferSyncSupport {
|
|||
return;
|
||||
}
|
||||
|
||||
const syncedBuffer = new SyncedBuffer(document, filepath, this, this.client);
|
||||
const syncedBuffer = new SyncedBuffer(document, filepath, this.client);
|
||||
this.syncedBuffers.set(resource, syncedBuffer);
|
||||
syncedBuffer.open();
|
||||
this.requestDiagnostic(resource);
|
||||
this.requestDiagnostic(syncedBuffer);
|
||||
}
|
||||
|
||||
public closeResource(resource: Uri): void {
|
||||
|
@ -240,25 +236,24 @@ export default class BufferSyncSupport {
|
|||
}
|
||||
|
||||
syncedBuffer.onContentChanged(e.contentChanges);
|
||||
this.requestDiagnostic(syncedBuffer);
|
||||
|
||||
if (this.pendingGetErr) {
|
||||
this.pendingGetErr.token.cancel();
|
||||
this.pendingGetErr = undefined;
|
||||
|
||||
this.diagnosticDelayer.trigger(() => {
|
||||
this.sendPendingDiagnostics();
|
||||
}, 200);
|
||||
// In this case we always want to re-trigger all diagnostics
|
||||
this.triggerDiagnostics();
|
||||
}
|
||||
}
|
||||
|
||||
public requestAllDiagnostics() {
|
||||
for (const buffer of this.syncedBuffers.allBuffers) {
|
||||
if (this.shouldValidate(buffer)) {
|
||||
this.pendingDiagnostics.set(buffer.filepath, Date.now());
|
||||
this.pendingDiagnostics.set(buffer.resource, Date.now());
|
||||
}
|
||||
}
|
||||
this.diagnosticDelayer.trigger(() => {
|
||||
this.sendPendingDiagnostics();
|
||||
}, 200);
|
||||
this.triggerDiagnostics();
|
||||
}
|
||||
|
||||
public getErr(resources: Uri[]): any {
|
||||
|
@ -268,65 +263,55 @@ export default class BufferSyncSupport {
|
|||
}
|
||||
|
||||
for (const resource of handledResources) {
|
||||
const file = this.client.normalizedPath(resource);
|
||||
if (file) {
|
||||
this.pendingDiagnostics.set(file, Date.now());
|
||||
}
|
||||
this.pendingDiagnostics.set(resource, Date.now());
|
||||
}
|
||||
|
||||
this.diagnosticDelayer.trigger(() => {
|
||||
this.sendPendingDiagnostics();
|
||||
}, 200);
|
||||
this.triggerDiagnostics();
|
||||
}
|
||||
|
||||
public requestDiagnostic(resource: Uri): void {
|
||||
const file = this.client.normalizedPath(resource);
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pendingDiagnostics.set(file, Date.now());
|
||||
const buffer = this.syncedBuffers.get(resource);
|
||||
if (!buffer || !this.shouldValidate(buffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let delay = 300;
|
||||
const lineCount = buffer.lineCount;
|
||||
delay = Math.min(Math.max(Math.ceil(lineCount / 20), 300), 800);
|
||||
private triggerDiagnostics(delay: number = 200) {
|
||||
this.diagnosticDelayer.trigger(() => {
|
||||
this.sendPendingDiagnostics();
|
||||
}, delay);
|
||||
}
|
||||
|
||||
private requestDiagnostic(buffer: SyncedBuffer): void {
|
||||
if (!this.shouldValidate(buffer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pendingDiagnostics.set(buffer.resource, Date.now());
|
||||
|
||||
const lineCount = buffer.lineCount;
|
||||
const delay = Math.min(Math.max(Math.ceil(lineCount / 20), 300), 800);
|
||||
this.triggerDiagnostics(delay);
|
||||
}
|
||||
|
||||
public hasPendingDiagnostics(resource: Uri): boolean {
|
||||
const file = this.client.normalizedPath(resource);
|
||||
return !file || this.pendingDiagnostics.has(file);
|
||||
return this.pendingDiagnostics.has(resource);
|
||||
}
|
||||
|
||||
private sendPendingDiagnostics(): void {
|
||||
const files = new Set(Array.from(this.pendingDiagnostics.entries())
|
||||
.sort((a, b) => a[1] - b[1])
|
||||
.map(entry => entry[0]));
|
||||
const fileList = this.pendingDiagnostics.getFileList();
|
||||
|
||||
// Add all open TS buffers to the geterr request. They might be visible
|
||||
for (const file of this.syncedBuffers.allResources) {
|
||||
if (!this.pendingDiagnostics.get(file)) {
|
||||
files.add(file);
|
||||
for (const buffer of this.syncedBuffers.values) {
|
||||
if (!this.pendingDiagnostics.has(buffer.resource)) {
|
||||
fileList.add(buffer.filepath);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.pendingGetErr) {
|
||||
for (const file of this.pendingGetErr.files) {
|
||||
files.add(file);
|
||||
fileList.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (files.size) {
|
||||
const fileList = Array.from(files);
|
||||
if (fileList.size) {
|
||||
const files = Array.from(fileList);
|
||||
const args: Proto.GeterrRequestArgs = {
|
||||
delay: 0,
|
||||
files: fileList
|
||||
files
|
||||
};
|
||||
const token = new CancellationTokenSource();
|
||||
|
||||
|
@ -338,7 +323,7 @@ export default class BufferSyncSupport {
|
|||
this.pendingGetErr = undefined;
|
||||
}
|
||||
}),
|
||||
files: fileList,
|
||||
files,
|
||||
token
|
||||
};
|
||||
}
|
||||
|
@ -363,8 +348,4 @@ export default class BufferSyncSupport {
|
|||
return this._validateTypeScript;
|
||||
}
|
||||
}
|
||||
|
||||
private normalizePath(path: Uri): string | null {
|
||||
return this.client.normalizedPath(path);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,17 +51,11 @@ class TypeScriptFormattingProvider implements vscode.DocumentRangeFormattingEdit
|
|||
options: vscode.FormattingOptions,
|
||||
token: vscode.CancellationToken
|
||||
): Promise<vscode.TextEdit[]> {
|
||||
const absPath = this.client.toPath(document.uri);
|
||||
if (!absPath) {
|
||||
const file = this.client.toPath(document.uri);
|
||||
if (!file) {
|
||||
return [];
|
||||
}
|
||||
const args: Proto.FormatRequestArgs = {
|
||||
file: absPath,
|
||||
line: range.start.line + 1,
|
||||
offset: range.start.character + 1,
|
||||
endLine: range.end.line + 1,
|
||||
endOffset: range.end.character + 1
|
||||
};
|
||||
const args = typeConverters.Range.toFormattingRequestArgs(file, range);
|
||||
return this.doFormat(document, options, args, token);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,12 +45,16 @@ export class ResourceMap<T> {
|
|||
}
|
||||
}
|
||||
|
||||
public clear() {
|
||||
this._map.clear();
|
||||
}
|
||||
|
||||
public get values(): Iterable<T> {
|
||||
return this._map.values();
|
||||
}
|
||||
|
||||
public get keys(): Iterable<string> {
|
||||
return this._map.keys();
|
||||
public get entries() {
|
||||
return this._map.entries();
|
||||
}
|
||||
|
||||
private toKey(resource: Uri): string | null {
|
||||
|
|
|
@ -23,13 +23,8 @@ class TagClosing {
|
|||
) {
|
||||
vscode.workspace.onDidChangeTextDocument(
|
||||
event => this.onDidChangeTextDocument(event.document, event.contentChanges),
|
||||
null, this.disposables);
|
||||
|
||||
vscode.window.onDidChangeActiveTextEditor(
|
||||
() => this.updateEnabledState(),
|
||||
null, this.disposables);
|
||||
|
||||
this.updateEnabledState();
|
||||
null,
|
||||
this.disposables);
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
|
@ -38,10 +33,6 @@ class TagClosing {
|
|||
this.timeout = undefined;
|
||||
}
|
||||
|
||||
private updateEnabledState() {
|
||||
|
||||
}
|
||||
|
||||
private onDidChangeTextDocument(
|
||||
document: vscode.TextDocument,
|
||||
changes: vscode.TextDocumentContentChangeEvent[]
|
||||
|
@ -66,6 +57,11 @@ class TagClosing {
|
|||
return;
|
||||
}
|
||||
|
||||
const secondToLastCharacter = lastChange.text[lastChange.text.length - 2];
|
||||
if (secondToLastCharacter === '>') {
|
||||
return;
|
||||
}
|
||||
|
||||
const rangeStart = lastChange.range.start;
|
||||
const version = document.version;
|
||||
this.timeout = setTimeout(async () => {
|
||||
|
@ -124,12 +120,8 @@ export class ActiveDocumentDependentRegistration {
|
|||
register: () => vscode.Disposable,
|
||||
) {
|
||||
this._registration = new ConditionalRegistration(register);
|
||||
|
||||
vscode.window.onDidChangeActiveTextEditor(this.update, this, this._disposables);
|
||||
this.update();
|
||||
|
||||
vscode.window.onDidChangeActiveTextEditor(() => {
|
||||
this.update();
|
||||
}, null, this._disposables);
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
|
|
|
@ -10,11 +10,11 @@ import * as nls from 'vscode-nls';
|
|||
import * as Proto from '../protocol';
|
||||
import { ITypeScriptServiceClient } from '../typescriptService';
|
||||
import API from '../utils/api';
|
||||
import * as languageIds from '../utils/languageModeIds';
|
||||
import * as fileSchemes from '../utils/fileSchemes';
|
||||
import { isTypeScriptDocument } from '../utils/languageModeIds';
|
||||
import { escapeRegExp } from '../utils/regexp';
|
||||
import * as typeConverters from '../utils/typeConverters';
|
||||
import FileConfigurationManager from './fileConfigurationManager';
|
||||
import * as fileSchemes from '../utils/fileSchemes';
|
||||
import { escapeRegExp } from '../utils/regexp';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
|
@ -83,14 +83,20 @@ export class UpdateImportsOnFileRenameHandler {
|
|||
this.client.bufferSyncSupport.closeResource(targetResource);
|
||||
this.client.bufferSyncSupport.openTextDocument(document);
|
||||
|
||||
// Workaround for https://github.com/Microsoft/vscode/issues/52967
|
||||
// Never attempt to update import paths if the file does not contain something the looks like an export
|
||||
const tree = await this.client.execute('navtree', { file: newFile });
|
||||
const hasExport = (node: Proto.NavigationTree): boolean => {
|
||||
return !!node.kindModifiers.match(/\bexport\b/g) || !!(node.childItems && node.childItems.some(hasExport));
|
||||
};
|
||||
if (!tree.body || !tree.body || !hasExport(tree.body)) {
|
||||
return;
|
||||
if (!this.client.apiVersion.gte(API.v300) && !fs.lstatSync(newResource.fsPath).isDirectory()) {
|
||||
// Workaround for https://github.com/Microsoft/vscode/issues/52967
|
||||
// Never attempt to update import paths if the file does not contain something the looks like an export
|
||||
try {
|
||||
const tree = await this.client.execute('navtree', { file: newFile });
|
||||
const hasExport = (node: Proto.NavigationTree): boolean => {
|
||||
return !!node.kindModifiers.match(/\bexports?\b/g) || !!(node.childItems && node.childItems.some(hasExport));
|
||||
};
|
||||
if (!tree.body || !tree.body || !hasExport(tree.body)) {
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
const edits = await this.getEditsForFileRename(targetFile, document, oldFile, newFile);
|
||||
|
@ -203,7 +209,12 @@ export class UpdateImportsOnFileRenameHandler {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
if (this.client.apiVersion.gte(API.v292) && fs.lstatSync(resource.fsPath).isDirectory()) {
|
||||
const isDirectory = fs.lstatSync(resource.fsPath).isDirectory();
|
||||
if (isDirectory && this.client.apiVersion.gte(API.v300)) {
|
||||
return resource;
|
||||
}
|
||||
|
||||
if (isDirectory && this.client.apiVersion.gte(API.v292)) {
|
||||
const files = await vscode.workspace.findFiles({
|
||||
base: resource.fsPath,
|
||||
pattern: '**/*.{ts,tsx,js,jsx}',
|
||||
|
@ -293,6 +304,3 @@ export class UpdateImportsOnFileRenameHandler {
|
|||
}
|
||||
}
|
||||
|
||||
function isTypeScriptDocument(document: vscode.TextDocument) {
|
||||
return document.languageId === languageIds.typescript || document.languageId === languageIds.typescriptreact;
|
||||
}
|
||||
|
|
|
@ -75,12 +75,8 @@ export class ConfigurationDependentRegistration {
|
|||
register: () => vscode.Disposable,
|
||||
) {
|
||||
this._registration = new ConditionalRegistration(register);
|
||||
|
||||
this.update();
|
||||
|
||||
vscode.workspace.onDidChangeConfiguration(() => {
|
||||
this.update();
|
||||
}, null, this._disposables);
|
||||
vscode.workspace.onDidChangeConfiguration(this.update, this, this._disposables);
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
|
|
|
@ -24,6 +24,14 @@ export namespace Range {
|
|||
endLine: range.end.line + 1,
|
||||
endOffset: range.end.character + 1
|
||||
});
|
||||
|
||||
export const toFormattingRequestArgs = (file: string, range: vscode.Range): Proto.FormatRequestArgs => ({
|
||||
file,
|
||||
line: range.start.line + 1,
|
||||
offset: range.start.character + 1,
|
||||
endLine: range.end.line + 1,
|
||||
endOffset: range.end.character + 1
|
||||
});
|
||||
}
|
||||
|
||||
export namespace Position {
|
||||
|
|
|
@ -499,17 +499,16 @@ suite('workspace-namespace', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// TODO@Joh this test fails randomly
|
||||
// test('findFiles, cancellation', () => {
|
||||
test('findFiles, cancellation', () => {
|
||||
|
||||
// const source = new CancellationTokenSource();
|
||||
// const token = source.token; // just to get an instance first
|
||||
// source.cancel();
|
||||
const source = new vscode.CancellationTokenSource();
|
||||
const token = source.token; // just to get an instance first
|
||||
source.cancel();
|
||||
|
||||
// return vscode.workspace.findFiles('*.js', null, 100, token).then((res) => {
|
||||
// assert.equal(res, void 0);
|
||||
// });
|
||||
// });
|
||||
return vscode.workspace.findFiles('*.js', null, 100, token).then((res) => {
|
||||
assert.deepEqual(res, []);
|
||||
});
|
||||
});
|
||||
|
||||
test('findTextInFiles', async () => {
|
||||
const results: vscode.TextSearchResult[] = [];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.26.0",
|
||||
"distro": "bf3aa85b8880d2d1c80030e21a3a2ddd384fa1e7",
|
||||
"distro": "655112e16611a8427ba96dbd6de2b05ecf2e3f6b",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
|
|
|
@ -840,6 +840,8 @@ export const EventType = {
|
|||
SUBMIT: 'submit',
|
||||
RESET: 'reset',
|
||||
FOCUS: 'focus',
|
||||
FOCUS_IN: 'focusin',
|
||||
FOCUS_OUT: 'focusout',
|
||||
BLUR: 'blur',
|
||||
INPUT: 'input',
|
||||
// Local Storage
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
outline-style: none;
|
||||
}
|
||||
|
||||
.monaco-breadcrumbs .monaco-breadcrumb-item {
|
||||
|
@ -16,13 +17,14 @@
|
|||
align-items: center;
|
||||
flex: 0 1 auto;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
cursor: pointer;
|
||||
align-self: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-breadcrumbs .monaco-breadcrumb-item:not(:last-child)::after {
|
||||
background-image: url(./collapsed.svg);
|
||||
opacity: .7;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: inline-block;
|
||||
|
@ -35,6 +37,3 @@
|
|||
background-image: url(./collpased-dark.svg);
|
||||
}
|
||||
|
||||
.monaco-breadcrumbs .monaco-breadcrumb-item.focused {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -44,8 +44,12 @@ export class SimpleBreadcrumbsItem extends BreadcrumbsItem {
|
|||
|
||||
export interface IBreadcrumbsWidgetStyles {
|
||||
breadcrumbsBackground?: Color;
|
||||
breadcrumbsActiveForeground?: Color;
|
||||
breadcrumbsInactiveForeground?: Color;
|
||||
breadcrumbsForeground?: Color;
|
||||
breadcrumbsHoverBackground?: Color;
|
||||
breadcrumbsHoverForeground?: Color;
|
||||
breadcrumbsFocusForeground?: Color;
|
||||
breadcrumbsFocusAndSelectionBackground?: Color;
|
||||
breadcrumbsFocusAndSelectionForeground?: Color;
|
||||
}
|
||||
|
||||
export interface IBreadcrumbsItemEvent {
|
||||
|
@ -123,11 +127,23 @@ export class BreadcrumbsWidget {
|
|||
if (style.breadcrumbsBackground) {
|
||||
content += `.monaco-breadcrumbs { background-color: ${style.breadcrumbsBackground}}`;
|
||||
}
|
||||
if (style.breadcrumbsActiveForeground) {
|
||||
content += `.monaco-breadcrumbs:focus .monaco-breadcrumb-item { color: ${style.breadcrumbsActiveForeground}}\n`;
|
||||
if (style.breadcrumbsForeground) {
|
||||
content += `.monaco-breadcrumbs .monaco-breadcrumb-item { color: ${style.breadcrumbsForeground}}\n`;
|
||||
}
|
||||
if (style.breadcrumbsInactiveForeground) {
|
||||
content += `.monaco-breadcrumbs .monaco-breadcrumb-item { color: ${style.breadcrumbsInactiveForeground}}\n`;
|
||||
if (style.breadcrumbsFocusForeground) {
|
||||
content += `.monaco-breadcrumbs .monaco-breadcrumb-item.focused { color: ${style.breadcrumbsFocusForeground}}\n`;
|
||||
}
|
||||
if (style.breadcrumbsFocusAndSelectionBackground) {
|
||||
content += `.monaco-breadcrumbs .monaco-breadcrumb-item.focused.selected { background-color: ${style.breadcrumbsFocusAndSelectionBackground}}\n`;
|
||||
}
|
||||
if (style.breadcrumbsFocusAndSelectionForeground) {
|
||||
content += `.monaco-breadcrumbs .monaco-breadcrumb-item.focused.selected { color: ${style.breadcrumbsFocusAndSelectionForeground}}\n`;
|
||||
}
|
||||
if (style.breadcrumbsHoverBackground) {
|
||||
content += `.monaco-breadcrumbs .monaco-breadcrumb-item:hover:not(.focused):not(.selected) { background-color: ${style.breadcrumbsHoverBackground}}\n`;
|
||||
}
|
||||
if (style.breadcrumbsHoverForeground) {
|
||||
content += `.monaco-breadcrumbs .monaco-breadcrumb-item:hover:not(.focused):not(.selected) { color: ${style.breadcrumbsHoverForeground}}\n`;
|
||||
}
|
||||
if (this._styleElement.innerHTML !== content) {
|
||||
this._styleElement.innerHTML = content;
|
||||
|
@ -153,13 +169,15 @@ export class BreadcrumbsWidget {
|
|||
}
|
||||
|
||||
focusPrev(): any {
|
||||
this._focus((this._focusedItemIdx - 1 + this._nodes.length) % this._nodes.length);
|
||||
// this._domNode.focus();
|
||||
if (this._focusedItemIdx > 0) {
|
||||
this._focus(this._focusedItemIdx - 1);
|
||||
}
|
||||
}
|
||||
|
||||
focusNext(): any {
|
||||
this._focus((this._focusedItemIdx + 1) % this._nodes.length);
|
||||
// this._domNode.focus();
|
||||
if (this._focusedItemIdx + 1 < this._nodes.length) {
|
||||
this._focus(this._focusedItemIdx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private _focus(nth: number): void {
|
||||
|
@ -173,14 +191,29 @@ export class BreadcrumbsWidget {
|
|||
dom.addClass(node, 'focused');
|
||||
}
|
||||
}
|
||||
this._reveal(this._focusedItemIdx);
|
||||
this._onDidFocusItem.fire({ type: 'focus', item: this._items[this._focusedItemIdx], node: this._nodes[this._focusedItemIdx] });
|
||||
}
|
||||
|
||||
getSelected(): BreadcrumbsItem {
|
||||
reveal(item: BreadcrumbsItem): void {
|
||||
let idx = this._items.indexOf(item);
|
||||
if (idx >= 0) {
|
||||
this._reveal(idx);
|
||||
}
|
||||
}
|
||||
|
||||
private _reveal(nth: number): void {
|
||||
const node = this._nodes[nth];
|
||||
if (node) {
|
||||
this._scrollable.setScrollPosition({ scrollLeft: node.offsetLeft });
|
||||
}
|
||||
}
|
||||
|
||||
getSelection(): BreadcrumbsItem {
|
||||
return this._items[this._selectedItemIdx];
|
||||
}
|
||||
|
||||
setSelected(item: BreadcrumbsItem): void {
|
||||
setSelection(item: BreadcrumbsItem): void {
|
||||
this._select(this._items.indexOf(item));
|
||||
}
|
||||
|
||||
|
@ -203,9 +236,7 @@ export class BreadcrumbsWidget {
|
|||
let removed = this._items.splice(prefix, this._items.length - prefix, ...items.slice(prefix));
|
||||
this._render(prefix);
|
||||
dispose(removed);
|
||||
if (prefix >= this._focusedItemIdx) {
|
||||
this._focus(-1);
|
||||
}
|
||||
this._focus(-1);
|
||||
}
|
||||
|
||||
private _render(start: number): void {
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
|
||||
.context-view {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
z-index: 2000;
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { GestureEvent } from 'vs/base/browser/touch';
|
||||
|
||||
export interface IDelegate<T> {
|
||||
export interface IVirtualDelegate<T> {
|
||||
getHeight(element: T): number;
|
||||
getTemplateId(element: T): string;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ export interface IRenderer<TElement, TTemplateData> {
|
|||
templateId: string;
|
||||
renderTemplate(container: HTMLElement): TTemplateData;
|
||||
renderElement(element: TElement, index: number, templateData: TTemplateData): void;
|
||||
disposeElement(element: TElement, index: number, templateData: TTemplateData): void;
|
||||
disposeTemplate(templateData: TTemplateData): void;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
import 'vs/css!./list';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { range } from 'vs/base/common/arrays';
|
||||
import { IDelegate, IRenderer, IListEvent, IListOpenEvent } from './list';
|
||||
import { IVirtualDelegate, IRenderer, IListEvent, IListOpenEvent } from './list';
|
||||
import { List, IListStyles, IListOptions } from './listWidget';
|
||||
import { IPagedModel } from 'vs/base/common/paging';
|
||||
import { Event, mapEvent } from 'vs/base/common/event';
|
||||
|
@ -50,6 +50,10 @@ class PagedRenderer<TElement, TTemplateData> implements IRenderer<number, ITempl
|
|||
promise.done(entry => this.renderer.renderElement(entry, index, data.data));
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
disposeTemplate(data: ITemplateData<TTemplateData>): void {
|
||||
data.disposable.dispose();
|
||||
data.disposable = null;
|
||||
|
@ -65,12 +69,12 @@ export class PagedList<T> implements IDisposable {
|
|||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
delegate: IDelegate<number>,
|
||||
virtualDelegate: IVirtualDelegate<number>,
|
||||
renderers: IPagedRenderer<T, any>[],
|
||||
options: IListOptions<any> = {}
|
||||
) {
|
||||
const pagedRenderers = renderers.map(r => new PagedRenderer<T, ITemplateData<T>>(r, () => this.model));
|
||||
this.list = new List(container, delegate, pagedRenderers, options);
|
||||
this.list = new List(container, virtualDelegate, pagedRenderers, options);
|
||||
}
|
||||
|
||||
getHTMLElement(): HTMLElement {
|
||||
|
|
|
@ -12,7 +12,7 @@ import { domEvent } from 'vs/base/browser/event';
|
|||
import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { ScrollEvent, ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { RangeMap, IRange, relativeComplement, intersect, shift } from './rangeMap';
|
||||
import { IDelegate, IRenderer, IListMouseEvent, IListTouchEvent, IListGestureEvent } from './list';
|
||||
import { IVirtualDelegate, IRenderer, IListMouseEvent, IListTouchEvent, IListGestureEvent } from './list';
|
||||
import { RowCache, IRow } from './rowCache';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
|
@ -72,7 +72,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
|||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
private delegate: IDelegate<T>,
|
||||
private virtualDelegate: IVirtualDelegate<T>,
|
||||
renderers: IRenderer<T, any>[],
|
||||
options: IListViewOptions = DefaultOptions
|
||||
) {
|
||||
|
@ -156,8 +156,8 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
|||
const inserted = elements.map<IItem<T>>(element => ({
|
||||
id: String(this.itemId++),
|
||||
element,
|
||||
size: this.delegate.getHeight(element),
|
||||
templateId: this.delegate.getTemplateId(element),
|
||||
size: this.virtualDelegate.getHeight(element),
|
||||
templateId: this.virtualDelegate.getTemplateId(element),
|
||||
row: null
|
||||
}));
|
||||
|
||||
|
@ -322,6 +322,12 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
|||
throw new Error(`Got index ${index} and there are ${this.items.length} items. File issue to joao!`);
|
||||
}
|
||||
|
||||
const renderer = this.renderers.get(item.templateId);
|
||||
|
||||
if (renderer.disposeElement) {
|
||||
renderer.disposeElement(item.element, index, item.row.templateData);
|
||||
}
|
||||
|
||||
this.cache.release(item.row);
|
||||
item.row = null;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
|||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { Event, Emitter, EventBufferer, chain, mapEvent, anyEvent } from 'vs/base/common/event';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IDelegate, IRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IListOpenEvent } from './list';
|
||||
import { IVirtualDelegate, IRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IListOpenEvent } from './list';
|
||||
import { ListView, IListViewOptions } from './listView';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
|
@ -68,6 +68,10 @@ class TraitRenderer<T> implements IRenderer<T, ITraitTemplateData>
|
|||
this.trait.renderIndex(index, templateData);
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
splice(start: number, deleteCount: number, insertCount: number): void {
|
||||
const rendered: IRenderedContainer[] = [];
|
||||
|
||||
|
@ -807,6 +811,14 @@ class PipelineRenderer<T> implements IRenderer<T, any> {
|
|||
}
|
||||
}
|
||||
|
||||
disposeElement(element: T, index: number, templateData: any[]): void {
|
||||
let i = 0;
|
||||
|
||||
for (const renderer of this.renderers) {
|
||||
renderer.disposeElement(element, index, templateData[i++]);
|
||||
}
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: any[]): void {
|
||||
let i = 0;
|
||||
|
||||
|
@ -871,7 +883,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
|||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
delegate: IDelegate<T>,
|
||||
virtualDelegate: IVirtualDelegate<T>,
|
||||
renderers: IRenderer<T, any>[],
|
||||
options: IListOptions<T> = DefaultOptions
|
||||
) {
|
||||
|
@ -882,7 +894,7 @@ export class List<T> implements ISpliceable<T>, IDisposable {
|
|||
|
||||
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 = new ListView(container, virtualDelegate, renderers, options);
|
||||
this.view.domNode.setAttribute('role', 'tree');
|
||||
DOM.addClass(this.view.domNode, this.idPrefix);
|
||||
this.view.domNode.tabIndex = 0;
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
export interface ISpliceable<T> {
|
||||
splice(start: number, deleteCount: number, elements: T[]): void;
|
||||
}
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
|
||||
export interface ISpreadSpliceable<T> {
|
||||
splice(start: number, deleteCount: number, ...elements: T[]): void;
|
||||
|
|
|
@ -15,6 +15,7 @@ import { Event } from 'vs/base/common/event';
|
|||
import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus } from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { $, Builder } from 'vs/base/browser/builder';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
|
||||
export interface IMenuOptions {
|
||||
context?: any;
|
||||
|
@ -241,6 +242,8 @@ class SubmenuActionItem extends MenuActionItem {
|
|||
private mysubmenu: Menu;
|
||||
private submenuContainer: Builder;
|
||||
private mouseOver: boolean;
|
||||
private showScheduler: RunOnceScheduler;
|
||||
private hideScheduler: RunOnceScheduler;
|
||||
|
||||
constructor(
|
||||
action: IAction,
|
||||
|
@ -249,6 +252,20 @@ class SubmenuActionItem extends MenuActionItem {
|
|||
private submenuOptions?: IMenuOptions
|
||||
) {
|
||||
super(action, action, { label: true, isMenu: true });
|
||||
|
||||
this.showScheduler = new RunOnceScheduler(() => {
|
||||
if (this.mouseOver) {
|
||||
this.cleanupExistingSubmenu(false);
|
||||
this.createSubmenu();
|
||||
}
|
||||
}, 250);
|
||||
|
||||
this.hideScheduler = new RunOnceScheduler(() => {
|
||||
if (!this.mouseOver && this.parentData.submenu === this.mysubmenu) {
|
||||
this.parentData.parent.focus();
|
||||
this.cleanupExistingSubmenu(true);
|
||||
}
|
||||
}, 750);
|
||||
}
|
||||
|
||||
public render(container: HTMLElement): void {
|
||||
|
@ -278,26 +295,14 @@ class SubmenuActionItem extends MenuActionItem {
|
|||
if (!this.mouseOver) {
|
||||
this.mouseOver = true;
|
||||
|
||||
setTimeout(() => {
|
||||
if (this.mouseOver) {
|
||||
this.cleanupExistingSubmenu(false);
|
||||
this.createSubmenu();
|
||||
}
|
||||
}, 250);
|
||||
|
||||
this.showScheduler.schedule();
|
||||
}
|
||||
});
|
||||
|
||||
$(this.builder).on(EventType.MOUSE_LEAVE, (e) => {
|
||||
this.mouseOver = false;
|
||||
|
||||
setTimeout(() => {
|
||||
if (!this.mouseOver && this.parentData.submenu === this.mysubmenu) {
|
||||
this.parentData.parent.focus();
|
||||
this.cleanupExistingSubmenu(true);
|
||||
}
|
||||
|
||||
}, 750);
|
||||
this.hideScheduler.schedule();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -360,6 +365,9 @@ class SubmenuActionItem extends MenuActionItem {
|
|||
public dispose() {
|
||||
super.dispose();
|
||||
|
||||
this.hideScheduler.dispose();
|
||||
this.showScheduler.dispose();
|
||||
|
||||
if (this.mysubmenu) {
|
||||
this.mysubmenu.dispose();
|
||||
this.mysubmenu = null;
|
||||
|
|
|
@ -14,7 +14,7 @@ import * as dom from 'vs/base/browser/dom';
|
|||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IDelegate, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { IVirtualDelegate, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
|
||||
import { ISelectBoxDelegate, ISelectBoxOptions, ISelectBoxStyles, ISelectData } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
|
@ -67,12 +67,16 @@ class SelectListRenderer implements IRenderer<ISelectOptionItem, ISelectListTemp
|
|||
}
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: ISelectListTemplateData): void {
|
||||
templateData.disposables = dispose(templateData.disposables);
|
||||
}
|
||||
}
|
||||
|
||||
export class SelectBoxList implements ISelectBoxDelegate, IDelegate<ISelectOptionItem> {
|
||||
export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate<ISelectOptionItem> {
|
||||
|
||||
private static readonly DEFAULT_DROPDOWN_MINIMUM_BOTTOM_MARGIN = 32;
|
||||
|
||||
|
@ -238,6 +242,8 @@ export class SelectBoxList implements ISelectBoxDelegate, IDelegate<ISelectOptio
|
|||
|
||||
if (selected !== undefined) {
|
||||
this.select(selected);
|
||||
// Set current = selected since this is not necessarily a user exit
|
||||
this._currentSelection = this.selected;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -523,9 +529,11 @@ export class SelectBoxList implements ISelectBoxDelegate, IDelegate<ISelectOptio
|
|||
|
||||
// List methods
|
||||
|
||||
// List mouse controller - active exit, select option, fire onDidSelect, return focus to parent select
|
||||
// List mouse controller - active exit, select option, fire onDidSelect if change, return focus to parent select
|
||||
private onMouseUp(e: MouseEvent): void {
|
||||
|
||||
dom.EventHelper.stop(e);
|
||||
|
||||
// Check our mouse event is on an option (not scrollbar)
|
||||
if (!e.toElement.classList.contains('option-text')) {
|
||||
return;
|
||||
|
@ -542,59 +550,58 @@ export class SelectBoxList implements ISelectBoxDelegate, IDelegate<ISelectOptio
|
|||
|
||||
this.selectList.setFocus([this.selected]);
|
||||
this.selectList.reveal(this.selectList.getFocus()[0]);
|
||||
this._onDidSelect.fire({
|
||||
index: this.selectElement.selectedIndex,
|
||||
selected: this.selectElement.title
|
||||
});
|
||||
|
||||
// Reset Selection Handler
|
||||
this._currentSelection = -1;
|
||||
// Only fire if selection change
|
||||
if (this.selected !== this._currentSelection) {
|
||||
// Set current = selected
|
||||
this._currentSelection = this.selected;
|
||||
|
||||
this._onDidSelect.fire({
|
||||
index: this.selectElement.selectedIndex,
|
||||
selected: this.selectElement.title
|
||||
});
|
||||
}
|
||||
|
||||
this.hideSelectDropDown(true);
|
||||
}
|
||||
dom.EventHelper.stop(e);
|
||||
}
|
||||
|
||||
// List Exit - passive - hide drop-down, fire onDidSelect
|
||||
// List Exit - passive - implicit no selection change, hide drop-down
|
||||
private onListBlur(): void {
|
||||
|
||||
if (this._currentSelection >= 0) {
|
||||
if (this.selected !== this._currentSelection) {
|
||||
// Reset selected to current if no change
|
||||
this.select(this._currentSelection);
|
||||
}
|
||||
|
||||
this._onDidSelect.fire({
|
||||
index: this.selectElement.selectedIndex,
|
||||
selected: this.selectElement.title
|
||||
});
|
||||
|
||||
this.hideSelectDropDown(false);
|
||||
}
|
||||
|
||||
// List keyboard controller
|
||||
// List exit - active - hide ContextView dropdown, return focus to parent select, fire onDidSelect
|
||||
|
||||
// List exit - active - hide ContextView dropdown, reset selection, return focus to parent select
|
||||
private onEscape(e: StandardKeyboardEvent): void {
|
||||
dom.EventHelper.stop(e);
|
||||
|
||||
// Reset selection to value when opened
|
||||
this.select(this._currentSelection);
|
||||
|
||||
this.hideSelectDropDown(true);
|
||||
|
||||
this._onDidSelect.fire({
|
||||
index: this.selectElement.selectedIndex,
|
||||
selected: this.selectElement.title
|
||||
});
|
||||
}
|
||||
|
||||
// List exit - active - hide ContextView dropdown, return focus to parent select, fire onDidSelect
|
||||
// List exit - active - hide ContextView dropdown, return focus to parent select, fire onDidSelect if change
|
||||
private onEnter(e: StandardKeyboardEvent): void {
|
||||
dom.EventHelper.stop(e);
|
||||
|
||||
// Reset current selection
|
||||
this._currentSelection = -1;
|
||||
// Only fire if selection change
|
||||
if (this.selected !== this._currentSelection) {
|
||||
this._currentSelection = this.selected;
|
||||
this._onDidSelect.fire({
|
||||
index: this.selectElement.selectedIndex,
|
||||
selected: this.selectElement.title
|
||||
});
|
||||
}
|
||||
|
||||
this.hideSelectDropDown(true);
|
||||
this._onDidSelect.fire({
|
||||
index: this.selectElement.selectedIndex,
|
||||
selected: this.selectElement.title
|
||||
});
|
||||
}
|
||||
|
||||
// List navigation - have to handle a disabled option (jump over)
|
||||
|
|
|
@ -4,15 +4,16 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./tree';
|
||||
import { IDisposable, dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IListOptions, List, IIdentityProvider, IMultipleSelectionController } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { TreeModel, ITreeNode, ITreeElement } from 'vs/base/browser/ui/tree/treeModel';
|
||||
import { IIterator, empty } from 'vs/base/common/iterator';
|
||||
import { IDelegate, IRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { TreeModel, ITreeNode, ITreeElement, getNodeLocation } from 'vs/base/browser/ui/tree/treeModel';
|
||||
import { Iterator, ISequence } from 'vs/base/common/iterator';
|
||||
import { IVirtualDelegate, IRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { append, $ } from 'vs/base/browser/dom';
|
||||
import { Event, Relay, chain } from 'vs/base/common/event';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { tail2 } from 'vs/base/common/arrays';
|
||||
|
||||
function toTreeListOptions<T>(options?: IListOptions<T>): IListOptions<ITreeNode<T>> {
|
||||
if (!options) {
|
||||
|
@ -44,9 +45,9 @@ function toTreeListOptions<T>(options?: IListOptions<T>): IListOptions<ITreeNode
|
|||
};
|
||||
}
|
||||
|
||||
class TreeDelegate<T> implements IDelegate<ITreeNode<T>> {
|
||||
class TreeDelegate<T> implements IVirtualDelegate<ITreeNode<T>> {
|
||||
|
||||
constructor(private delegate: IDelegate<T>) { }
|
||||
constructor(private delegate: IVirtualDelegate<T>) { }
|
||||
|
||||
getHeight(element: ITreeNode<T>): number {
|
||||
return this.delegate.getHeight(element.element);
|
||||
|
@ -59,10 +60,17 @@ class TreeDelegate<T> implements IDelegate<ITreeNode<T>> {
|
|||
|
||||
interface ITreeListTemplateData<T> {
|
||||
twistie: HTMLElement;
|
||||
elementDisposable: IDisposable;
|
||||
templateData: T;
|
||||
}
|
||||
|
||||
function renderTwistie<T>(node: ITreeNode<T>, twistie: HTMLElement): void {
|
||||
if (node.children.length === 0 && !node.collapsible) {
|
||||
twistie.innerText = '';
|
||||
} else {
|
||||
twistie.innerText = node.collapsed ? '▹' : '◢';
|
||||
}
|
||||
}
|
||||
|
||||
class TreeRenderer<T, TTemplateData> implements IRenderer<ITreeNode<T>, ITreeListTemplateData<TTemplateData>> {
|
||||
|
||||
readonly templateId: string;
|
||||
|
@ -83,21 +91,22 @@ class TreeRenderer<T, TTemplateData> implements IRenderer<ITreeNode<T>, ITreeLis
|
|||
const contents = append(el, $('.tl-contents'));
|
||||
const templateData = this.renderer.renderTemplate(contents);
|
||||
|
||||
return { twistie, elementDisposable: Disposable.None, templateData };
|
||||
return { twistie, templateData };
|
||||
}
|
||||
|
||||
renderElement(node: ITreeNode<T>, index: number, templateData: ITreeListTemplateData<TTemplateData>): void {
|
||||
templateData.elementDisposable.dispose();
|
||||
|
||||
this.renderedNodes.set(node, templateData);
|
||||
templateData.elementDisposable = toDisposable(() => this.renderedNodes.delete(node));
|
||||
|
||||
templateData.twistie.innerText = node.children.length === 0 ? '' : (node.collapsed ? '▹' : '◢');
|
||||
templateData.twistie.style.width = `${10 + node.depth * 10}px`;
|
||||
renderTwistie(node, templateData.twistie);
|
||||
|
||||
this.renderer.renderElement(node.element, index, templateData.templateData);
|
||||
}
|
||||
|
||||
disposeElement(node: ITreeNode<T>): void {
|
||||
this.renderedNodes.delete(node);
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: ITreeListTemplateData<TTemplateData>): void {
|
||||
this.renderer.disposeTemplate(templateData.templateData);
|
||||
}
|
||||
|
@ -109,7 +118,7 @@ class TreeRenderer<T, TTemplateData> implements IRenderer<ITreeNode<T>, ITreeLis
|
|||
return;
|
||||
}
|
||||
|
||||
templateData.twistie.innerText = node.children.length === 0 ? '' : (node.collapsed ? '▹' : '◢');
|
||||
renderTwistie(node, templateData.twistie);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
@ -118,21 +127,12 @@ class TreeRenderer<T, TTemplateData> implements IRenderer<ITreeNode<T>, ITreeLis
|
|||
}
|
||||
}
|
||||
|
||||
function getLocation<T>(node: ITreeNode<T>): number[] {
|
||||
const location = [];
|
||||
|
||||
while (node.parent) {
|
||||
location.push(node.parent.children.indexOf(node));
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
return location.reverse();
|
||||
}
|
||||
|
||||
function isInputElement(e: HTMLElement): boolean {
|
||||
return e.tagName === 'INPUT' || e.tagName === 'TEXTAREA';
|
||||
}
|
||||
|
||||
export interface ITreeOptions<T> extends IListOptions<T> { }
|
||||
|
||||
export class Tree<T> implements IDisposable {
|
||||
|
||||
private view: List<ITreeNode<T>>;
|
||||
|
@ -141,9 +141,9 @@ export class Tree<T> implements IDisposable {
|
|||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
delegate: IDelegate<T>,
|
||||
delegate: IVirtualDelegate<T>,
|
||||
renderers: IRenderer<T, any>[],
|
||||
options?: IListOptions<T>
|
||||
options?: ITreeOptions<T>
|
||||
) {
|
||||
const treeDelegate = new TreeDelegate(delegate);
|
||||
|
||||
|
@ -168,13 +168,13 @@ export class Tree<T> implements IDisposable {
|
|||
onKeyDown.filter(e => e.keyCode === KeyCode.Space).on(this.onSpace, this, this.disposables);
|
||||
}
|
||||
|
||||
splice(location: number[], deleteCount: number, toInsert: IIterator<ITreeElement<T>> = empty()): IIterator<ITreeElement<T>> {
|
||||
splice(location: number[], deleteCount: number, toInsert: ISequence<ITreeElement<T>> = Iterator.empty()): Iterator<ITreeElement<T>> {
|
||||
return this.model.splice(location, deleteCount, toInsert);
|
||||
}
|
||||
|
||||
private onMouseClick(e: IListMouseEvent<ITreeNode<T>>): void {
|
||||
const node = e.element;
|
||||
const location = getLocation(node);
|
||||
const location = getNodeLocation(node);
|
||||
|
||||
this.model.toggleCollapsed(location);
|
||||
}
|
||||
|
@ -190,12 +190,17 @@ export class Tree<T> implements IDisposable {
|
|||
}
|
||||
|
||||
const node = nodes[0];
|
||||
const location = getLocation(node);
|
||||
const didCollapse = this.model.setCollapsed(location, true);
|
||||
const location = getNodeLocation(node);
|
||||
const didChange = this.model.setCollapsed(location, true);
|
||||
|
||||
if (!didCollapse) {
|
||||
console.log('should focus parent');
|
||||
// this.view.setFocus([]);
|
||||
if (!didChange) {
|
||||
if (location.length === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [parentLocation] = tail2(location);
|
||||
const parentListIndex = this.model.getListIndex(parentLocation);
|
||||
this.view.setFocus([parentListIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,8 +215,17 @@ export class Tree<T> implements IDisposable {
|
|||
}
|
||||
|
||||
const node = nodes[0];
|
||||
const location = getLocation(node);
|
||||
this.model.setCollapsed(location, false);
|
||||
const location = getNodeLocation(node);
|
||||
const didChange = this.model.setCollapsed(location, false);
|
||||
|
||||
if (!didChange) {
|
||||
if (node.children.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [focusedIndex] = this.view.getFocus();
|
||||
this.view.setFocus([focusedIndex + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
private onSpace(e: StandardKeyboardEvent): void {
|
||||
|
@ -225,7 +239,7 @@ export class Tree<T> implements IDisposable {
|
|||
}
|
||||
|
||||
const node = nodes[0];
|
||||
const location = getLocation(node);
|
||||
const location = getNodeLocation(node);
|
||||
this.model.toggleCollapsed(location);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,13 @@
|
|||
'use strict';
|
||||
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { IIterator, map, collect, iter, empty } from 'vs/base/common/iterator';
|
||||
import { Iterator, ISequence } from 'vs/base/common/iterator';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
||||
export interface ITreeElement<T> {
|
||||
readonly element: T;
|
||||
readonly children?: IIterator<ITreeElement<T>> | ITreeElement<T>[];
|
||||
readonly children?: Iterator<ITreeElement<T>> | ITreeElement<T>[];
|
||||
readonly collapsible?: boolean;
|
||||
readonly collapsed?: boolean;
|
||||
}
|
||||
|
||||
|
@ -20,6 +21,7 @@ export interface ITreeNode<T> {
|
|||
readonly element: T;
|
||||
readonly children: IMutableTreeNode<T>[];
|
||||
readonly depth: number;
|
||||
readonly collapsible: boolean;
|
||||
readonly collapsed: boolean;
|
||||
readonly visibleCount: number;
|
||||
}
|
||||
|
@ -49,11 +51,11 @@ function getVisibleNodes<T>(nodes: IMutableTreeNode<T>[], result: ITreeNode<T>[]
|
|||
return result;
|
||||
}
|
||||
|
||||
function getTreeElementIterator<T>(elements: IIterator<ITreeElement<T>> | ITreeElement<T>[] | undefined): IIterator<ITreeElement<T>> {
|
||||
function getTreeElementIterator<T>(elements: Iterator<ITreeElement<T>> | ITreeElement<T>[] | undefined): Iterator<ITreeElement<T>> {
|
||||
if (!elements) {
|
||||
return empty();
|
||||
return Iterator.empty();
|
||||
} else if (Array.isArray(elements)) {
|
||||
return iter(elements);
|
||||
return Iterator.iterate(elements);
|
||||
} else {
|
||||
return elements;
|
||||
}
|
||||
|
@ -61,15 +63,16 @@ function getTreeElementIterator<T>(elements: IIterator<ITreeElement<T>> | ITreeE
|
|||
|
||||
function treeElementToNode<T>(treeElement: ITreeElement<T>, parent: IMutableTreeNode<T>, visible: boolean, treeListElements: ITreeNode<T>[]): IMutableTreeNode<T> {
|
||||
const depth = parent.depth + 1;
|
||||
const { element, collapsed } = treeElement;
|
||||
const node = { parent, element, children: [], depth, collapsed: !!collapsed, visibleCount: 0 };
|
||||
const { element, collapsible, collapsed } = treeElement;
|
||||
const node = { parent, element, children: [], depth, collapsible: !!collapsible, collapsed: !!collapsed, visibleCount: 0 };
|
||||
|
||||
if (visible) {
|
||||
treeListElements.push(node);
|
||||
}
|
||||
|
||||
const children = getTreeElementIterator(treeElement.children);
|
||||
node.children = collect(map(children, el => treeElementToNode(el, node, visible && !treeElement.collapsed, treeListElements)));
|
||||
node.children = Iterator.collect(Iterator.map(children, el => treeElementToNode(el, node, visible && !treeElement.collapsed, treeListElements)));
|
||||
node.collapsible = node.collapsible || node.children.length > 0;
|
||||
node.visibleCount = 1 + getVisibleCount(node.children);
|
||||
|
||||
return node;
|
||||
|
@ -77,11 +80,22 @@ function treeElementToNode<T>(treeElement: ITreeElement<T>, parent: IMutableTree
|
|||
|
||||
function treeNodeToElement<T>(node: IMutableTreeNode<T>): ITreeElement<T> {
|
||||
const { element, collapsed } = node;
|
||||
const children = map(iter(node.children), treeNodeToElement);
|
||||
const children = Iterator.map(Iterator.iterate(node.children), treeNodeToElement);
|
||||
|
||||
return { element, children, collapsed };
|
||||
}
|
||||
|
||||
export function getNodeLocation<T>(node: ITreeNode<T>): number[] {
|
||||
const location = [];
|
||||
|
||||
while (node.parent) {
|
||||
location.push(node.parent.children.indexOf(node));
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
return location.reverse();
|
||||
}
|
||||
|
||||
export class TreeModel<T> {
|
||||
|
||||
private root: IMutableTreeNode<T> = {
|
||||
|
@ -89,6 +103,7 @@ export class TreeModel<T> {
|
|||
element: undefined,
|
||||
children: [],
|
||||
depth: 0,
|
||||
collapsible: false,
|
||||
collapsed: false,
|
||||
visibleCount: 1
|
||||
};
|
||||
|
@ -98,7 +113,7 @@ export class TreeModel<T> {
|
|||
|
||||
constructor(private list: ISpliceable<ITreeNode<T>>) { }
|
||||
|
||||
splice(location: number[], deleteCount: number, toInsert?: IIterator<ITreeElement<T>> | ITreeElement<T>[]): IIterator<ITreeElement<T>> {
|
||||
splice(location: number[], deleteCount: number, toInsert?: ISequence<ITreeElement<T>>): Iterator<ITreeElement<T>> {
|
||||
if (location.length === 0) {
|
||||
throw new Error('Invalid tree location');
|
||||
}
|
||||
|
@ -106,7 +121,7 @@ export class TreeModel<T> {
|
|||
const { parentNode, listIndex, visible } = this.findParentNode(location);
|
||||
const treeListElementsToInsert: ITreeNode<T>[] = [];
|
||||
const elementsToInsert = getTreeElementIterator(toInsert);
|
||||
const nodesToInsert = collect(map(elementsToInsert, el => treeElementToNode(el, parentNode, visible, treeListElementsToInsert)));
|
||||
const nodesToInsert = Iterator.collect(Iterator.map(elementsToInsert, el => treeElementToNode(el, parentNode, visible, treeListElementsToInsert)));
|
||||
const lastIndex = location[location.length - 1];
|
||||
const deletedNodes = parentNode.children.splice(lastIndex, deleteCount, ...nodesToInsert);
|
||||
const visibleDeleteCount = getVisibleCount(deletedNodes);
|
||||
|
@ -117,7 +132,11 @@ export class TreeModel<T> {
|
|||
this.list.splice(listIndex, visibleDeleteCount, treeListElementsToInsert);
|
||||
}
|
||||
|
||||
return map(iter(deletedNodes), treeNodeToElement);
|
||||
return Iterator.map(Iterator.iterate(deletedNodes), treeNodeToElement);
|
||||
}
|
||||
|
||||
getListIndex(location: number[]): number {
|
||||
return this.findNode(location).listIndex;
|
||||
}
|
||||
|
||||
setCollapsed(location: number[], collapsed: boolean): boolean {
|
||||
|
@ -131,6 +150,10 @@ export class TreeModel<T> {
|
|||
private _setCollapsed(location: number[], collapsed?: boolean | undefined): boolean {
|
||||
const { node, listIndex, visible } = this.findNode(location);
|
||||
|
||||
if (!node.collapsible) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof collapsed === 'undefined') {
|
||||
collapsed = !node.collapsed;
|
||||
}
|
||||
|
@ -142,6 +165,8 @@ export class TreeModel<T> {
|
|||
node.collapsed = collapsed;
|
||||
|
||||
if (visible) {
|
||||
this._onDidChangeCollapseState.fire(node);
|
||||
|
||||
let visibleCountDiff: number;
|
||||
|
||||
if (collapsed) {
|
||||
|
@ -162,8 +187,6 @@ export class TreeModel<T> {
|
|||
mutableNode.visibleCount += visibleCountDiff;
|
||||
mutableNode = mutableNode.parent;
|
||||
}
|
||||
|
||||
this._onDidChangeCollapseState.fire(node);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -5,74 +5,86 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
export interface IIteratorResult<T> {
|
||||
export interface IteratorResult<T> {
|
||||
readonly done: boolean;
|
||||
readonly value: T | undefined;
|
||||
}
|
||||
|
||||
export interface IIterator<T> {
|
||||
next(): IIteratorResult<T>;
|
||||
export interface Iterator<T> {
|
||||
next(): IteratorResult<T>;
|
||||
}
|
||||
|
||||
const _empty: IIterator<any> = {
|
||||
next() {
|
||||
return { done: true, value: undefined };
|
||||
export module Iterator {
|
||||
const _empty: Iterator<any> = {
|
||||
next() {
|
||||
return { done: true, value: undefined };
|
||||
}
|
||||
};
|
||||
|
||||
export function empty<T>(): Iterator<T> {
|
||||
return _empty;
|
||||
}
|
||||
};
|
||||
|
||||
export function empty<T>(): IIterator<T> {
|
||||
return _empty;
|
||||
}
|
||||
export function iterate<T>(array: T[], index = 0, length = array.length): Iterator<T> {
|
||||
return {
|
||||
next(): IteratorResult<T> {
|
||||
if (index >= length) {
|
||||
return { done: true, value: undefined };
|
||||
}
|
||||
|
||||
export function iter<T>(array: T[], index = 0, length = array.length): IIterator<T> {
|
||||
return {
|
||||
next(): IIteratorResult<T> {
|
||||
if (index >= length) {
|
||||
return { done: true, value: undefined };
|
||||
return { done: false, value: array[index++] };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return { done: false, value: array[index++] };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function map<T, R>(iterator: IIterator<T>, fn: (t: T) => R): IIterator<R> {
|
||||
return {
|
||||
next() {
|
||||
const { done, value } = iterator.next();
|
||||
return { done, value: done ? undefined : fn(value) };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function filter<T>(iterator: IIterator<T>, fn: (t: T) => boolean): IIterator<T> {
|
||||
return {
|
||||
next() {
|
||||
while (true) {
|
||||
export function map<T, R>(iterator: Iterator<T>, fn: (t: T) => R): Iterator<R> {
|
||||
return {
|
||||
next() {
|
||||
const { done, value } = iterator.next();
|
||||
return { done, value: done ? undefined : fn(value) };
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (done) {
|
||||
return { done, value: undefined };
|
||||
}
|
||||
export function filter<T>(iterator: Iterator<T>, fn: (t: T) => boolean): Iterator<T> {
|
||||
return {
|
||||
next() {
|
||||
while (true) {
|
||||
const { done, value } = iterator.next();
|
||||
|
||||
if (fn(value)) {
|
||||
return { done, value };
|
||||
if (done) {
|
||||
return { done, value: undefined };
|
||||
}
|
||||
|
||||
if (fn(value)) {
|
||||
return { done, value };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function forEach<T>(iterator: IIterator<T>, fn: (t: T) => void): void {
|
||||
for (let next = iterator.next(); !next.done; next = iterator.next()) {
|
||||
fn(next.value);
|
||||
export function forEach<T>(iterator: Iterator<T>, fn: (t: T) => void): void {
|
||||
for (let next = iterator.next(); !next.done; next = iterator.next()) {
|
||||
fn(next.value);
|
||||
}
|
||||
}
|
||||
|
||||
export function collect<T>(iterator: Iterator<T>): T[] {
|
||||
const result: T[] = [];
|
||||
forEach(iterator, value => result.push(value));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export function collect<T>(iterator: IIterator<T>): T[] {
|
||||
const result: T[] = [];
|
||||
forEach(iterator, value => result.push(value));
|
||||
return result;
|
||||
export type ISequence<T> = Iterator<T> | T[];
|
||||
|
||||
export function getSequenceIterator<T>(arg: Iterator<T> | T[]): Iterator<T> {
|
||||
if (Array.isArray(arg)) {
|
||||
return Iterator.iterate(arg);
|
||||
} else {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
export interface INextIterator<T> {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { IIterator } from 'vs/base/common/iterator';
|
||||
import { Iterator } from 'vs/base/common/iterator';
|
||||
|
||||
class Node<E> {
|
||||
element: E;
|
||||
|
@ -94,7 +94,7 @@ export class LinkedList<E> {
|
|||
};
|
||||
}
|
||||
|
||||
iterator(): IIterator<E> {
|
||||
iterator(): Iterator<E> {
|
||||
let element = {
|
||||
done: undefined,
|
||||
value: undefined,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { IIterator } from './iterator';
|
||||
import { Iterator } from './iterator';
|
||||
|
||||
export function values<V = any>(set: Set<V>): V[];
|
||||
export function values<K = any, V = any>(map: Map<K, V>): V[];
|
||||
|
@ -306,7 +306,7 @@ export class TernarySearchTree<E> {
|
|||
return node && node.value || candidate;
|
||||
}
|
||||
|
||||
findSuperstr(key: string): IIterator<E> {
|
||||
findSuperstr(key: string): Iterator<E> {
|
||||
let iter = this._iter.reset(key);
|
||||
let node = this._root;
|
||||
while (node) {
|
||||
|
@ -333,7 +333,7 @@ export class TernarySearchTree<E> {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
private _nodeIterator(node: TernarySearchTreeNode<E>): IIterator<E> {
|
||||
private _nodeIterator(node: TernarySearchTreeNode<E>): Iterator<E> {
|
||||
let res = {
|
||||
done: false,
|
||||
value: undefined
|
||||
|
|
|
@ -8,7 +8,7 @@ import * as path from 'path';
|
|||
import * as cp from 'child_process';
|
||||
import { fork } from 'vs/base/node/stdFork';
|
||||
import * as nls from 'vs/nls';
|
||||
import { PPromise, TPromise, TValueCallback, TProgressCallback, ErrorCallback } from 'vs/base/common/winjs.base';
|
||||
import { TPromise, TValueCallback, ErrorCallback } from 'vs/base/common/winjs.base';
|
||||
import * as Types from 'vs/base/common/types';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
@ -19,6 +19,8 @@ import { LineDecoder } from 'vs/base/node/decoder';
|
|||
import { CommandOptions, ForkOptions, SuccessData, Source, TerminateResponse, TerminateResponseCode, Executable } from 'vs/base/common/processes';
|
||||
export { CommandOptions, ForkOptions, SuccessData, Source, TerminateResponse, TerminateResponseCode };
|
||||
|
||||
export type TProgressCallback<T> = (progress: T) => void;
|
||||
|
||||
export interface LineData {
|
||||
line: string;
|
||||
source: Source;
|
||||
|
@ -152,18 +154,16 @@ export abstract class AbstractProcess<TProgressData> {
|
|||
return 'other';
|
||||
}
|
||||
|
||||
public start(): PPromise<SuccessData, TProgressData> {
|
||||
public start(pp: TProgressCallback<TProgressData>): TPromise<SuccessData> {
|
||||
if (Platform.isWindows && ((this.options && this.options.cwd && TPath.isUNC(this.options.cwd)) || !this.options && !this.options.cwd && TPath.isUNC(process.cwd()))) {
|
||||
return TPromise.wrapError(new Error(nls.localize('TaskRunner.UNC', 'Can\'t execute a shell command on a UNC drive.')));
|
||||
}
|
||||
return this.useExec().then((useExec) => {
|
||||
let cc: TValueCallback<SuccessData>;
|
||||
let ee: ErrorCallback;
|
||||
let pp: TProgressCallback<TProgressData>;
|
||||
let result = new PPromise<any, TProgressData>((c, e, p) => {
|
||||
let result = new TPromise<any>((c, e) => {
|
||||
cc = c;
|
||||
ee = e;
|
||||
pp = p;
|
||||
});
|
||||
|
||||
if (useExec) {
|
||||
|
|
|
@ -94,8 +94,8 @@ export interface IChannelClient {
|
|||
* channels (each from a separate client) to pick from.
|
||||
*/
|
||||
export interface IClientRouter {
|
||||
routeCall(command: string, arg: any): string;
|
||||
routeEvent(event: string, arg: any): string;
|
||||
routeCall(command: string, arg: any): TPromise<string>;
|
||||
routeEvent(event: string, arg: any): TPromise<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -433,24 +433,20 @@ export class IPCServer implements IChannelServer, IRoutingChannelClient, IDispos
|
|||
|
||||
getChannel<T extends IChannel>(channelName: string, router: IClientRouter): T {
|
||||
const call = (command: string, arg: any) => {
|
||||
const id = router.routeCall(command, arg);
|
||||
const channelPromise = router.routeCall(command, arg)
|
||||
.then(id => this.getClient(id))
|
||||
.then(client => client.getChannel(channelName));
|
||||
|
||||
if (!id) {
|
||||
return TPromise.wrapError(new Error('Client id should be provided'));
|
||||
}
|
||||
|
||||
return getDelayedChannel(this.getClient(id).then(client => client.getChannel(channelName)))
|
||||
return getDelayedChannel(channelPromise)
|
||||
.call(command, arg);
|
||||
};
|
||||
|
||||
const listen = (event: string, arg: any) => {
|
||||
const id = router.routeEvent(event, arg);
|
||||
const channelPromise = router.routeEvent(event, arg)
|
||||
.then(id => this.getClient(id))
|
||||
.then(client => client.getChannel(channelName));
|
||||
|
||||
if (!id) {
|
||||
return TPromise.wrapError(new Error('Client id should be provided'));
|
||||
}
|
||||
|
||||
return getDelayedChannel(this.getClient(id).then(client => client.getChannel(channelName)))
|
||||
return getDelayedChannel(channelPromise)
|
||||
.listen(event, arg);
|
||||
};
|
||||
|
||||
|
@ -462,6 +458,10 @@ export class IPCServer implements IChannelServer, IRoutingChannelClient, IDispos
|
|||
}
|
||||
|
||||
private getClient(clientId: string): TPromise<IChannelClient> {
|
||||
if (!clientId) {
|
||||
return TPromise.wrapError(new Error('Client id should be provided'));
|
||||
}
|
||||
|
||||
const client = this.channelClients[clientId];
|
||||
|
||||
if (client) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import * as assert from 'assert';
|
||||
import { ListView } from 'vs/base/browser/ui/list/listView';
|
||||
import { IDelegate, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { IVirtualDelegate, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { range } from 'vs/base/common/arrays';
|
||||
|
||||
suite('ListView', function () {
|
||||
|
@ -14,7 +14,7 @@ suite('ListView', function () {
|
|||
element.style.height = '200px';
|
||||
element.style.width = '200px';
|
||||
|
||||
const delegate: IDelegate<number> = {
|
||||
const delegate: IVirtualDelegate<number> = {
|
||||
getHeight() { return 20; },
|
||||
getTemplateId() { return 'template'; }
|
||||
};
|
||||
|
@ -25,6 +25,7 @@ suite('ListView', function () {
|
|||
templateId: 'template',
|
||||
renderTemplate() { templatesCount++; },
|
||||
renderElement() { },
|
||||
disposeElement() { },
|
||||
disposeTemplate() { templatesCount--; }
|
||||
};
|
||||
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
import * as assert from 'assert';
|
||||
import { TreeModel, ITreeNode } from 'vs/base/browser/ui/tree/treeModel';
|
||||
import { ISpliceable } from 'vs/base/browser/ui/list/splice';
|
||||
import { iter } from 'vs/base/common/iterator';
|
||||
import { ISpliceable } from 'vs/base/common/sequence';
|
||||
import { Iterator } from 'vs/base/common/iterator';
|
||||
|
||||
function toSpliceable<T>(arr: T[]): ISpliceable<T> {
|
||||
return {
|
||||
|
@ -33,7 +33,7 @@ suite('TreeModel2', function () {
|
|||
const list = [] as ITreeNode<number>[];
|
||||
const model = new TreeModel<number>(toSpliceable(list));
|
||||
|
||||
model.splice([0], 0, iter([
|
||||
model.splice([0], 0, Iterator.iterate([
|
||||
{ element: 0 },
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
|
@ -55,9 +55,9 @@ suite('TreeModel2', function () {
|
|||
const list = [] as ITreeNode<number>[];
|
||||
const model = new TreeModel<number>(toSpliceable(list));
|
||||
|
||||
model.splice([0], 0, iter([
|
||||
model.splice([0], 0, Iterator.iterate([
|
||||
{
|
||||
element: 0, children: iter([
|
||||
element: 0, children: Iterator.iterate([
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
|
@ -92,9 +92,9 @@ suite('TreeModel2', function () {
|
|||
const list = [] as ITreeNode<number>[];
|
||||
const model = new TreeModel<number>(toSpliceable(list));
|
||||
|
||||
model.splice([0], 0, iter([
|
||||
model.splice([0], 0, Iterator.iterate([
|
||||
{
|
||||
element: 0, collapsed: true, children: iter([
|
||||
element: 0, collapsed: true, children: Iterator.iterate([
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
|
@ -120,7 +120,7 @@ suite('TreeModel2', function () {
|
|||
const list = [] as ITreeNode<number>[];
|
||||
const model = new TreeModel<number>(toSpliceable(list));
|
||||
|
||||
model.splice([0], 0, iter([
|
||||
model.splice([0], 0, Iterator.iterate([
|
||||
{ element: 0 },
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
|
@ -145,9 +145,9 @@ suite('TreeModel2', function () {
|
|||
const list = [] as ITreeNode<number>[];
|
||||
const model = new TreeModel<number>(toSpliceable(list));
|
||||
|
||||
model.splice([0], 0, iter([
|
||||
model.splice([0], 0, Iterator.iterate([
|
||||
{
|
||||
element: 0, children: iter([
|
||||
element: 0, children: Iterator.iterate([
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
|
@ -179,9 +179,9 @@ suite('TreeModel2', function () {
|
|||
const list = [] as ITreeNode<number>[];
|
||||
const model = new TreeModel<number>(toSpliceable(list));
|
||||
|
||||
model.splice([0], 0, iter([
|
||||
model.splice([0], 0, Iterator.iterate([
|
||||
{
|
||||
element: 0, children: iter([
|
||||
element: 0, children: Iterator.iterate([
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
|
@ -207,9 +207,9 @@ suite('TreeModel2', function () {
|
|||
const list = [] as ITreeNode<number>[];
|
||||
const model = new TreeModel<number>(toSpliceable(list));
|
||||
|
||||
model.splice([0], 0, iter([
|
||||
model.splice([0], 0, Iterator.iterate([
|
||||
{
|
||||
element: 0, collapsed: true, children: iter([
|
||||
element: 0, collapsed: true, children: Iterator.iterate([
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
|
@ -232,9 +232,9 @@ suite('TreeModel2', function () {
|
|||
const list = [] as ITreeNode<number>[];
|
||||
const model = new TreeModel<number>(toSpliceable(list));
|
||||
|
||||
model.splice([0], 0, iter([
|
||||
model.splice([0], 0, Iterator.iterate([
|
||||
{
|
||||
element: 0, children: iter([
|
||||
element: 0, children: Iterator.iterate([
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
|
@ -263,9 +263,9 @@ suite('TreeModel2', function () {
|
|||
const list = [] as ITreeNode<number>[];
|
||||
const model = new TreeModel<number>(toSpliceable(list));
|
||||
|
||||
model.splice([0], 0, iter([
|
||||
model.splice([0], 0, Iterator.iterate([
|
||||
{
|
||||
element: 0, collapsed: true, children: iter([
|
||||
element: 0, collapsed: true, children: Iterator.iterate([
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
|
@ -303,7 +303,7 @@ suite('TreeModel2', function () {
|
|||
const list = [] as ITreeNode<number>[];
|
||||
const model = new TreeModel<number>(toSpliceable(list));
|
||||
|
||||
model.splice([0], 0, iter([
|
||||
model.splice([0], 0, Iterator.iterate([
|
||||
{
|
||||
element: 1, children: [
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { ResourceMap, TernarySearchTree, PathIterator, StringIterator, LinkedMap, Touch, LRUCache } from 'vs/base/common/map';
|
||||
import * as assert from 'assert';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { IIteratorResult } from 'vs/base/common/iterator';
|
||||
import { IteratorResult } from 'vs/base/common/iterator';
|
||||
|
||||
suite('Map', () => {
|
||||
|
||||
|
@ -419,7 +419,7 @@ suite('Map', () => {
|
|||
map.set('/user/foo/flip/flop', 3);
|
||||
map.set('/usr/foo', 4);
|
||||
|
||||
let item: IIteratorResult<number>;
|
||||
let item: IteratorResult<number>;
|
||||
let iter = map.findSuperstr('/user');
|
||||
|
||||
item = iter.next();
|
||||
|
|
|
@ -67,7 +67,8 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
|
|||
process.once('exit', () => dispose(disposables));
|
||||
|
||||
const environmentService = new EnvironmentService(initData.args, process.execPath);
|
||||
const logLevelClient = new LogLevelSetterChannelClient(server.getChannel('loglevel', { routeCall: () => 'main', routeEvent: () => 'main' }));
|
||||
const mainRoute = () => TPromise.as('main');
|
||||
const logLevelClient = new LogLevelSetterChannelClient(server.getChannel('loglevel', { routeCall: mainRoute, routeEvent: mainRoute }));
|
||||
const logService = new FollowerLogService(logLevelClient, createSpdLogService('sharedprocess', initData.logLevel, environmentService.logsPath));
|
||||
disposables.push(logService);
|
||||
|
||||
|
@ -78,21 +79,13 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
|
|||
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService));
|
||||
services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||
|
||||
const windowsChannel = server.getChannel('windows', { routeCall: () => 'main', routeEvent: () => 'main' });
|
||||
const windowsChannel = server.getChannel('windows', { routeCall: mainRoute, routeEvent: mainRoute });
|
||||
const windowsService = new WindowsChannelClient(windowsChannel);
|
||||
services.set(IWindowsService, windowsService);
|
||||
|
||||
const activeWindowManager = new ActiveWindowManager(windowsService);
|
||||
const dialogChannel = server.getChannel('dialog', {
|
||||
routeCall: () => {
|
||||
logService.info('Routing dialog call request to the client', activeWindowManager.activeClientId);
|
||||
return activeWindowManager.activeClientId;
|
||||
},
|
||||
routeEvent: () => {
|
||||
logService.info('Routing dialog listen request to the client', activeWindowManager.activeClientId);
|
||||
return activeWindowManager.activeClientId;
|
||||
}
|
||||
});
|
||||
const route = () => activeWindowManager.getActiveClientId();
|
||||
const dialogChannel = server.getChannel('dialog', { routeCall: route, routeEvent: route });
|
||||
services.set(IDialogService, new DialogChannelClient(dialogChannel));
|
||||
|
||||
const instantiationService = new InstantiationService(services);
|
||||
|
|
|
@ -426,7 +426,7 @@ export class CodeApplication {
|
|||
|
||||
// Create a URL handler which forwards to the last active window
|
||||
const activeWindowManager = new ActiveWindowManager(windowsService);
|
||||
const route = () => activeWindowManager.activeClientId;
|
||||
const route = () => activeWindowManager.getActiveClientId();
|
||||
const urlHandlerChannel = this.electronIpcServer.getChannel('urlHandler', { routeCall: route, routeEvent: route });
|
||||
const multiplexURLHandler = new URLHandlerChannelClient(urlHandlerChannel);
|
||||
|
||||
|
|
|
@ -662,11 +662,66 @@ export class CodeMenu {
|
|||
const terminal = this.createMenuItem(nls.localize({ key: 'miToggleTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal"), 'workbench.action.terminal.toggleTerminal');
|
||||
const problems = this.createMenuItem(nls.localize({ key: 'miMarker', comment: ['&& denotes a mnemonic'] }, "&&Problems"), 'workbench.actions.view.problems');
|
||||
|
||||
// Appearance
|
||||
|
||||
const appearanceMenu = new Menu();
|
||||
|
||||
const fullscreen = new MenuItem(this.withKeybinding('workbench.action.toggleFullScreen', { label: this.mnemonicLabel(nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "Toggle &&Full Screen")), click: () => this.windowsMainService.getLastActiveWindow().toggleFullScreen(), enabled: this.windowsMainService.getWindowCount() > 0 }));
|
||||
const toggleZenMode = this.createMenuItem(nls.localize('miToggleZenMode', "Toggle Zen Mode"), 'workbench.action.toggleZenMode');
|
||||
const toggleCenteredLayout = this.createMenuItem(nls.localize('miToggleCenteredLayout', "Toggle Centered Layout"), 'workbench.action.toggleCenteredLayout');
|
||||
const toggleMenuBar = this.createMenuItem(nls.localize({ key: 'miToggleMenuBar', comment: ['&& denotes a mnemonic'] }, "Toggle Menu &&Bar"), 'workbench.action.toggleMenuBar');
|
||||
|
||||
const toggleSidebar = this.createMenuItem(nls.localize({ key: 'miToggleSidebar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Side Bar"), 'workbench.action.toggleSidebarVisibility');
|
||||
|
||||
let moveSideBarLabel: string;
|
||||
if (this.currentSidebarLocation !== 'right') {
|
||||
moveSideBarLabel = nls.localize({ key: 'miMoveSidebarRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Right");
|
||||
} else {
|
||||
moveSideBarLabel = nls.localize({ key: 'miMoveSidebarLeft', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left");
|
||||
}
|
||||
|
||||
const moveSidebar = this.createMenuItem(moveSideBarLabel, 'workbench.action.toggleSidebarPosition');
|
||||
const togglePanel = this.createMenuItem(nls.localize({ key: 'miTogglePanel', comment: ['&& denotes a mnemonic'] }, "Toggle &&Panel"), 'workbench.action.togglePanel');
|
||||
|
||||
let statusBarLabel: string;
|
||||
if (this.currentStatusbarVisible) {
|
||||
statusBarLabel = nls.localize({ key: 'miHideStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Hide Status Bar");
|
||||
} else {
|
||||
statusBarLabel = nls.localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Show Status Bar");
|
||||
}
|
||||
const toggleStatusbar = this.createMenuItem(statusBarLabel, 'workbench.action.toggleStatusbarVisibility');
|
||||
|
||||
let activityBarLabel: string;
|
||||
if (this.currentActivityBarVisible) {
|
||||
activityBarLabel = nls.localize({ key: 'miHideActivityBar', comment: ['&& denotes a mnemonic'] }, "Hide &&Activity Bar");
|
||||
} else {
|
||||
activityBarLabel = nls.localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar");
|
||||
}
|
||||
const toggleActivtyBar = this.createMenuItem(activityBarLabel, 'workbench.action.toggleActivityBarVisibility');
|
||||
|
||||
const zoomIn = this.createMenuItem(nls.localize({ key: 'miZoomIn', comment: ['&& denotes a mnemonic'] }, "&&Zoom In"), 'workbench.action.zoomIn');
|
||||
const zoomOut = this.createMenuItem(nls.localize({ key: 'miZoomOut', comment: ['&& denotes a mnemonic'] }, "Zoom O&&ut"), 'workbench.action.zoomOut');
|
||||
const resetZoom = this.createMenuItem(nls.localize({ key: 'miZoomReset', comment: ['&& denotes a mnemonic'] }, "&&Reset Zoom"), 'workbench.action.zoomReset');
|
||||
|
||||
arrays.coalesce([
|
||||
fullscreen,
|
||||
toggleZenMode,
|
||||
toggleCenteredLayout,
|
||||
isWindows || isLinux ? toggleMenuBar : void 0,
|
||||
__separator__(),
|
||||
moveSidebar,
|
||||
toggleSidebar,
|
||||
togglePanel,
|
||||
toggleStatusbar,
|
||||
toggleActivtyBar,
|
||||
__separator__(),
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
resetZoom
|
||||
]).forEach(item => appearanceMenu.append(item));
|
||||
|
||||
const appearance = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miAppearance', comment: ['&& denotes a mnemonic'] }, "&&Appearance")), submenu: appearanceMenu });
|
||||
|
||||
// Editor Layout
|
||||
|
||||
const editorLayoutMenu = new Menu();
|
||||
|
@ -707,50 +762,18 @@ export class CodeMenu {
|
|||
|
||||
const editorLayout = new MenuItem({ label: this.mnemonicLabel(nls.localize({ key: 'miEditorLayout', comment: ['&& denotes a mnemonic'] }, "Editor &&Layout")), submenu: editorLayoutMenu });
|
||||
|
||||
// Workbench Layout
|
||||
const toggleSidebar = this.createMenuItem(nls.localize({ key: 'miToggleSidebar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Side Bar"), 'workbench.action.toggleSidebarVisibility');
|
||||
|
||||
let moveSideBarLabel: string;
|
||||
if (this.currentSidebarLocation !== 'right') {
|
||||
moveSideBarLabel = nls.localize({ key: 'miMoveSidebarRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Right");
|
||||
} else {
|
||||
moveSideBarLabel = nls.localize({ key: 'miMoveSidebarLeft', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left");
|
||||
}
|
||||
|
||||
const moveSidebar = this.createMenuItem(moveSideBarLabel, 'workbench.action.toggleSidebarPosition');
|
||||
const togglePanel = this.createMenuItem(nls.localize({ key: 'miTogglePanel', comment: ['&& denotes a mnemonic'] }, "Toggle &&Panel"), 'workbench.action.togglePanel');
|
||||
|
||||
let statusBarLabel: string;
|
||||
if (this.currentStatusbarVisible) {
|
||||
statusBarLabel = nls.localize({ key: 'miHideStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Hide Status Bar");
|
||||
} else {
|
||||
statusBarLabel = nls.localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Show Status Bar");
|
||||
}
|
||||
const toggleStatusbar = this.createMenuItem(statusBarLabel, 'workbench.action.toggleStatusbarVisibility');
|
||||
|
||||
let activityBarLabel: string;
|
||||
if (this.currentActivityBarVisible) {
|
||||
activityBarLabel = nls.localize({ key: 'miHideActivityBar', comment: ['&& denotes a mnemonic'] }, "Hide &&Activity Bar");
|
||||
} else {
|
||||
activityBarLabel = nls.localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar");
|
||||
}
|
||||
const toggleActivtyBar = this.createMenuItem(activityBarLabel, 'workbench.action.toggleActivityBarVisibility');
|
||||
|
||||
// Editor
|
||||
const toggleWordWrap = this.createMenuItem(nls.localize({ key: 'miToggleWordWrap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Word Wrap"), 'editor.action.toggleWordWrap');
|
||||
const toggleMinimap = this.createMenuItem(nls.localize({ key: 'miToggleMinimap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Minimap"), 'editor.action.toggleMinimap');
|
||||
const toggleRenderWhitespace = this.createMenuItem(nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "Toggle &&Render Whitespace"), 'editor.action.toggleRenderWhitespace');
|
||||
const toggleRenderControlCharacters = this.createMenuItem(nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Toggle &&Control Characters"), 'editor.action.toggleRenderControlCharacter');
|
||||
|
||||
// Zoom
|
||||
const zoomIn = this.createMenuItem(nls.localize({ key: 'miZoomIn', comment: ['&& denotes a mnemonic'] }, "&&Zoom In"), 'workbench.action.zoomIn');
|
||||
const zoomOut = this.createMenuItem(nls.localize({ key: 'miZoomOut', comment: ['&& denotes a mnemonic'] }, "Zoom O&&ut"), 'workbench.action.zoomOut');
|
||||
const resetZoom = this.createMenuItem(nls.localize({ key: 'miZoomReset', comment: ['&& denotes a mnemonic'] }, "&&Reset Zoom"), 'workbench.action.zoomReset');
|
||||
|
||||
arrays.coalesce([
|
||||
commands,
|
||||
openView,
|
||||
__separator__(),
|
||||
appearance,
|
||||
editorLayout,
|
||||
__separator__(),
|
||||
explorer,
|
||||
search,
|
||||
scm,
|
||||
|
@ -762,27 +785,10 @@ export class CodeMenu {
|
|||
debugConsole,
|
||||
terminal,
|
||||
__separator__(),
|
||||
fullscreen,
|
||||
toggleZenMode,
|
||||
toggleCenteredLayout,
|
||||
isWindows || isLinux ? toggleMenuBar : void 0,
|
||||
__separator__(),
|
||||
editorLayout,
|
||||
__separator__(),
|
||||
moveSidebar,
|
||||
toggleSidebar,
|
||||
togglePanel,
|
||||
toggleStatusbar,
|
||||
toggleActivtyBar,
|
||||
__separator__(),
|
||||
toggleWordWrap,
|
||||
toggleMinimap,
|
||||
toggleRenderWhitespace,
|
||||
toggleRenderControlCharacters,
|
||||
__separator__(),
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
resetZoom
|
||||
toggleRenderControlCharacters
|
||||
]).forEach(item => viewMenu.append(item));
|
||||
}
|
||||
|
||||
|
|
|
@ -282,19 +282,19 @@ const editorConfiguration: IConfigurationNode = {
|
|||
'type': 'number',
|
||||
'default': EDITOR_MODEL_DEFAULTS.tabSize,
|
||||
'minimum': 1,
|
||||
'description': nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overridden based on the file contents when `editor.detectIndentation` is on."),
|
||||
'description': nls.localize('tabSize', "The number of spaces a tab is equal to. This setting is overridden based on the file contents when [`editor.detectIndentation`](#editor.detectIndentation) is on."),
|
||||
'errorMessage': nls.localize('tabSize.errorMessage', "Expected 'number'. Note that the value \"auto\" has been replaced by the `editor.detectIndentation` setting.")
|
||||
},
|
||||
'editor.insertSpaces': {
|
||||
'type': 'boolean',
|
||||
'default': EDITOR_MODEL_DEFAULTS.insertSpaces,
|
||||
'description': nls.localize('insertSpaces', "Insert spaces when pressing Tab. This setting is overridden based on the file contents when `editor.detectIndentation` is on."),
|
||||
'description': nls.localize('insertSpaces', "Insert spaces when pressing Tab. This setting is overridden based on the file contents when [`editor.detectIndentation`](#editor.detectIndentation) is on."),
|
||||
'errorMessage': nls.localize('insertSpaces.errorMessage', "Expected 'boolean'. Note that the value \"auto\" has been replaced by the `editor.detectIndentation` setting.")
|
||||
},
|
||||
'editor.detectIndentation': {
|
||||
'type': 'boolean',
|
||||
'default': EDITOR_MODEL_DEFAULTS.detectIndentation,
|
||||
'description': nls.localize('detectIndentation', "When opening a file, `editor.tabSize` and `editor.insertSpaces` will be detected based on the file contents.")
|
||||
'description': nls.localize('detectIndentation', "When opening a file, [`editor.tabSize`](#editor.tabSize) and [`editor.insertSpaces`](#editor.insertSpaces) will be detected based on the file contents.")
|
||||
},
|
||||
'editor.roundedSelection': {
|
||||
'type': 'boolean',
|
||||
|
@ -440,7 +440,7 @@ const editorConfiguration: IConfigurationNode = {
|
|||
'- `ctrlCmd` refers to a value the setting can take and should not be localized.',
|
||||
'- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized.'
|
||||
]
|
||||
}, "The modifier to be used to add multiple cursors with the mouse. `ctrlCmd` maps to `Control` on Windows and Linux and to `Command` on macOS. The Go To Definition and Open Link mouse gestures will adapt such that they do not conflict with the multicursor modifier.")
|
||||
}, "The modifier to be used to add multiple cursors with the mouse. `ctrlCmd` maps to `Control` on Windows and Linux and to `Command` on macOS. The Go To Definition and Open Link mouse gestures will adapt such that they do not conflict with the multicursor modifier. [Read more](https://code.visualstudio.com/docs/editor/codebasics#_multicursor-modifier)")
|
||||
},
|
||||
'editor.multiCursorMergeOverlapping': {
|
||||
'type': 'boolean',
|
||||
|
|
|
@ -22,7 +22,7 @@ import { getWordAtText, ensureValidWordDefinition } from 'vs/editor/common/model
|
|||
import { createMonacoBaseAPI } from 'vs/editor/common/standalone/standaloneBase';
|
||||
import { IWordAtPosition, EndOfLineSequence } from 'vs/editor/common/model';
|
||||
import { globals } from 'vs/base/common/platform';
|
||||
import { IIterator } from 'vs/base/common/iterator';
|
||||
import { Iterator } from 'vs/base/common/iterator';
|
||||
|
||||
export interface IMirrorModel {
|
||||
readonly uri: URI;
|
||||
|
@ -59,7 +59,7 @@ export interface ICommonModel {
|
|||
getLinesContent(): string[];
|
||||
getLineCount(): number;
|
||||
getLineContent(lineNumber: number): string;
|
||||
createWordIterator(wordDefinition: RegExp): IIterator<string>;
|
||||
createWordIterator(wordDefinition: RegExp): Iterator<string>;
|
||||
getWordUntilPosition(position: IPosition, wordDefinition: RegExp): IWordAtPosition;
|
||||
getValueInRange(range: IRange): string;
|
||||
getWordAtPosition(position: IPosition, wordDefinition: RegExp): Range;
|
||||
|
@ -147,7 +147,7 @@ class MirrorModel extends BaseMirrorModel implements ICommonModel {
|
|||
};
|
||||
}
|
||||
|
||||
public createWordIterator(wordDefinition: RegExp): IIterator<string> {
|
||||
public createWordIterator(wordDefinition: RegExp): Iterator<string> {
|
||||
let obj = {
|
||||
done: false,
|
||||
value: ''
|
||||
|
|
|
@ -138,7 +138,7 @@ let showReferencesCommand: ICommandHandler = (accessor: ServicesAccessor, resour
|
|||
|
||||
return TPromise.as(controller.toggleWidget(
|
||||
new Range(position.lineNumber, position.column, position.lineNumber, position.column),
|
||||
createCancelablePromise(_ => Promise.reject(new ReferencesModel(references))),
|
||||
createCancelablePromise(_ => Promise.resolve(new ReferencesModel(references))),
|
||||
defaultReferenceSearchOptions)).then(() => true);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ import { onUnexpectedError } from 'vs/base/common/errors';
|
|||
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass } from 'vs/base/browser/dom';
|
||||
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
import { IDelegate, IListEvent, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { IVirtualDelegate, IListEvent, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
|
@ -173,7 +173,10 @@ class Renderer implements IRenderer<ICompletionItem, ISuggestionTemplateData> {
|
|||
data.readMore.onmousedown = null;
|
||||
data.readMore.onclick = null;
|
||||
}
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: ISuggestionTemplateData): void {
|
||||
|
@ -349,7 +352,7 @@ export interface ISelectedSuggestion {
|
|||
model: CompletionModel;
|
||||
}
|
||||
|
||||
export class SuggestWidget implements IContentWidget, IDelegate<ICompletionItem>, IDisposable {
|
||||
export class SuggestWidget implements IContentWidget, IVirtualDelegate<ICompletionItem>, IDisposable {
|
||||
|
||||
private static readonly ID: string = 'editor.widget.suggestWidget';
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ export class MenuId {
|
|||
static readonly MenubarRecentMenu = new MenuId();
|
||||
static readonly MenubarSelectionMenu = new MenuId();
|
||||
static readonly MenubarViewMenu = new MenuId();
|
||||
static readonly MenubarAppearanceMenu = new MenuId();
|
||||
static readonly MenubarLayoutMenu = new MenuId();
|
||||
static readonly MenubarGoMenu = new MenuId();
|
||||
static readonly MenubarDebugMenu = new MenuId();
|
||||
|
|
|
@ -27,12 +27,12 @@ class WindowRouter implements IClientRouter {
|
|||
|
||||
constructor(private windowId: number) { }
|
||||
|
||||
routeCall(): string {
|
||||
return `window:${this.windowId}`;
|
||||
routeCall(): TPromise<string> {
|
||||
return TPromise.as(`window:${this.windowId}`);
|
||||
}
|
||||
|
||||
routeEvent(): string {
|
||||
return `window:${this.windowId}`;
|
||||
routeEvent(): TPromise<string> {
|
||||
return TPromise.as(`window:${this.windowId}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import { createDecorator, IInstantiationService } from 'vs/platform/instantiatio
|
|||
import { IDisposable, toDisposable, combinedDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IContextKeyService, IContextKey, RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { PagedList, IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
|
||||
import { IDelegate, IRenderer, IListMouseEvent, IListTouchEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { IVirtualDelegate, IRenderer, IListMouseEvent, IListTouchEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
|
||||
import { attachListStyler, defaultListStyles, computeStyles } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
|
@ -208,7 +208,7 @@ export class WorkbenchList<T> extends List<T> {
|
|||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
delegate: IDelegate<T>,
|
||||
delegate: IVirtualDelegate<T>,
|
||||
renderers: IRenderer<T, any>[],
|
||||
options: IListOptions<T>,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
|
@ -279,7 +279,7 @@ export class WorkbenchPagedList<T> extends PagedList<T> {
|
|||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
delegate: IDelegate<number>,
|
||||
delegate: IVirtualDelegate<number>,
|
||||
renderers: IPagedRenderer<T, any>[],
|
||||
options: IListOptions<T>,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
|
|
|
@ -223,6 +223,11 @@ export const scrollbarSliderActiveBackground = registerColor('scrollbarSlider.ac
|
|||
|
||||
export const progressBarBackground = registerColor('progressBar.background', { dark: Color.fromHex('#0E70C0'), light: Color.fromHex('#0E70C0'), hc: contrastBorder }, nls.localize('progressBarBackground', "Background color of the progress bar that can show for long running operations."));
|
||||
|
||||
export const breadcrumbsForeground = registerColor('breadcrumb.breadcrumbsForeground', { light: Color.fromHex('#6C6C6C').transparent(.7), dark: Color.fromHex('#CCCCCC').transparent(.7), hc: Color.white.transparent(.7) }, nls.localize('breadcrumbsFocusForeground', "Color of focused breadcrumb items."));
|
||||
export const breadcrumbsFocusForeground = registerColor('breadcrumb.breadcrumbsFocusForeground', { light: '#6C6C6C', dark: '#CCCCCC', hc: Color.white }, nls.localize('breadcrumbsFocusForeground', "Color of focused breadcrumb items."));
|
||||
export const breadcrumbsActiveSelectionForeground = registerColor('breadcrumb.breadcrumbsActiveSelectionForeground', { light: '#6C6C6C', dark: '#CCCCCC', hc: Color.white }, nls.localize('breadcrumbsSelectedForegound', "Color of selected breadcrumb items."));
|
||||
export const breadcrumbsActiveSelectionBackground = registerColor('breadcrumb.breadcrumbsActiveSelectionBackground', { light: '#F3F3F3', dark: '#252526', hc: Color.black }, nls.localize('breadcrumbsSelectedBackground', "Background color of selected breadcrumb items."));
|
||||
|
||||
/**
|
||||
* Editor background color.
|
||||
* Because of bug https://monacotools.visualstudio.com/DefaultCollection/Monaco/_workitems/edit/13254
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
'use strict';
|
||||
|
||||
import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, lighten, badgeBackground, badgeForeground, progressBarBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, lighten, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionBackground, breadcrumbsActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
|
@ -265,28 +265,22 @@ export function attachStylerCallback(themeService: IThemeService, colors: { [nam
|
|||
|
||||
export interface IBreadcrumbsWidgetStyleOverrides extends IStyleOverrides {
|
||||
breadcrumbsBackground?: ColorIdentifier;
|
||||
breadcrumbsItemHoverBackground?: ColorIdentifier;
|
||||
breadcrumbsItemHoverForeground?: ColorIdentifier;
|
||||
breadcrumbsItemFocusBackground?: ColorIdentifier;
|
||||
breadcrumbsItemFocusForeground?: ColorIdentifier;
|
||||
breadcrumbsActiveItemSelectionBackground?: ColorIdentifier;
|
||||
breadcrumbsActiveItemSelectionForeground?: ColorIdentifier;
|
||||
breadcrumbsInactiveItemSelectionBackground?: ColorIdentifier;
|
||||
breadcrumbsInactiveItemSelectionForeground?: ColorIdentifier;
|
||||
breadcrumbsForeground?: ColorIdentifier;
|
||||
breadcrumbsHoverBackground?: ColorIdentifier;
|
||||
breadcrumbsHoverForeground?: ColorIdentifier;
|
||||
breadcrumbsFocusForeground?: ColorIdentifier;
|
||||
breadcrumbsFocusAndSelectionBackground?: ColorIdentifier;
|
||||
breadcrumbsFocusAndSelectionForeground?: ColorIdentifier;
|
||||
}
|
||||
|
||||
export const defaultBreadcrumbsStyles = <IBreadcrumbsWidgetStyleOverrides>{
|
||||
breadcrumbsBackground: editorBackground,
|
||||
breadcrumbsItemHoverBackground: listHoverBackground,
|
||||
breadcrumbsItemHoverForeground: listHoverForeground,
|
||||
breadcrumbsItemFocusBackground: listFocusBackground,
|
||||
breadcrumbsItemFocusForeground: listFocusForeground,
|
||||
breadcrumbsItemSelectionBackground: listActiveSelectionBackground,
|
||||
breadcrumbsItemSelectionForeground: listActiveSelectionForeground,
|
||||
breadcrumbsActiveItemSelectionBackground: listActiveSelectionBackground,
|
||||
breadcrumbsActiveItemSelectionForeground: listActiveSelectionForeground,
|
||||
breadcrumbsInactiveItemSelectionBackground: editorBackground,
|
||||
breadcrumbsInactiveItemSelectionForeground: listInactiveSelectionForeground,
|
||||
breadcrumbsForeground: breadcrumbsForeground,
|
||||
breadcrumbsHoverBackground: editorBackground,
|
||||
breadcrumbsHoverForeground: breadcrumbsFocusForeground,
|
||||
breadcrumbsFocusForeground: breadcrumbsFocusForeground,
|
||||
breadcrumbsFocusAndSelectionBackground: breadcrumbsActiveSelectionBackground,
|
||||
breadcrumbsFocusAndSelectionForeground: breadcrumbsActiveSelectionForeground,
|
||||
};
|
||||
|
||||
export function attachBreadcrumbsStyler(widget: IThemable, themeService: IThemeService, style?: IBreadcrumbsWidgetStyleOverrides): IDisposable {
|
||||
|
|
|
@ -162,6 +162,7 @@ export interface IWindowsService {
|
|||
getWindowCount(): TPromise<number>;
|
||||
log(severity: string, ...messages: string[]): TPromise<void>;
|
||||
showItemInFolder(path: string): TPromise<void>;
|
||||
getActiveWindowId(): TPromise<number | undefined>;
|
||||
|
||||
// This needs to be handled from browser process to prevent
|
||||
// foreground ordering issues on Windows
|
||||
|
@ -357,19 +358,31 @@ export interface IRunActionInWindowRequest {
|
|||
export class ActiveWindowManager implements IDisposable {
|
||||
|
||||
private disposables: IDisposable[] = [];
|
||||
private _activeWindowId: number;
|
||||
private firstActiveWindowIdPromise: TPromise<any> | null;
|
||||
private _activeWindowId: number | undefined;
|
||||
|
||||
constructor(@IWindowsService windowsService: IWindowsService) {
|
||||
const onActiveWindowChange = latch(anyEvent(windowsService.onWindowOpen, windowsService.onWindowFocus));
|
||||
onActiveWindowChange(this.setActiveWindow, this, this.disposables);
|
||||
|
||||
this.firstActiveWindowIdPromise = windowsService.getActiveWindowId()
|
||||
.then(id => (typeof this._activeWindowId === 'undefined') && this.setActiveWindow(id));
|
||||
}
|
||||
|
||||
private setActiveWindow(windowId: number) {
|
||||
if (this.firstActiveWindowIdPromise) {
|
||||
this.firstActiveWindowIdPromise = null;
|
||||
}
|
||||
|
||||
this._activeWindowId = windowId;
|
||||
}
|
||||
|
||||
get activeClientId(): string {
|
||||
return `window:${this._activeWindowId}`;
|
||||
getActiveClientId(): TPromise<string> {
|
||||
if (this.firstActiveWindowIdPromise) {
|
||||
return this.firstActiveWindowIdPromise;
|
||||
}
|
||||
|
||||
return TPromise.as(`window:${this._activeWindowId}`);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
|
|
|
@ -68,6 +68,7 @@ export interface IWindowsChannel extends IChannel {
|
|||
call(command: 'toggleSharedProcess'): TPromise<void>;
|
||||
call(command: 'log', arg: [string, string[]]): TPromise<void>;
|
||||
call(command: 'showItemInFolder', arg: string): TPromise<void>;
|
||||
call(command: 'getActiveWindowId'): TPromise<number>;
|
||||
call(command: 'openExternal', arg: string): TPromise<boolean>;
|
||||
call(command: 'startCrashReporter', arg: CrashReporterStartOptions): TPromise<void>;
|
||||
call(command: 'openAccessibilityOptions'): TPromise<void>;
|
||||
|
@ -166,6 +167,7 @@ export class WindowsChannel implements IWindowsChannel {
|
|||
case 'quit': return this.service.quit();
|
||||
case 'log': return this.service.log(arg[0], arg[1]);
|
||||
case 'showItemInFolder': return this.service.showItemInFolder(arg);
|
||||
case 'getActiveWindowId': return this.service.getActiveWindowId();
|
||||
case 'openExternal': return this.service.openExternal(arg);
|
||||
case 'startCrashReporter': return this.service.startCrashReporter(arg);
|
||||
case 'openAccessibilityOptions': return this.service.openAccessibilityOptions();
|
||||
|
@ -364,6 +366,10 @@ export class WindowsChannelClient implements IWindowsService {
|
|||
return this.channel.call('showItemInFolder', path);
|
||||
}
|
||||
|
||||
getActiveWindowId(): TPromise<number | undefined> {
|
||||
return this.channel.call('getActiveWindowId');
|
||||
}
|
||||
|
||||
openExternal(url: string): TPromise<boolean> {
|
||||
return this.channel.call('openExternal', url);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import product from 'vs/platform/node/product';
|
|||
import { IWindowsService, OpenContext, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult, IDevToolsOptions } from 'vs/platform/windows/common/windows';
|
||||
import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment';
|
||||
import { shell, crashReporter, app, Menu, clipboard, BrowserWindow } from 'electron';
|
||||
import { Event, fromNodeEventEmitter, mapEvent, filterEvent, anyEvent } from 'vs/base/common/event';
|
||||
import { Event, fromNodeEventEmitter, mapEvent, filterEvent, anyEvent, latch } from 'vs/base/common/event';
|
||||
import { IURLService, IURLHandler } from 'vs/platform/url/common/url';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
|
||||
import { IWindowsMainService, ISharedProcess } from 'vs/platform/windows/electron-main/windows';
|
||||
|
@ -32,6 +32,8 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
|
|||
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
private _activeWindowId: number | undefined;
|
||||
|
||||
readonly onWindowOpen: Event<number> = filterEvent(fromNodeEventEmitter(app, 'browser-window-created', (_, w: Electron.BrowserWindow) => w.id), id => !!this.windowsMainService.getWindowById(id));
|
||||
readonly onWindowFocus: Event<number> = anyEvent(
|
||||
mapEvent(filterEvent(mapEvent(this.windowsMainService.onWindowsCountChanged, () => this.windowsMainService.getLastActiveWindow()), w => !!w), w => w.id),
|
||||
|
@ -54,6 +56,10 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
|
|||
@ILogService private logService: ILogService
|
||||
) {
|
||||
urlService.registerHandler(this);
|
||||
|
||||
// remember last active window id
|
||||
latch(anyEvent(this.onWindowOpen, this.onWindowFocus))
|
||||
(id => this._activeWindowId = id, null, this.disposables);
|
||||
}
|
||||
|
||||
pickFileFolderAndOpen(options: INativeOpenDialogOptions): TPromise<void> {
|
||||
|
@ -435,6 +441,10 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable
|
|||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
getActiveWindowId(): TPromise<number | undefined> {
|
||||
return TPromise.as(this._activeWindowId);
|
||||
}
|
||||
|
||||
openExternal(url: string): TPromise<boolean> {
|
||||
this.logService.trace('windowsService#openExternal');
|
||||
return TPromise.as(shell.openExternal(url));
|
||||
|
|
|
@ -332,7 +332,7 @@ namespace TaskDTO {
|
|||
let definition = TaskDefinitionDTO.to(task.definition, executeOnly);
|
||||
let id = `${task.source.extensionId}.${definition._key}`;
|
||||
let result: ContributedTask = {
|
||||
_id: id, // uuidMap.getUUID(identifier),
|
||||
_id: id, // uuidMap.getUUID(identifier)
|
||||
_source: source,
|
||||
_label: label,
|
||||
type: definition.type,
|
||||
|
|
|
@ -71,11 +71,10 @@ export class ExtHostProgress implements ExtHostProgressShape {
|
|||
|
||||
function mergeProgress(result: IProgressStep, currentValue: IProgressStep): IProgressStep {
|
||||
result.message = currentValue.message;
|
||||
if (typeof currentValue.increment === 'number' && typeof result.message === 'number') {
|
||||
result.increment += currentValue.increment;
|
||||
} else if (typeof currentValue.increment === 'number') {
|
||||
if (typeof currentValue.increment === 'number') {
|
||||
result.increment = currentValue.increment;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ import * as strings from 'vs/base/common/strings';
|
|||
import URI, { UriComponents } from 'vs/base/common/uri';
|
||||
import { PPromise, TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as extfs from 'vs/base/node/extfs';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { IFileMatch, IFolderQuery, IPatternInfo, IRawSearchQuery, ISearchCompleteStats, ISearchQuery } from 'vs/platform/search/common/search';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostSearchShape, IMainContext, MainContext, MainThreadSearchShape } from './extHost.protocol';
|
||||
|
@ -30,9 +29,9 @@ export class ExtHostSearch implements ExtHostSearchShape {
|
|||
|
||||
private _fileSearchManager: FileSearchManager;
|
||||
|
||||
constructor(mainContext: IMainContext, private _schemeTransformer: ISchemeTransformer, private _extfs = extfs, private _pfs = pfs) {
|
||||
constructor(mainContext: IMainContext, private _schemeTransformer: ISchemeTransformer, private _extfs = extfs) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadSearch);
|
||||
this._fileSearchManager = new FileSearchManager(this._pfs);
|
||||
this._fileSearchManager = new FileSearchManager();
|
||||
}
|
||||
|
||||
private _transformScheme(scheme: string): string {
|
||||
|
@ -518,7 +517,7 @@ class FileSearchEngine {
|
|||
|
||||
private globalExcludePattern: glob.ParsedExpression;
|
||||
|
||||
constructor(private config: ISearchQuery, private provider: vscode.SearchProvider, private _pfs: typeof pfs) {
|
||||
constructor(private config: ISearchQuery, private provider: vscode.SearchProvider) {
|
||||
this.filePattern = config.filePattern;
|
||||
this.includePattern = config.includePattern && glob.parse(config.includePattern);
|
||||
this.maxResults = config.maxResults || null;
|
||||
|
@ -633,19 +632,6 @@ class FileSearchEngine {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (noSiblingsClauses && this.isLimitHit) {
|
||||
// If the limit was hit, check whether filePattern is an exact relative match because it must be included
|
||||
return this.checkFilePatternRelativeMatch(fq.folder).then(({ exists, size }) => {
|
||||
if (exists) {
|
||||
onResult({
|
||||
base: fq.folder,
|
||||
relativePath: this.filePattern,
|
||||
basename: path.basename(this.filePattern),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.matchDirectoryTree(tree, queryTester, onResult);
|
||||
return null;
|
||||
}).then(
|
||||
|
@ -743,24 +729,6 @@ class FileSearchEngine {
|
|||
matchDirectory(rootEntries);
|
||||
}
|
||||
|
||||
private checkFilePatternRelativeMatch(base: URI): TPromise<{ exists: boolean, size?: number }> {
|
||||
if (!this.filePattern || path.isAbsolute(this.filePattern) || base.scheme !== 'file') {
|
||||
return TPromise.wrap({ exists: false });
|
||||
}
|
||||
|
||||
const absolutePath = path.join(base.fsPath, this.filePattern);
|
||||
return this._pfs.stat(absolutePath).then(stat => {
|
||||
return {
|
||||
exists: !stat.isDirectory(),
|
||||
size: stat.size
|
||||
};
|
||||
}, err => {
|
||||
return {
|
||||
exists: false
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private matchFile(onResult: (result: IInternalFileMatch) => void, candidate: IInternalFileMatch): void {
|
||||
if (this.isFilePatternMatch(candidate.relativePath) && (!this.includePattern || this.includePattern(candidate.relativePath, candidate.basename))) {
|
||||
if (this.exists || (this.maxResults && this.resultCount >= this.maxResults)) {
|
||||
|
@ -800,12 +768,10 @@ class FileSearchManager {
|
|||
|
||||
private readonly expandedCacheKeys = new Map<string, string[]>();
|
||||
|
||||
constructor(private _pfs: typeof pfs) { }
|
||||
|
||||
fileSearch(config: ISearchQuery, provider: vscode.SearchProvider): PPromise<ISearchCompleteStats, IFileMatch[]> {
|
||||
let searchP: PPromise;
|
||||
return new PPromise<ISearchCompleteStats, IFileMatch[]>((c, e, p) => {
|
||||
const engine = new FileSearchEngine(config, provider, this._pfs);
|
||||
const engine = new FileSearchEngine(config, provider);
|
||||
|
||||
searchP = this.doSearch(engine, FileSearchManager.BATCH_SIZE).then(
|
||||
result => {
|
||||
|
|
|
@ -30,9 +30,12 @@
|
|||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part > .title > .title-label span {
|
||||
.monaco-workbench > .part > .title > .title-label h2 {
|
||||
font-size: 11px;
|
||||
cursor: default;
|
||||
font-weight: normal;
|
||||
-webkit-margin-before: 0;
|
||||
-webkit-margin-after: 0;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part > .title > .title-label a {
|
||||
|
|
|
@ -434,7 +434,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
|||
$(parent).div({
|
||||
'class': 'title-label'
|
||||
}, div => {
|
||||
titleLabel = div.span();
|
||||
titleLabel = div.element('h2');
|
||||
});
|
||||
|
||||
const $this = this;
|
||||
|
|
47
src/vs/workbench/browser/parts/editor/breadcrumbs.ts
Normal file
47
src/vs/workbench/browser/parts/editor/breadcrumbs.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { BreadcrumbsWidget } from 'vs/base/browser/ui/breadcrumbs/breadcrumbsWidget';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { GroupIdentifier } from 'vs/workbench/common/editor';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
export const IBreadcrumbsService = createDecorator<IBreadcrumbsService>('IEditorBreadcrumbsService');
|
||||
|
||||
export interface IBreadcrumbsService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
register(group: GroupIdentifier, widget: BreadcrumbsWidget): IDisposable;
|
||||
|
||||
getWidget(group: GroupIdentifier): BreadcrumbsWidget;
|
||||
}
|
||||
|
||||
|
||||
export class BreadcrumbsService implements IBreadcrumbsService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
private readonly _map = new Map<number, BreadcrumbsWidget>();
|
||||
|
||||
register(group: number, widget: BreadcrumbsWidget): IDisposable {
|
||||
if (this._map.has(group)) {
|
||||
throw new Error(`group (${group}) has already a widget`);
|
||||
}
|
||||
this._map.set(group, widget);
|
||||
return {
|
||||
dispose: () => this._map.delete(group)
|
||||
};
|
||||
}
|
||||
|
||||
getWidget(group: number): BreadcrumbsWidget {
|
||||
return this._map.get(group);
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IBreadcrumbsService, BreadcrumbsService);
|
|
@ -12,11 +12,11 @@ import { compareFileNames } from 'vs/base/common/comparers';
|
|||
import { debounceEvent, Emitter, Event } from 'vs/base/common/event';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { dispose, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { dirname, isEqual } from 'vs/base/common/resources';
|
||||
import { dirname, isEqual, basenameOrAuthority } from 'vs/base/common/resources';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IDataSource, IRenderer, ISelectionEvent, ISorter, ITree, ITreeConfiguration } from 'vs/base/parts/tree/browser/tree';
|
||||
import 'vs/css!./media/editorbreadcrumbs';
|
||||
import 'vs/css!./media/breadcrumbscontrol';
|
||||
import { ICodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { OutlineElement, OutlineGroup, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel';
|
||||
|
@ -35,13 +35,15 @@ import { attachBreadcrumbsStyler } from 'vs/platform/theme/common/styler';
|
|||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { FileLabel } from 'vs/workbench/browser/labels';
|
||||
import { BreadcrumbElement, EditorBreadcrumbsModel, FileElement } from 'vs/workbench/browser/parts/editor/editorBreadcrumbsModel';
|
||||
import { BreadcrumbElement, EditorBreadcrumbsModel, FileElement } from 'vs/workbench/browser/parts/editor/breadcrumbsModel';
|
||||
import { EditorGroupView } from 'vs/workbench/browser/parts/editor/editorGroupView';
|
||||
import { EditorInput } from 'vs/workbench/common/editor';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorBreadcrumbs, IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { IBreadcrumbsService } from 'vs/workbench/browser/parts/editor/breadcrumbs';
|
||||
import { editorBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { symbolKindToCssClass } from 'vs/editor/common/modes';
|
||||
|
||||
class Item extends BreadcrumbsItem {
|
||||
|
||||
|
@ -49,6 +51,7 @@ class Item extends BreadcrumbsItem {
|
|||
|
||||
constructor(
|
||||
readonly element: BreadcrumbElement,
|
||||
readonly options: IBreadcrumbsControlOptions,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService
|
||||
) {
|
||||
super();
|
||||
|
@ -74,12 +77,20 @@ class Item extends BreadcrumbsItem {
|
|||
render(container: HTMLElement): void {
|
||||
if (this.element instanceof FileElement) {
|
||||
// file/folder
|
||||
let label = this._instantiationService.createInstance(FileLabel, container, {});
|
||||
label.setFile(this.element.uri, {
|
||||
hidePath: true,
|
||||
fileKind: this.element.isFile ? FileKind.FILE : FileKind.FOLDER
|
||||
});
|
||||
this._disposables.push(label);
|
||||
if (this.options.showIcons) {
|
||||
let label = this._instantiationService.createInstance(FileLabel, container, {});
|
||||
label.setFile(this.element.uri, {
|
||||
hidePath: true,
|
||||
fileKind: this.element.isFile ? FileKind.FILE : FileKind.FOLDER,
|
||||
fileDecorations: { colors: this.options.showDecorationColors, badges: false }
|
||||
});
|
||||
this._disposables.push(label);
|
||||
|
||||
} else {
|
||||
let label = new IconLabel(container);
|
||||
label.setValue(basenameOrAuthority(this.element.uri));
|
||||
this._disposables.push(label);
|
||||
}
|
||||
|
||||
} else if (this.element instanceof OutlineGroup) {
|
||||
// provider
|
||||
|
@ -89,14 +100,28 @@ class Item extends BreadcrumbsItem {
|
|||
|
||||
} else if (this.element instanceof OutlineElement) {
|
||||
// symbol
|
||||
|
||||
if (this.options.showIcons) {
|
||||
let icon = document.createElement('div');
|
||||
icon.className = `symbol-icon ${symbolKindToCssClass(this.element.symbol.kind)}`;
|
||||
container.appendChild(icon);
|
||||
}
|
||||
|
||||
let label = new IconLabel(container);
|
||||
label.setValue(this.element.symbol.name);
|
||||
label.setValue(this.element.symbol.name.replace(/\r|\n|\r\n/g, '\u23CE'));
|
||||
this._disposables.push(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class EditorBreadcrumbs implements IEditorBreadcrumbs {
|
||||
export interface IBreadcrumbsControlOptions {
|
||||
showIcons: boolean;
|
||||
showDecorationColors: boolean;
|
||||
}
|
||||
|
||||
export class BreadcrumbsControl {
|
||||
|
||||
static HEIGHT = 25;
|
||||
|
||||
static CK_BreadcrumbsVisible = new RawContextKey('breadcrumbsVisible', false);
|
||||
static CK_BreadcrumbsActive = new RawContextKey('breadcrumbsActive', false);
|
||||
|
@ -104,17 +129,16 @@ export class EditorBreadcrumbs implements IEditorBreadcrumbs {
|
|||
private readonly _ckBreadcrumbsVisible: IContextKey<boolean>;
|
||||
private readonly _ckBreadcrumbsActive: IContextKey<boolean>;
|
||||
|
||||
private readonly _cfEnabled: Config<boolean>;
|
||||
|
||||
private readonly _disposables = new Array<IDisposable>();
|
||||
private readonly _domNode: HTMLDivElement;
|
||||
readonly domNode: HTMLDivElement;
|
||||
private readonly _widget: BreadcrumbsWidget;
|
||||
private _disposables = new Array<IDisposable>();
|
||||
|
||||
private _breadcrumbsDisposables = new Array<IDisposable>();
|
||||
private _breadcrumbsPickerShowing = false;
|
||||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
private readonly _options: IBreadcrumbsControlOptions,
|
||||
private readonly _editorGroup: EditorGroupView,
|
||||
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
|
||||
@IContextViewService private readonly _contextViewService: IContextViewService,
|
||||
|
@ -124,127 +148,105 @@ export class EditorBreadcrumbs implements IEditorBreadcrumbs {
|
|||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IThemeService private readonly _themeService: IThemeService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IBreadcrumbsService breadcrumbsService: IBreadcrumbsService,
|
||||
) {
|
||||
this._domNode = document.createElement('div');
|
||||
dom.addClasses(this._domNode, 'editor-breadcrumbs', 'show-file-icons');
|
||||
dom.append(container, this._domNode);
|
||||
this.domNode = document.createElement('div');
|
||||
dom.addClasses(this.domNode, 'breadcrumbs-control');
|
||||
dom.append(container, this.domNode);
|
||||
|
||||
this._widget = new BreadcrumbsWidget(this._domNode);
|
||||
this._widget.onDidSelectItem(this._onDidSelectItem, this, this._disposables);
|
||||
this._widget.onDidFocusItem(this._onDidSelectItem, this, this._disposables);
|
||||
this._widget = new BreadcrumbsWidget(this.domNode);
|
||||
this._widget.onDidSelectItem(this._onSelectEvent, this, this._disposables);
|
||||
this._widget.onDidFocusItem(this._onFocusEvent, this, this._disposables);
|
||||
this._widget.onDidChangeFocus(this._updateCkBreadcrumbsActive, this, this._disposables);
|
||||
this._disposables.push(attachBreadcrumbsStyler(this._widget, this._themeService));
|
||||
|
||||
this._cfEnabled = Config.create(configurationService, 'breadcrumbs.enabled');
|
||||
this._disposables.push(this._cfEnabled.onDidChange(value => {
|
||||
if (!value) {
|
||||
this.closeEditor(undefined);
|
||||
this._editorGroup.relayout();
|
||||
} else if (this._editorGroup.activeEditor) {
|
||||
this.openEditor(this._editorGroup.activeEditor);
|
||||
this._editorGroup.relayout();
|
||||
}
|
||||
}));
|
||||
this._ckBreadcrumbsVisible = BreadcrumbsControl.CK_BreadcrumbsVisible.bindTo(this._contextKeyService);
|
||||
this._ckBreadcrumbsActive = BreadcrumbsControl.CK_BreadcrumbsActive.bindTo(this._contextKeyService);
|
||||
|
||||
this._ckBreadcrumbsVisible = EditorBreadcrumbs.CK_BreadcrumbsVisible.bindTo(this._contextKeyService);
|
||||
this._ckBreadcrumbsActive = EditorBreadcrumbs.CK_BreadcrumbsActive.bindTo(this._contextKeyService);
|
||||
this._disposables.push(breadcrumbsService.register(this._editorGroup.id, this._widget));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
dispose(this._disposables);
|
||||
this._widget.dispose();
|
||||
this._disposables = dispose(this._disposables);
|
||||
this._breadcrumbsDisposables = dispose(this._breadcrumbsDisposables);
|
||||
this._ckBreadcrumbsVisible.reset();
|
||||
this._cfEnabled.dispose();
|
||||
}
|
||||
|
||||
getPreferredHeight(): number {
|
||||
return this._cfEnabled.value ? 25 : 0;
|
||||
this._ckBreadcrumbsActive.reset();
|
||||
this._widget.dispose();
|
||||
this.domNode.remove();
|
||||
}
|
||||
|
||||
layout(dim: dom.Dimension): void {
|
||||
this._domNode.style.width = `${dim.width}px`;
|
||||
this._domNode.style.height = `${dim.height}px`;
|
||||
this._widget.layout(dim);
|
||||
}
|
||||
|
||||
setActive(value: boolean): void {
|
||||
dom.toggleClass(this._domNode, 'active', value);
|
||||
}
|
||||
update(): void {
|
||||
const input = this._editorGroup.activeEditor;
|
||||
this._breadcrumbsDisposables = dispose(this._breadcrumbsDisposables);
|
||||
|
||||
openEditor(input: EditorInput): void {
|
||||
if (!this._cfEnabled.value) {
|
||||
// not enabled -> return early
|
||||
if (!input || !input.getResource() || !this._fileService.canHandleResource(input.getResource())) {
|
||||
// cleanup and return when there is no input or when
|
||||
// we cannot handle this input
|
||||
this._ckBreadcrumbsVisible.set(false);
|
||||
dom.toggleClass(this.domNode, 'hidden', true);
|
||||
return;
|
||||
}
|
||||
|
||||
this._breadcrumbsDisposables = dispose(this._breadcrumbsDisposables);
|
||||
|
||||
let uri = input.getResource();
|
||||
if (!uri || !this._fileService.canHandleResource(uri)) {
|
||||
return this.closeEditor(undefined);
|
||||
}
|
||||
|
||||
dom.toggleClass(this._domNode, 'hidden', false);
|
||||
dom.toggleClass(this.domNode, 'hidden', false);
|
||||
this._ckBreadcrumbsVisible.set(true);
|
||||
|
||||
let control = this._editorGroup.activeControl.getControl() as ICodeEditor;
|
||||
let model = new EditorBreadcrumbsModel(input.getResource(), isCodeEditor(control) ? control : undefined, this._workspaceService);
|
||||
let listener = model.onDidUpdate(_ => this._widget.setItems(model.getElements().map(element => new Item(element, this._instantiationService))));
|
||||
this._widget.setItems(model.getElements().map(element => new Item(element, this._instantiationService)));
|
||||
|
||||
this._breadcrumbsDisposables.push(model, listener);
|
||||
let updateBreadcrumbs = () => {
|
||||
let items = model.getElements().map(element => new Item(element, this._options, this._instantiationService));
|
||||
this._widget.setItems(items);
|
||||
this._widget.reveal(items[items.length - 1]);
|
||||
};
|
||||
let listener = model.onDidUpdate(updateBreadcrumbs);
|
||||
updateBreadcrumbs();
|
||||
this._breadcrumbsDisposables = [model, listener];
|
||||
}
|
||||
|
||||
closeEditor(input: EditorInput): void {
|
||||
clear(): void {
|
||||
this._breadcrumbsDisposables = dispose(this._breadcrumbsDisposables);
|
||||
this._ckBreadcrumbsVisible.set(false);
|
||||
dom.toggleClass(this._domNode, 'hidden', true);
|
||||
dom.toggleClass(this.domNode, 'hidden', true);
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this._widget.domFocus();
|
||||
}
|
||||
|
||||
focusNext(): void {
|
||||
this._widget.focusNext();
|
||||
}
|
||||
|
||||
focusPrev(): void {
|
||||
this._widget.focusPrev();
|
||||
}
|
||||
|
||||
select(): void {
|
||||
const item = this._widget.getFocused();
|
||||
if (item) {
|
||||
this._widget.setSelected(item);
|
||||
private _onFocusEvent(event: IBreadcrumbsItemEvent): void {
|
||||
if (event.item && this._breadcrumbsPickerShowing) {
|
||||
return this._widget.setSelection(event.item);
|
||||
}
|
||||
}
|
||||
|
||||
private _onDidSelectItem(event: IBreadcrumbsItemEvent): void {
|
||||
private _onSelectEvent(event: IBreadcrumbsItemEvent): void {
|
||||
if (!event.item) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.type === 'focus' && !this._breadcrumbsPickerShowing) {
|
||||
// focus change only moves the picker when already active
|
||||
return;
|
||||
}
|
||||
|
||||
this._editorGroup.focus();
|
||||
this._contextViewService.showContextView({
|
||||
getAnchor() {
|
||||
return event.node;
|
||||
},
|
||||
render: (container: HTMLElement) => {
|
||||
dom.addClasses(container, 'monaco-breadcrumbs-picker', 'monaco-workbench', 'show-file-icons');
|
||||
let color = this._themeService.getTheme().getColor(SIDE_BAR_BACKGROUND);
|
||||
container.style.borderColor = color.darken(.2).toString();
|
||||
container.style.boxShadow = `${color.toString()} 6px 6px 6px -6px;`;
|
||||
render: (parent: HTMLElement) => {
|
||||
const container = document.createElement('div');
|
||||
parent.appendChild(container);
|
||||
const theme = this._themeService.getTheme();
|
||||
const color = theme.getColor(editorBackground).darken(theme.type === 'dark' ? .2 : .1);
|
||||
container.style.borderColor = color.toString();
|
||||
container.style.boxShadow = `2px 2px 3px ${color.toString()}`;
|
||||
container.style.position = 'absolute';
|
||||
container.style.zIndex = '1000';
|
||||
dom.addClasses(container, 'monaco-breadcrumbs-picker', 'show-file-icons');
|
||||
|
||||
let { element } = event.item as Item;
|
||||
let ctor: IConstructorSignature2<HTMLElement, BreadcrumbElement, BreadcrumbsPicker> = element instanceof FileElement ? BreadcrumbsFilePicker : BreadcrumbsOutlinePicker;
|
||||
let res = this._instantiationService.createInstance(ctor, container, element);
|
||||
res.layout({ width: 250, height: 300 });
|
||||
res.layout({ width: 330, height: 220 });
|
||||
let listener = res.onDidPickElement(data => {
|
||||
this._contextViewService.hideContextView();
|
||||
this._widget.setSelection(undefined);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
@ -313,8 +315,8 @@ export abstract class BreadcrumbsPicker {
|
|||
this.focus = dom.trackFocus(this._domNode);
|
||||
this.focus.onDidBlur(_ => this._onDidPickElement.fire(undefined), undefined, this._disposables);
|
||||
this._tree.setInput(this._getInput(input)).then(_ => {
|
||||
this._tree.domFocus();
|
||||
this._tree.focusFirst();
|
||||
this._tree.domFocus();
|
||||
}, onUnexpectedError);
|
||||
}
|
||||
|
||||
|
@ -464,32 +466,41 @@ export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker {
|
|||
|
||||
//#region config
|
||||
|
||||
abstract class Config<T> {
|
||||
export abstract class BreadcrumbsConfig<T> {
|
||||
|
||||
name: string;
|
||||
value: T;
|
||||
onDidChange: Event<T>;
|
||||
abstract dispose(): void;
|
||||
|
||||
static create<T>(service: IConfigurationService, name: string): Config<T> {
|
||||
private constructor() {
|
||||
// internal
|
||||
}
|
||||
|
||||
let value: T = service.getValue(name);
|
||||
let onDidChange = new Emitter<T>();
|
||||
|
||||
let listener = service.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(name)) {
|
||||
value = service.getValue(name);
|
||||
onDidChange.fire(value);
|
||||
}
|
||||
});
|
||||
static IsEnabled = BreadcrumbsConfig._stub<boolean>('breadcrumbs.enabled');
|
||||
|
||||
private static _stub<T>(name: string): { bindTo(service: IConfigurationService): BreadcrumbsConfig<T> } {
|
||||
return {
|
||||
name,
|
||||
get value() { return value; },
|
||||
onDidChange: onDidChange.event,
|
||||
dispose(): void {
|
||||
listener.dispose();
|
||||
onDidChange.dispose();
|
||||
bindTo(service) {
|
||||
let value: T = service.getValue(name);
|
||||
let onDidChange = new Emitter<T>();
|
||||
|
||||
let listener = service.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(name)) {
|
||||
value = service.getValue(name);
|
||||
onDidChange.fire(value);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
name,
|
||||
get value() { return value; },
|
||||
onDidChange: onDidChange.event,
|
||||
dispose(): void {
|
||||
listener.dispose();
|
||||
onDidChange.dispose();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -517,10 +528,12 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
|||
id: 'breadcrumbs.focus',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_DOT,
|
||||
when: EditorBreadcrumbs.CK_BreadcrumbsVisible,
|
||||
when: BreadcrumbsControl.CK_BreadcrumbsVisible,
|
||||
handler(accessor) {
|
||||
let groups = accessor.get(IEditorGroupsService);
|
||||
groups.activeGroup.breadcrumbs.focus();
|
||||
const groups = accessor.get(IEditorGroupsService);
|
||||
const breadcrumbs = accessor.get(IBreadcrumbsService);
|
||||
//todo@joh focus last?
|
||||
breadcrumbs.getWidget(groups.activeGroup.id).domFocus();
|
||||
}
|
||||
});
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
|
@ -528,10 +541,11 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
|||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
primary: KeyCode.RightArrow,
|
||||
secondary: [KeyMod.Shift | KeyCode.RightArrow],
|
||||
when: ContextKeyExpr.and(EditorBreadcrumbs.CK_BreadcrumbsVisible, EditorBreadcrumbs.CK_BreadcrumbsActive),
|
||||
when: ContextKeyExpr.and(BreadcrumbsControl.CK_BreadcrumbsVisible, BreadcrumbsControl.CK_BreadcrumbsActive),
|
||||
handler(accessor) {
|
||||
let groups = accessor.get(IEditorGroupsService);
|
||||
groups.activeGroup.breadcrumbs.focusNext();
|
||||
const groups = accessor.get(IEditorGroupsService);
|
||||
const breadcrumbs = accessor.get(IBreadcrumbsService);
|
||||
breadcrumbs.getWidget(groups.activeGroup.id).focusNext();
|
||||
}
|
||||
});
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
|
@ -539,21 +553,24 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
|||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
primary: KeyCode.LeftArrow,
|
||||
secondary: [KeyMod.Shift | KeyCode.LeftArrow],
|
||||
when: ContextKeyExpr.and(EditorBreadcrumbs.CK_BreadcrumbsVisible, EditorBreadcrumbs.CK_BreadcrumbsActive),
|
||||
when: ContextKeyExpr.and(BreadcrumbsControl.CK_BreadcrumbsVisible, BreadcrumbsControl.CK_BreadcrumbsActive),
|
||||
handler(accessor) {
|
||||
let groups = accessor.get(IEditorGroupsService);
|
||||
groups.activeGroup.breadcrumbs.focusPrev();
|
||||
const groups = accessor.get(IEditorGroupsService);
|
||||
const breadcrumbs = accessor.get(IBreadcrumbsService);
|
||||
breadcrumbs.getWidget(groups.activeGroup.id).focusPrev();
|
||||
}
|
||||
});
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'breadcrumbs.selectFocused',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
primary: KeyCode.Enter,
|
||||
secondary: [KeyCode.UpArrow, KeyCode.Space],
|
||||
when: ContextKeyExpr.and(EditorBreadcrumbs.CK_BreadcrumbsVisible, EditorBreadcrumbs.CK_BreadcrumbsActive),
|
||||
secondary: [KeyCode.DownArrow, KeyCode.Space],
|
||||
when: ContextKeyExpr.and(BreadcrumbsControl.CK_BreadcrumbsVisible, BreadcrumbsControl.CK_BreadcrumbsActive),
|
||||
handler(accessor) {
|
||||
let groups = accessor.get(IEditorGroupsService);
|
||||
groups.activeGroup.breadcrumbs.select();
|
||||
const groups = accessor.get(IEditorGroupsService);
|
||||
const breadcrumbs = accessor.get(IBreadcrumbsService);
|
||||
const widget = breadcrumbs.getWidget(groups.activeGroup.id);
|
||||
widget.setSelection(widget.getFocused());
|
||||
}
|
||||
});
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
|
@ -561,9 +578,12 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
|||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
primary: KeyCode.Escape,
|
||||
secondary: [KeyMod.Shift | KeyCode.Escape],
|
||||
when: ContextKeyExpr.and(EditorBreadcrumbs.CK_BreadcrumbsVisible, EditorBreadcrumbs.CK_BreadcrumbsActive),
|
||||
when: ContextKeyExpr.and(BreadcrumbsControl.CK_BreadcrumbsVisible, BreadcrumbsControl.CK_BreadcrumbsActive),
|
||||
handler(accessor) {
|
||||
let groups = accessor.get(IEditorGroupsService);
|
||||
const groups = accessor.get(IEditorGroupsService);
|
||||
const breadcrumbs = accessor.get(IBreadcrumbsService);
|
||||
breadcrumbs.getWidget(groups.activeGroup.id).setFocused(undefined);
|
||||
breadcrumbs.getWidget(groups.activeGroup.id).setSelection(undefined);
|
||||
groups.activeGroup.activeControl.focus();
|
||||
}
|
||||
});
|
|
@ -117,6 +117,7 @@ export interface IEditorGroupView extends IDisposable, ISerializableView, IEdito
|
|||
isEmpty(): boolean;
|
||||
setActive(isActive: boolean): void;
|
||||
setLabel(label: string): void;
|
||||
relayout(): void;
|
||||
|
||||
shutdown(): void;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import { attachProgressBarStyler } from 'vs/platform/theme/common/styler';
|
|||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { editorBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { Themable, EDITOR_GROUP_HEADER_TABS_BORDER, EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND, EDITOR_GROUP_EMPTY_BACKGROUND, EDITOR_GROUP_FOCUSED_EMPTY_BORDER } from 'vs/workbench/common/theme';
|
||||
import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChangeEvent, GroupChangeKind, EditorsOrder, GroupsOrder, IEditorBreadcrumbs } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChangeEvent, GroupChangeKind, EditorsOrder, GroupsOrder } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
import { TabsTitleControl } from 'vs/workbench/browser/parts/editor/tabsTitleControl';
|
||||
import { EditorControl } from 'vs/workbench/browser/parts/editor/editorControl';
|
||||
import { IProgressService } from 'vs/platform/progress/common/progress';
|
||||
|
@ -34,7 +34,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
|||
import { RunOnceWorker } from 'vs/base/common/async';
|
||||
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
|
||||
import { TitleControl } from 'vs/workbench/browser/parts/editor/titleControl';
|
||||
import { IEditorGroupsAccessor, IEditorGroupView, IEditorPartOptionsChangeEvent, EDITOR_TITLE_HEIGHT, getActiveTextEditorOptions, IEditorOpeningEvent } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IEditorGroupsAccessor, IEditorGroupView, IEditorPartOptionsChangeEvent, getActiveTextEditorOptions, IEditorOpeningEvent } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
|
||||
import { join } from 'vs/base/common/paths';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
|
@ -46,7 +46,6 @@ import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'
|
|||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { EditorBreadcrumbs } from 'vs/workbench/browser/parts/editor/editorBreadcrumbs';
|
||||
|
||||
export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
|
||||
|
@ -105,9 +104,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
private titleContainer: HTMLElement;
|
||||
private titleAreaControl: TitleControl;
|
||||
|
||||
private breadcrumbsContainer: HTMLElement;
|
||||
private breadcrumbsControl: EditorBreadcrumbs;
|
||||
|
||||
private progressBar: ProgressBar;
|
||||
|
||||
private editorContainer: HTMLElement;
|
||||
|
@ -194,14 +190,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
// Title control
|
||||
this.createTitleAreaControl();
|
||||
|
||||
// Breadcrumbs container
|
||||
this.breadcrumbsContainer = document.createElement('div');
|
||||
addClass(this.breadcrumbsContainer, 'editor-breadcrumbs');
|
||||
this.element.appendChild(this.breadcrumbsContainer);
|
||||
|
||||
// Breadcrumbs control
|
||||
this.createEditorBreadcrumbs();
|
||||
|
||||
// Editor container
|
||||
this.editorContainer = document.createElement('div');
|
||||
addClass(this.editorContainer, 'editor-container');
|
||||
|
@ -409,16 +397,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
}
|
||||
}
|
||||
|
||||
private createEditorBreadcrumbs(): void {
|
||||
|
||||
if (this.breadcrumbsControl) {
|
||||
this.breadcrumbsControl.dispose();
|
||||
clearNode(this.breadcrumbsContainer);
|
||||
}
|
||||
|
||||
this.breadcrumbsControl = this.scopedInstantiationService.createInstance(EditorBreadcrumbs, this.breadcrumbsContainer, this);
|
||||
}
|
||||
|
||||
private restoreEditors(from: IEditorGroupView | ISerializedEditorGroup): TPromise<void> {
|
||||
if (this._group.count === 0) {
|
||||
return TPromise.as(void 0); // nothing to show
|
||||
|
@ -615,10 +593,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
return this._label;
|
||||
}
|
||||
|
||||
get breadcrumbs(): IEditorBreadcrumbs {
|
||||
return this.breadcrumbsControl;
|
||||
}
|
||||
|
||||
get disposed(): boolean {
|
||||
return this._disposed;
|
||||
}
|
||||
|
@ -644,8 +618,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
// Update title control
|
||||
this.titleAreaControl.setActive(isActive);
|
||||
|
||||
this.breadcrumbsControl.setActive(isActive);
|
||||
|
||||
// Update styles
|
||||
this.updateStyles();
|
||||
|
||||
|
@ -817,8 +789,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
// Show in title control after editor control because some actions depend on it
|
||||
this.titleAreaControl.openEditor(editor);
|
||||
|
||||
this.breadcrumbsControl.openEditor(editor);
|
||||
|
||||
return openEditorPromise;
|
||||
}
|
||||
|
||||
|
@ -988,7 +958,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
|
||||
// Forward to title control & breadcrumbs
|
||||
this.titleAreaControl.closeEditor(editor);
|
||||
this.breadcrumbsControl.closeEditor(editor);
|
||||
}
|
||||
|
||||
private doCloseActiveEditor(focusNext = this.accessor.activeGroup === this, fromError?: boolean): void {
|
||||
|
@ -1375,9 +1344,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
this.dimension = new Dimension(width, height);
|
||||
|
||||
// Forward to controls
|
||||
this.titleAreaControl.layout(new Dimension(this.dimension.width, EDITOR_TITLE_HEIGHT));
|
||||
this.breadcrumbsControl.layout(new Dimension(this.dimension.width, this.breadcrumbsControl.getPreferredHeight()));
|
||||
this.editorControl.layout(new Dimension(this.dimension.width, this.dimension.height - (EDITOR_TITLE_HEIGHT + this.breadcrumbsControl.getPreferredHeight())));
|
||||
this.titleAreaControl.layout(new Dimension(this.dimension.width, this.titleAreaControl.getPreferredHeight()));
|
||||
this.editorControl.layout(new Dimension(this.dimension.width, this.dimension.height - this.titleAreaControl.getPreferredHeight()));
|
||||
}
|
||||
|
||||
relayout(): void {
|
||||
|
@ -1404,8 +1372,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
|||
|
||||
this.titleAreaControl.dispose();
|
||||
|
||||
this.breadcrumbsControl.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-workbench>.part.editor>.content .editor-group-container .breadcrumbs-control.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.monaco-workbench>.part.editor>.content .editor-group-container:not(.active) .breadcrumbs-control {
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
.monaco-workbench>.part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item .symbol-icon{
|
||||
margin-left: 4px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.monaco-workbench>.part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumbs .monaco-breadcrumb-item:nth-child(2) {
|
||||
/*first-child is the style-element*/
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.monaco-workbench>.part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumbs .monaco-breadcrumb-item:last-child {
|
||||
/*first-child is the style-element*/
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.monaco-breadcrumbs-picker {
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-workbench>.part.editor>.content .editor-group-container:not(.active) .editor-breadcrumbs {
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
|
||||
.monaco-workbench>.part.editor>.content .editor-group-container .editor-breadcrumbs .monaco-breadcrumbs .monaco-breadcrumb-item:nth-child(2) { /*first-child is the style-element*/
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.monaco-breadcrumbs-picker {
|
||||
border: 1px #dddddd solid;
|
||||
box-shadow: #dddddd 6px 6px 6px -6px;
|
||||
}
|
|
@ -44,12 +44,16 @@
|
|||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title {
|
||||
position: relative;
|
||||
height: 35px;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title.tabs {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title.title-border-bottom::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
@ -112,4 +116,4 @@
|
|||
.monaco-workbench > .part.editor > .content .grid-view-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,48 @@
|
|||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .no-tabs.title-label {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .monaco-icon-label::before {
|
||||
height: 35px; /* tweak the icon size of the editor labels when icons are enabled */
|
||||
}
|
||||
|
||||
/* Breadcrumbs */
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .no-tabs-breadcrumbs {
|
||||
flex: 1 50%;
|
||||
overflow: hidden;
|
||||
line-height: 35px;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .no-tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .no-tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:nth-child(2) {
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .no-tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:last-child {
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .no-tabs-breadcrumbs .breadcrumbs-control.preview .monaco-breadcrumb-item {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .no-tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:not(:last-child)::after {
|
||||
content: '/';
|
||||
height: inherit;
|
||||
width: inherit;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.monaco-workbench.windows > .part.editor > .content .editor-group-container > .title .no-tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:not(:last-child)::after {
|
||||
content: '\\';
|
||||
}
|
||||
|
||||
/* Title Actions */
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-actions {
|
||||
display: flex;
|
||||
|
@ -26,4 +64,4 @@
|
|||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container.active > .title .title-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -252,4 +252,20 @@
|
|||
cursor: default;
|
||||
flex: initial;
|
||||
padding-left: 4px;
|
||||
}
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
/* Breadcrumbs */
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control {
|
||||
flex: 1 100%;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-icon-label::before {
|
||||
height: 18px; /* tweak the icon size of the editor labels when icons are enabled */
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:last-child {
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab .monaco-icon-label::before,
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-label a,
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label a,
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-label span,
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-label h2,
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label span {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import { TitleControl, IToolbarActions } from 'vs/workbench/browser/parts/editor
|
|||
import { ResourceLabel } from 'vs/workbench/browser/labels';
|
||||
import { TAB_ACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch';
|
||||
import { addDisposableListener, EventType, addClass, EventHelper, removeClass } from 'vs/base/browser/dom';
|
||||
import { addDisposableListener, EventType, addClass, EventHelper, removeClass, toggleClass } from 'vs/base/browser/dom';
|
||||
import { IEditorPartOptions } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { CLOSE_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';
|
||||
|
@ -35,6 +35,12 @@ export class NoTabsTitleControl extends TitleControl {
|
|||
this.editorLabel = this._register(this.instantiationService.createInstance(ResourceLabel, this.titleContainer, void 0));
|
||||
this._register(this.editorLabel.onClick(e => this.onTitleLabelClick(e)));
|
||||
|
||||
// Breadcrumbs
|
||||
const breadcrumbsContainer = document.createElement('div');
|
||||
addClass(breadcrumbsContainer, 'no-tabs-breadcrumbs');
|
||||
this.titleContainer.appendChild(breadcrumbsContainer);
|
||||
this.createBreadcrumbsControl(breadcrumbsContainer, { showIcons: false, showDecorationColors: false });
|
||||
|
||||
// Right Actions Container
|
||||
const actionsContainer = document.createElement('div');
|
||||
addClass(actionsContainer, 'title-actions');
|
||||
|
@ -156,6 +162,9 @@ export class NoTabsTitleControl extends TitleControl {
|
|||
const editor = this.group.activeEditor;
|
||||
this.lastRenderedActiveEditor = editor;
|
||||
|
||||
const isEditorPinned = this.group.isPinned(this.group.activeEditor);
|
||||
const isGroupActive = this.accessor.activeGroup === this.group;
|
||||
|
||||
// Clear if there is no editor
|
||||
if (!editor) {
|
||||
removeClass(this.titleContainer, 'dirty');
|
||||
|
@ -165,9 +174,6 @@ export class NoTabsTitleControl extends TitleControl {
|
|||
|
||||
// Otherwise render it
|
||||
else {
|
||||
const isEditorPinned = this.group.isPinned(this.group.activeEditor);
|
||||
const isGroupActive = this.accessor.activeGroup === this.group;
|
||||
|
||||
// Dirty state
|
||||
this.updateEditorDirty(editor);
|
||||
|
||||
|
@ -177,7 +183,9 @@ export class NoTabsTitleControl extends TitleControl {
|
|||
|
||||
const { labelFormat } = this.accessor.partOptions;
|
||||
let description: string;
|
||||
if (labelFormat === 'default' && !isGroupActive) {
|
||||
if (this.breadcrumbsControl) {
|
||||
description = ''; // hide description when showing breadcrumbs
|
||||
} else if (labelFormat === 'default' && !isGroupActive) {
|
||||
description = ''; // hide description when group is not active and style is 'default'
|
||||
} else {
|
||||
description = editor.getDescription(this.getVerbosity(labelFormat)) || '';
|
||||
|
@ -188,7 +196,7 @@ export class NoTabsTitleControl extends TitleControl {
|
|||
title = ''; // dont repeat what is already shown
|
||||
}
|
||||
|
||||
this.editorLabel.setLabel({ name, description, resource }, { title, italic: !isEditorPinned, extraClasses: ['title-label'] });
|
||||
this.editorLabel.setLabel({ name, description, resource }, { title, italic: !isEditorPinned, extraClasses: ['no-tabs', 'title-label'] });
|
||||
if (isGroupActive) {
|
||||
this.editorLabel.element.style.color = this.getColor(TAB_ACTIVE_FOREGROUND);
|
||||
} else {
|
||||
|
@ -198,6 +206,16 @@ export class NoTabsTitleControl extends TitleControl {
|
|||
// Update Editor Actions Toolbar
|
||||
this.updateEditorActionsToolbar();
|
||||
}
|
||||
|
||||
// Update Breadcrumbs
|
||||
if (this.breadcrumbsControl) {
|
||||
if (isGroupActive) {
|
||||
this.breadcrumbsControl.update();
|
||||
toggleClass(this.breadcrumbsControl.domNode, 'preview', !isEditorPinned);
|
||||
} else {
|
||||
this.breadcrumbsControl.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getVerbosity(style: string): Verbosity {
|
||||
|
|
|
@ -39,6 +39,8 @@ import { addClass, addDisposableListener, hasClass, EventType, EventHelper, remo
|
|||
import { localize } from 'vs/nls';
|
||||
import { IEditorGroupsAccessor, IEditorPartOptions, IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { CloseOneEditorAction } from 'vs/workbench/browser/parts/editor/editorActions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { BreadcrumbsControl } from 'vs/workbench/browser/parts/editor/breadcrumbsControl';
|
||||
|
||||
interface IEditorInputLabel {
|
||||
name: string;
|
||||
|
@ -78,9 +80,10 @@ export class TabsTitleControl extends TitleControl {
|
|||
@IMenuService menuService: IMenuService,
|
||||
@IQuickOpenService quickOpenService: IQuickOpenService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IExtensionService extensionService: IExtensionService
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IConfigurationService configurationService: IConfigurationService
|
||||
) {
|
||||
super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService);
|
||||
super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService, configurationService);
|
||||
}
|
||||
|
||||
protected create(parent: HTMLElement): void {
|
||||
|
@ -108,6 +111,12 @@ export class TabsTitleControl extends TitleControl {
|
|||
|
||||
// Close Action
|
||||
this.closeOneEditorAction = this._register(this.instantiationService.createInstance(CloseOneEditorAction, CloseOneEditorAction.ID, CloseOneEditorAction.LABEL));
|
||||
|
||||
// Breadcrumbs
|
||||
const breadcrumbsContainer = document.createElement('div');
|
||||
addClass(breadcrumbsContainer, 'tabs-breadcrumbs');
|
||||
this.titleContainer.appendChild(breadcrumbsContainer);
|
||||
this.createBreadcrumbsControl(breadcrumbsContainer, { showIcons: true, showDecorationColors: false });
|
||||
}
|
||||
|
||||
private createScrollbar(): void {
|
||||
|
@ -240,6 +249,11 @@ export class TabsTitleControl extends TitleControl {
|
|||
|
||||
// Redraw all tabs
|
||||
this.redraw();
|
||||
|
||||
// Update Breadcrumbs
|
||||
if (this.breadcrumbsControl) {
|
||||
this.breadcrumbsControl.update();
|
||||
}
|
||||
}
|
||||
|
||||
closeEditor(editor: IEditorInput): void {
|
||||
|
@ -287,6 +301,11 @@ export class TabsTitleControl extends TitleControl {
|
|||
|
||||
this.clearEditorActionsToolbar();
|
||||
}
|
||||
|
||||
// Update Breadcrumbs
|
||||
if (this.breadcrumbsControl) {
|
||||
this.breadcrumbsControl.update();
|
||||
}
|
||||
}
|
||||
|
||||
moveEditor(editor: IEditorInput, fromIndex: number, targetIndex: number): void {
|
||||
|
@ -910,6 +929,11 @@ export class TabsTitleControl extends TitleControl {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.breadcrumbsControl) {
|
||||
this.breadcrumbsControl.layout({ width: dimension.width, height: BreadcrumbsControl.HEIGHT });
|
||||
this.scrollbar.getDomNode().style.height = `${dimension.height - BreadcrumbsControl.HEIGHT}px`;
|
||||
}
|
||||
|
||||
const visibleContainerWidth = this.tabsContainer.offsetWidth;
|
||||
const totalContainerWidth = this.tabsContainer.scrollWidth;
|
||||
|
||||
|
@ -1198,4 +1222,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
|||
`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -33,10 +33,12 @@ import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { Dimension, addDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IEditorGroupsAccessor, IEditorPartOptions, IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IEditorGroupsAccessor, IEditorPartOptions, IEditorGroupView, EDITOR_TITLE_HEIGHT } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { listActiveSelectionBackground, listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { LocalSelectionTransfer, DraggedEditorGroupIdentifier, DraggedEditorIdentifier, fillResourceDataTransfers } from 'vs/workbench/browser/dnd';
|
||||
import { applyDragImage } from 'vs/base/browser/dnd';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { BreadcrumbsConfig, BreadcrumbsControl, IBreadcrumbsControlOptions } from 'vs/workbench/browser/parts/editor/breadcrumbsControl';
|
||||
|
||||
export interface IToolbarActions {
|
||||
primary: IAction[];
|
||||
|
@ -48,6 +50,8 @@ export abstract class TitleControl extends Themable {
|
|||
protected readonly groupTransfer = LocalSelectionTransfer.getInstance<DraggedEditorGroupIdentifier>();
|
||||
protected readonly editorTransfer = LocalSelectionTransfer.getInstance<DraggedEditorIdentifier>();
|
||||
|
||||
protected breadcrumbsControl: BreadcrumbsControl;
|
||||
|
||||
private currentPrimaryEditorActionIds: string[] = [];
|
||||
private currentSecondaryEditorActionIds: string[] = [];
|
||||
protected editorActionsToolbar: ToolBar;
|
||||
|
@ -72,7 +76,8 @@ export abstract class TitleControl extends Themable {
|
|||
@IMenuService private menuService: IMenuService,
|
||||
@IQuickOpenService protected quickOpenService: IQuickOpenService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IExtensionService private extensionService: IExtensionService
|
||||
@IExtensionService private extensionService: IExtensionService,
|
||||
@IConfigurationService protected configurationService: IConfigurationService
|
||||
) {
|
||||
super(themeService);
|
||||
|
||||
|
@ -89,6 +94,24 @@ export abstract class TitleControl extends Themable {
|
|||
|
||||
protected abstract create(parent: HTMLElement): void;
|
||||
|
||||
protected createBreadcrumbsControl(container: HTMLElement, options: IBreadcrumbsControlOptions): void {
|
||||
const config = this._register(BreadcrumbsConfig.IsEnabled.bindTo(this.configurationService));
|
||||
config.onDidChange(value => {
|
||||
if (!value && this.breadcrumbsControl) {
|
||||
this.breadcrumbsControl.dispose();
|
||||
this.breadcrumbsControl = undefined;
|
||||
this.group.relayout();
|
||||
} else if (value && !this.breadcrumbsControl) {
|
||||
this.breadcrumbsControl = this.instantiationService.createInstance(BreadcrumbsControl, container, options, this.group);
|
||||
this.breadcrumbsControl.update();
|
||||
this.group.relayout();
|
||||
}
|
||||
});
|
||||
if (config.value) {
|
||||
this.breadcrumbsControl = this.instantiationService.createInstance(BreadcrumbsControl, container, options, this.group);
|
||||
}
|
||||
}
|
||||
|
||||
protected createEditorActionsToolBar(container: HTMLElement): void {
|
||||
const context = { groupId: this.group.id } as IEditorCommandsContext;
|
||||
|
||||
|
@ -327,9 +350,18 @@ export abstract class TitleControl extends Themable {
|
|||
|
||||
layout(dimension: Dimension): void {
|
||||
// Optionally implemented in subclasses
|
||||
|
||||
if (this.breadcrumbsControl) {
|
||||
this.breadcrumbsControl.layout(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
getPreferredHeight(): number {
|
||||
return EDITOR_TITLE_HEIGHT + (this.breadcrumbsControl ? BreadcrumbsControl.HEIGHT : 0);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.breadcrumbsControl = dispose(this.breadcrumbsControl);
|
||||
this.editorToolBarMenuDisposables = dispose(this.editorToolBarMenuDisposables);
|
||||
|
||||
super.dispose();
|
||||
|
|
|
@ -32,12 +32,15 @@
|
|||
zoom: 1;
|
||||
}
|
||||
|
||||
|
||||
.monaco-workbench > .part.menubar > .menubar-menu-button.open,
|
||||
.monaco-workbench > .part.menubar > .menubar-menu-button:focus,
|
||||
.monaco-workbench > .part.menubar > .menubar-menu-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.menubar.light > .menubar-menu-button.open,
|
||||
.monaco-workbench > .part.menubar.light > .menubar-menu-button:focus,
|
||||
.monaco-workbench > .part.menubar.light > .menubar-menu-button:hover {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ fileMenuRegistration();
|
|||
editMenuRegistration();
|
||||
selectionMenuRegistration();
|
||||
viewMenuRegistration();
|
||||
appearanceMenuRegistration();
|
||||
layoutMenuRegistration();
|
||||
goMenuRegistration();
|
||||
debugMenuRegistration();
|
||||
|
@ -494,9 +495,25 @@ function viewMenuRegistration() {
|
|||
order: 2
|
||||
});
|
||||
|
||||
// TODO: Appearance Submenu
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '2_appearance',
|
||||
title: nls.localize({ key: 'miAppearance', comment: ['&& denotes a mnemonic'] }, "&&Appearance"),
|
||||
submenu: MenuId.MenubarAppearanceMenu,
|
||||
order: 1
|
||||
});
|
||||
|
||||
// TODO: Editor Layout Submenu
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '2_appearance',
|
||||
title: nls.localize({ key: 'miEditorLayout', comment: ['&& denotes a mnemonic'] }, "Editor &&Layout"),
|
||||
submenu: MenuId.MenubarLayoutMenu,
|
||||
order: 2
|
||||
});
|
||||
|
||||
// Viewlets
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '2_views',
|
||||
group: '3_views',
|
||||
command: {
|
||||
id: 'workbench.view.explorer',
|
||||
title: nls.localize({ key: 'miViewExplorer', comment: ['&& denotes a mnemonic'] }, "&&Explorer")
|
||||
|
@ -505,7 +522,7 @@ function viewMenuRegistration() {
|
|||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '2_views',
|
||||
group: '3_views',
|
||||
command: {
|
||||
id: 'workbench.view.search',
|
||||
title: nls.localize({ key: 'miViewSearch', comment: ['&& denotes a mnemonic'] }, "&&Search")
|
||||
|
@ -514,7 +531,7 @@ function viewMenuRegistration() {
|
|||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '2_views',
|
||||
group: '3_views',
|
||||
command: {
|
||||
id: 'workbench.view.scm',
|
||||
title: nls.localize({ key: 'miViewSCM', comment: ['&& denotes a mnemonic'] }, "S&&CM")
|
||||
|
@ -523,7 +540,7 @@ function viewMenuRegistration() {
|
|||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '2_views',
|
||||
group: '3_views',
|
||||
command: {
|
||||
id: 'workbench.view.debug',
|
||||
title: nls.localize({ key: 'miViewDebug', comment: ['&& denotes a mnemonic'] }, "&&Debug")
|
||||
|
@ -532,7 +549,7 @@ function viewMenuRegistration() {
|
|||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '2_views',
|
||||
group: '3_views',
|
||||
command: {
|
||||
id: 'workbench.view.extensions',
|
||||
title: nls.localize({ key: 'miViewExtensions', comment: ['&& denotes a mnemonic'] }, "E&&xtensions")
|
||||
|
@ -542,7 +559,7 @@ function viewMenuRegistration() {
|
|||
|
||||
// Panels
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '3_panels',
|
||||
group: '4_panels',
|
||||
command: {
|
||||
id: 'workbench.action.output.toggleOutput',
|
||||
title: nls.localize({ key: 'miToggleOutput', comment: ['&& denotes a mnemonic'] }, "&&Output")
|
||||
|
@ -551,7 +568,7 @@ function viewMenuRegistration() {
|
|||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '3_panels',
|
||||
group: '4_panels',
|
||||
command: {
|
||||
id: 'workbench.debug.action.toggleRepl',
|
||||
title: nls.localize({ key: 'miToggleDebugConsole', comment: ['&& denotes a mnemonic'] }, "De&&bug Console")
|
||||
|
@ -560,7 +577,7 @@ function viewMenuRegistration() {
|
|||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '3_panels',
|
||||
group: '4_panels',
|
||||
command: {
|
||||
id: 'workbench.action.terminal.toggleTerminal',
|
||||
title: nls.localize({ key: 'miToggleIntegratedTerminal', comment: ['&& denotes a mnemonic'] }, "&&Integrated Terminal")
|
||||
|
@ -569,7 +586,7 @@ function viewMenuRegistration() {
|
|||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '3_panels',
|
||||
group: '4_panels',
|
||||
command: {
|
||||
id: 'workbench.actions.view.problems',
|
||||
title: nls.localize({ key: 'miMarker', comment: ['&& denotes a mnemonic'] }, "&&Problems")
|
||||
|
@ -577,101 +594,9 @@ function viewMenuRegistration() {
|
|||
order: 4
|
||||
});
|
||||
|
||||
// Toggle View
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '4_toggle_view',
|
||||
command: {
|
||||
id: 'workbench.action.toggleFullScreen',
|
||||
title: nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "Toggle &&Full Screen")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '4_toggle_view',
|
||||
command: {
|
||||
id: 'workbench.action.toggleZenMode',
|
||||
title: nls.localize('miToggleZenMode', "Toggle Zen Mode")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '4_toggle_view',
|
||||
command: {
|
||||
id: 'workbench.action.toggleCenteredLayout',
|
||||
title: nls.localize('miToggleCenteredLayout', "Toggle Centered Layout")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '4_toggle_view',
|
||||
command: {
|
||||
id: 'workbench.action.toggleMenuBar',
|
||||
title: nls.localize({ key: 'miToggleMenuBar', comment: ['&& denotes a mnemonic'] }, "Toggle Menu &&Bar")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
// TODO: Editor Layout Submenu
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
title: nls.localize({ key: 'miEditorLayout', comment: ['&& denotes a mnemonic'] }, "Editor &&Layout"),
|
||||
submenu: MenuId.MenubarLayoutMenu,
|
||||
group: '5_layout',
|
||||
order: 1
|
||||
});
|
||||
|
||||
|
||||
// Workbench Layout
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '6_workbench_layout',
|
||||
command: {
|
||||
id: 'workbench.action.toggleSidebarVisibility',
|
||||
title: nls.localize({ key: 'miToggleSidebar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Side Bar")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '6_workbench_layout',
|
||||
command: {
|
||||
id: 'workbench.action.toggleSidebarPosition',
|
||||
title: nls.localize({ key: 'miMoveSidebarLeftRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left/Right")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '6_workbench_layout',
|
||||
command: {
|
||||
id: 'workbench.action.toggleStatusbarVisibility',
|
||||
title: nls.localize({ key: 'miToggleStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Status Bar")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '6_workbench_layout',
|
||||
command: {
|
||||
id: 'workbench.action.toggleActivityBarVisibility',
|
||||
title: nls.localize({ key: 'miToggleActivityBar', comment: ['&& denotes a mnemonic'] }, "Toggle &&Activity Bar")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '6_workbench_layout',
|
||||
command: {
|
||||
id: 'workbench.action.togglePanel',
|
||||
title: nls.localize({ key: 'miTogglePanel', comment: ['&& denotes a mnemonic'] }, "Toggle &&Panel")
|
||||
},
|
||||
order: 5
|
||||
});
|
||||
|
||||
// Toggle Editor Settings
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '8_editor',
|
||||
group: '5_editor',
|
||||
command: {
|
||||
id: 'workbench.action.toggleWordWrap',
|
||||
title: nls.localize({ key: 'miToggleWordWrap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Word Wrap")
|
||||
|
@ -680,7 +605,7 @@ function viewMenuRegistration() {
|
|||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '8_editor',
|
||||
group: '5_editor',
|
||||
command: {
|
||||
id: 'workbench.action.toggleMinimap',
|
||||
title: nls.localize({ key: 'miToggleMinimap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Minimap")
|
||||
|
@ -689,7 +614,7 @@ function viewMenuRegistration() {
|
|||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '8_editor',
|
||||
group: '5_editor',
|
||||
command: {
|
||||
id: 'workbench.action.toggleRenderWhitespace',
|
||||
title: nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "Toggle &&Render Whitespace")
|
||||
|
@ -698,17 +623,100 @@ function viewMenuRegistration() {
|
|||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '8_editor',
|
||||
group: '5_editor',
|
||||
command: {
|
||||
id: 'workbench.action.toggleRenderControlCharacters',
|
||||
title: nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Toggle &&Control Characters")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
}
|
||||
|
||||
function appearanceMenuRegistration() {
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '1_toggle_view',
|
||||
command: {
|
||||
id: 'workbench.action.toggleFullScreen',
|
||||
title: nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "Toggle &&Full Screen")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '1_toggle_view',
|
||||
command: {
|
||||
id: 'workbench.action.toggleZenMode',
|
||||
title: nls.localize('miToggleZenMode', "Toggle Zen Mode")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '1_toggle_view',
|
||||
command: {
|
||||
id: 'workbench.action.toggleCenteredLayout',
|
||||
title: nls.localize('miToggleCenteredLayout', "Toggle Centered Layout")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '1_toggle_view',
|
||||
command: {
|
||||
id: 'workbench.action.toggleMenuBar',
|
||||
title: nls.localize({ key: 'miToggleMenuBar', comment: ['&& denotes a mnemonic'] }, "Toggle Menu &&Bar")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '2_workbench_layout',
|
||||
command: {
|
||||
id: 'workbench.action.toggleSidebarVisibility',
|
||||
title: nls.localize({ key: 'miToggleSidebar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Side Bar")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '2_workbench_layout',
|
||||
command: {
|
||||
id: 'workbench.action.toggleSidebarPosition',
|
||||
title: nls.localize({ key: 'miMoveSidebarLeftRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left/Right")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '2_workbench_layout',
|
||||
command: {
|
||||
id: 'workbench.action.toggleStatusbarVisibility',
|
||||
title: nls.localize({ key: 'miToggleStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Status Bar")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '2_workbench_layout',
|
||||
command: {
|
||||
id: 'workbench.action.toggleActivityBarVisibility',
|
||||
title: nls.localize({ key: 'miToggleActivityBar', comment: ['&& denotes a mnemonic'] }, "Toggle &&Activity Bar")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '2_workbench_layout',
|
||||
command: {
|
||||
id: 'workbench.action.togglePanel',
|
||||
title: nls.localize({ key: 'miTogglePanel', comment: ['&& denotes a mnemonic'] }, "Toggle &&Panel")
|
||||
},
|
||||
order: 5
|
||||
});
|
||||
|
||||
// Zoom
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '9_zoom',
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '3_zoom',
|
||||
command: {
|
||||
id: 'workbench.action.zoomIn',
|
||||
title: nls.localize({ key: 'miZoomIn', comment: ['&& denotes a mnemonic'] }, "&&Zoom In")
|
||||
|
@ -716,8 +724,8 @@ function viewMenuRegistration() {
|
|||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '9_zoom',
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '3_zoom',
|
||||
command: {
|
||||
id: 'workbench.action.zoomOut',
|
||||
title: nls.localize({ key: 'miZoomOut', comment: ['&& denotes a mnemonic'] }, "&&Zoom Out")
|
||||
|
@ -725,8 +733,8 @@ function viewMenuRegistration() {
|
|||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
||||
group: '9_zoom',
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
||||
group: '3_zoom',
|
||||
command: {
|
||||
id: 'workbench.action.zoomReset',
|
||||
title: nls.localize({ key: 'miZoomReset', comment: ['&& denotes a mnemonic'] }, "&&Reset Zoom")
|
||||
|
|
|
@ -43,6 +43,13 @@ interface CustomMenu {
|
|||
actions?: IAction[];
|
||||
}
|
||||
|
||||
enum MenubarState {
|
||||
HIDDEN,
|
||||
VISIBLE,
|
||||
FOCUSED,
|
||||
OPEN
|
||||
}
|
||||
|
||||
export class MenubarPart extends Part {
|
||||
|
||||
private keys = [
|
||||
|
@ -84,19 +91,22 @@ export class MenubarPart extends Part {
|
|||
|
||||
private focusedMenu: {
|
||||
index: number;
|
||||
holder: Builder;
|
||||
widget: Menu;
|
||||
holder?: Builder;
|
||||
widget?: Menu;
|
||||
};
|
||||
|
||||
private customMenus: CustomMenu[];
|
||||
|
||||
private menuUpdater: RunOnceScheduler;
|
||||
private actionRunner: IActionRunner;
|
||||
private focusToReturn: Builder;
|
||||
private container: Builder;
|
||||
private recentlyOpened: IRecentlyOpened;
|
||||
private updatePending: boolean;
|
||||
private focusingWithAlt: boolean;
|
||||
private _modifierKeyStatus: IModifierKeyStatus;
|
||||
private _isFocused: boolean;
|
||||
private _focusState: MenubarState;
|
||||
|
||||
private _onVisibilityChange: Emitter<Dimension>;
|
||||
|
||||
private initialSizing: {
|
||||
|
@ -143,9 +153,7 @@ export class MenubarPart extends Part {
|
|||
|
||||
this.actionRunner = this._register(new ActionRunner());
|
||||
this._register(this.actionRunner.onDidBeforeRun(() => {
|
||||
if (this.focusedMenu && this.focusedMenu.holder) {
|
||||
this.focusedMenu.holder.hide();
|
||||
}
|
||||
this.focusState = this.currentMenubarVisibility === 'toggle' ? MenubarState.HIDDEN : MenubarState.VISIBLE;
|
||||
}));
|
||||
|
||||
this._onVisibilityChange = this._register(new Emitter<Dimension>());
|
||||
|
@ -157,7 +165,7 @@ export class MenubarPart extends Part {
|
|||
this.doSetupMenubar();
|
||||
}
|
||||
|
||||
this.isFocused = false;
|
||||
this._focusState = MenubarState.HIDDEN;
|
||||
|
||||
this.windowService.getRecentlyOpened().then((recentlyOpened) => {
|
||||
this.recentlyOpened = recentlyOpened;
|
||||
|
@ -213,12 +221,12 @@ export class MenubarPart extends Part {
|
|||
return this.configurationService.getValue<string>('window.titleBarStyle');
|
||||
}
|
||||
|
||||
private get isFocused(): boolean {
|
||||
return this._isFocused;
|
||||
private get focusState(): MenubarState {
|
||||
return this._focusState;
|
||||
}
|
||||
|
||||
private set isFocused(value: boolean) {
|
||||
if (this._isFocused && !value) {
|
||||
private set focusState(value: MenubarState) {
|
||||
if (this._focusState >= MenubarState.FOCUSED && value < MenubarState.FOCUSED) {
|
||||
// Losing focus, update the menu if needed
|
||||
|
||||
if (this.updatePending) {
|
||||
|
@ -227,13 +235,91 @@ export class MenubarPart extends Part {
|
|||
}
|
||||
}
|
||||
|
||||
this._isFocused = value;
|
||||
|
||||
if (!this._isFocused && this.currentMenubarVisibility === 'toggle') {
|
||||
if (this.container) {
|
||||
this.hideMenubar();
|
||||
}
|
||||
if (value === this._focusState) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case MenubarState.HIDDEN:
|
||||
if (this.isVisible) {
|
||||
this.hideMenubar();
|
||||
}
|
||||
|
||||
if (this.isOpen) {
|
||||
this.cleanupCustomMenu();
|
||||
}
|
||||
|
||||
if (this.isFocused) {
|
||||
this.focusedMenu = null;
|
||||
|
||||
if (this.focusToReturn) {
|
||||
this.focusToReturn.domFocus();
|
||||
this.focusToReturn = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
case MenubarState.VISIBLE:
|
||||
if (!this.isVisible) {
|
||||
this.showMenubar();
|
||||
}
|
||||
|
||||
if (this.isOpen) {
|
||||
this.cleanupCustomMenu();
|
||||
}
|
||||
|
||||
if (this.isFocused) {
|
||||
if (this.focusedMenu) {
|
||||
this.customMenus[this.focusedMenu.index].buttonElement.domBlur();
|
||||
}
|
||||
|
||||
this.focusedMenu = null;
|
||||
|
||||
if (this.focusToReturn) {
|
||||
this.focusToReturn.domFocus();
|
||||
this.focusToReturn = null;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case MenubarState.FOCUSED:
|
||||
if (!this.isVisible) {
|
||||
this.showMenubar();
|
||||
}
|
||||
|
||||
if (this.isOpen) {
|
||||
this.cleanupCustomMenu();
|
||||
}
|
||||
|
||||
if (this.focusedMenu) {
|
||||
this.customMenus[this.focusedMenu.index].buttonElement.domFocus();
|
||||
}
|
||||
break;
|
||||
case MenubarState.OPEN:
|
||||
if (!this.isVisible) {
|
||||
this.showMenubar();
|
||||
}
|
||||
|
||||
if (this.focusedMenu) {
|
||||
this.showCustomMenu(this.focusedMenu.index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
this._focusState = value;
|
||||
}
|
||||
|
||||
private get isVisible(): boolean {
|
||||
return this.focusState >= MenubarState.VISIBLE;
|
||||
}
|
||||
|
||||
private get isFocused(): boolean {
|
||||
return this.focusState >= MenubarState.FOCUSED;
|
||||
}
|
||||
|
||||
private get isOpen(): boolean {
|
||||
return this.focusState >= MenubarState.OPEN;
|
||||
}
|
||||
|
||||
private onDidChangeFullscreen(): void {
|
||||
|
@ -256,26 +342,42 @@ export class MenubarPart extends Part {
|
|||
this.container.style('visibility', null);
|
||||
}
|
||||
|
||||
private onModifierKeyToggled(modiferKeyStatus: IModifierKeyStatus): void {
|
||||
private onModifierKeyToggled(modifierKeyStatus: IModifierKeyStatus): void {
|
||||
const altKeyPressed = (!this._modifierKeyStatus || !this._modifierKeyStatus.altKey) && modifierKeyStatus.altKey;
|
||||
const altKeyAlone = altKeyPressed && !modifierKeyStatus.ctrlKey && !modifierKeyStatus.shiftKey;
|
||||
const allModifiersReleased = !modifierKeyStatus.altKey && !modifierKeyStatus.ctrlKey && !modifierKeyStatus.shiftKey;
|
||||
|
||||
if (this.currentMenubarVisibility === 'toggle') {
|
||||
const altKeyPressed = (!this._modifierKeyStatus || !this._modifierKeyStatus.altKey) && modiferKeyStatus.altKey;
|
||||
if (altKeyPressed && !modiferKeyStatus.ctrlKey && !modiferKeyStatus.shiftKey) {
|
||||
this.showMenubar();
|
||||
} else if (!this.isFocused) {
|
||||
this.hideMenubar();
|
||||
if (altKeyAlone) {
|
||||
if (!this.isVisible) {
|
||||
this.focusState = MenubarState.VISIBLE;
|
||||
}
|
||||
} else if (!allModifiersReleased && !this.isFocused) {
|
||||
this.focusState = MenubarState.HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
this._modifierKeyStatus = modiferKeyStatus;
|
||||
if (allModifiersReleased && this.focusingWithAlt) {
|
||||
if (!this.isFocused) {
|
||||
this.focusedMenu = { index: 0 };
|
||||
this.focusState = MenubarState.FOCUSED;
|
||||
} else if (!this.isOpen) {
|
||||
this.focusState = this.currentMenubarVisibility === 'toggle' ? MenubarState.HIDDEN : MenubarState.VISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
this._modifierKeyStatus = modifierKeyStatus;
|
||||
|
||||
if (this.currentEnableMenuBarMnemonics && this.customMenus) {
|
||||
this.customMenus.forEach(customMenu => {
|
||||
let child = customMenu.titleElement.child();
|
||||
if (child) {
|
||||
child.style('text-decoration', modiferKeyStatus.altKey ? 'underline' : null);
|
||||
child.style('text-decoration', modifierKeyStatus.altKey ? 'underline' : null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.focusingWithAlt = altKeyAlone;
|
||||
}
|
||||
|
||||
private onRecentlyOpenedChange(): void {
|
||||
|
@ -286,8 +388,6 @@ export class MenubarPart extends Part {
|
|||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(browser.onDidChangeFullscreen(() => this.onDidChangeFullscreen()));
|
||||
|
||||
// Update when config changes
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e)));
|
||||
|
||||
|
@ -303,7 +403,14 @@ export class MenubarPart extends Part {
|
|||
// Listen to keybindings change
|
||||
this._register(this.keybindingService.onDidUpdateKeybindings(() => this.setupMenubar()));
|
||||
|
||||
this._register(ModifierKeyEmitter.getInstance().event(this.onModifierKeyToggled, this));
|
||||
// These listeners only apply when the custom menubar is being used
|
||||
if (!isMacintosh && this.currentTitlebarStyleSetting === 'custom') {
|
||||
// Listen to fullscreen changes
|
||||
this._register(browser.onDidChangeFullscreen(() => this.onDidChangeFullscreen()));
|
||||
|
||||
// Listen for alt key presses
|
||||
this._register(ModifierKeyEmitter.getInstance().event(this.onModifierKeyToggled, this));
|
||||
}
|
||||
}
|
||||
|
||||
private doSetupMenubar(): void {
|
||||
|
@ -473,7 +580,7 @@ export class MenubarPart extends Part {
|
|||
|
||||
// Create the top level menu button element
|
||||
if (firstTimeSetup) {
|
||||
const buttonElement = $(this.container).div({ class: 'menubar-menu-button' }).attr('role', 'menu');
|
||||
const buttonElement = $(this.container).div({ class: 'menubar-menu-button' }).attr({ 'role': 'menu', 'tabindex': 0 });
|
||||
buttonElement.attr('aria-label', this.topLevelTitles[menuTitle].replace(/&&(.)/g, '$1'));
|
||||
|
||||
const titleElement = $(buttonElement).div({ class: 'menubar-menu-title', 'aria-hidden': true });
|
||||
|
@ -533,30 +640,56 @@ export class MenubarPart extends Part {
|
|||
updateActions(menu, this.customMenus[menuIndex].actions);
|
||||
|
||||
if (firstTimeSetup) {
|
||||
this.customMenus[menuIndex].buttonElement.on(EventType.KEY_UP, (e) => {
|
||||
let event = new StandardKeyboardEvent(e as KeyboardEvent);
|
||||
let eventHandled = true;
|
||||
|
||||
if ((event.equals(KeyCode.DownArrow) || event.equals(KeyCode.Enter)) && !this.isOpen) {
|
||||
this.focusedMenu = { index: menuIndex };
|
||||
this.focusState = MenubarState.OPEN;
|
||||
} else {
|
||||
eventHandled = false;
|
||||
}
|
||||
|
||||
if (eventHandled) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
this.customMenus[menuIndex].buttonElement.on(EventType.CLICK, () => {
|
||||
if (this._modifierKeyStatus && (this._modifierKeyStatus.shiftKey || this._modifierKeyStatus.ctrlKey)) {
|
||||
return; // supress keyboard shortcuts that shouldn't conflict
|
||||
}
|
||||
|
||||
this.toggleCustomMenu(menuIndex);
|
||||
this.isFocused = !this.isFocused;
|
||||
if (this.isOpen) {
|
||||
if (this.isCurrentMenu(menuIndex)) {
|
||||
this.focusState = this.currentMenubarVisibility === 'toggle' ? MenubarState.HIDDEN : MenubarState.VISIBLE;
|
||||
} else {
|
||||
this.cleanupCustomMenu();
|
||||
this.showCustomMenu(menuIndex);
|
||||
}
|
||||
} else {
|
||||
this.focusedMenu = { index: menuIndex };
|
||||
this.focusState = MenubarState.OPEN;
|
||||
}
|
||||
});
|
||||
|
||||
this.customMenus[menuIndex].buttonElement.on(EventType.MOUSE_ENTER, () => {
|
||||
if (this.isFocused && !this.isCurrentMenu(menuIndex)) {
|
||||
this.toggleCustomMenu(menuIndex);
|
||||
if (this.isOpen && !this.isCurrentMenu(menuIndex)) {
|
||||
this.customMenus[menuIndex].buttonElement.domFocus();
|
||||
this.cleanupCustomMenu();
|
||||
this.showCustomMenu(menuIndex);
|
||||
} else if (this.isFocused && !this.isOpen) {
|
||||
this.customMenus[menuIndex].buttonElement.domFocus();
|
||||
}
|
||||
});
|
||||
|
||||
this.customMenus[menuIndex].buttonElement.on(EventType.MOUSE_LEAVE, () => {
|
||||
if (!this.isFocused) {
|
||||
this.cleanupCustomMenu();
|
||||
if (!this.isOpen && this.isFocused) {
|
||||
this.customMenus[menuIndex].buttonElement.domBlur();
|
||||
}
|
||||
});
|
||||
|
||||
this.customMenus[menuIndex].buttonElement.on(EventType.BLUR, () => {
|
||||
this.cleanupCustomMenu();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -569,6 +702,8 @@ export class MenubarPart extends Part {
|
|||
this.focusPrevious();
|
||||
} else if (event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Tab)) {
|
||||
this.focusNext();
|
||||
} else if (event.equals(KeyCode.Escape) && this.isFocused && !this.isOpen) {
|
||||
this.focusState = this.currentMenubarVisibility === 'toggle' ? MenubarState.HIDDEN : MenubarState.VISIBLE;
|
||||
} else {
|
||||
eventHandled = false;
|
||||
}
|
||||
|
@ -579,9 +714,31 @@ export class MenubarPart extends Part {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.container.on(EventType.FOCUS_IN, (e) => {
|
||||
let event = e as FocusEvent;
|
||||
|
||||
if (event.relatedTarget) {
|
||||
if (!this.container.getHTMLElement().contains(event.relatedTarget as HTMLElement)) {
|
||||
this.focusToReturn = $(event.relatedTarget as HTMLElement);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.container.on(EventType.FOCUS_OUT, (e) => {
|
||||
let event = e as FocusEvent;
|
||||
|
||||
if (event.relatedTarget) {
|
||||
if (!this.container.getHTMLElement().contains(event.relatedTarget as HTMLElement)) {
|
||||
this.focusToReturn = null;
|
||||
this.focusState = this.currentMenubarVisibility === 'toggle' ? MenubarState.HIDDEN : MenubarState.VISIBLE;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private focusPrevious(): void {
|
||||
|
||||
if (!this.focusedMenu) {
|
||||
return;
|
||||
}
|
||||
|
@ -592,7 +749,13 @@ export class MenubarPart extends Part {
|
|||
return;
|
||||
}
|
||||
|
||||
this.toggleCustomMenu(newFocusedIndex);
|
||||
if (this.isOpen) {
|
||||
this.cleanupCustomMenu();
|
||||
this.showCustomMenu(newFocusedIndex);
|
||||
} else if (this.isFocused) {
|
||||
this.focusedMenu.index = newFocusedIndex;
|
||||
this.customMenus[newFocusedIndex].buttonElement.domFocus();
|
||||
}
|
||||
}
|
||||
|
||||
private focusNext(): void {
|
||||
|
@ -606,7 +769,13 @@ export class MenubarPart extends Part {
|
|||
return;
|
||||
}
|
||||
|
||||
this.toggleCustomMenu(newFocusedIndex);
|
||||
if (this.isOpen) {
|
||||
this.cleanupCustomMenu();
|
||||
this.showCustomMenu(newFocusedIndex);
|
||||
} else if (this.isFocused) {
|
||||
this.focusedMenu.index = newFocusedIndex;
|
||||
this.customMenus[newFocusedIndex].buttonElement.domFocus();
|
||||
}
|
||||
}
|
||||
|
||||
private getMenubarMenus(): IMenubarData {
|
||||
|
@ -665,32 +834,14 @@ export class MenubarPart extends Part {
|
|||
if (this.focusedMenu.widget) {
|
||||
this.focusedMenu.widget.dispose();
|
||||
}
|
||||
|
||||
this.focusedMenu = { index: this.focusedMenu.index };
|
||||
}
|
||||
|
||||
this.focusedMenu = null;
|
||||
}
|
||||
|
||||
public focusCustomMenu(menuTitle: string): void {
|
||||
this.toggleCustomMenu(0);
|
||||
}
|
||||
|
||||
private toggleCustomMenu(menuIndex: number): void {
|
||||
private showCustomMenu(menuIndex: number): void {
|
||||
const customMenu = this.customMenus[menuIndex];
|
||||
|
||||
if (this.focusedMenu) {
|
||||
let hiding: boolean = this.isCurrentMenu(menuIndex);
|
||||
|
||||
// Need to cleanup currently displayed menu
|
||||
this.cleanupCustomMenu();
|
||||
|
||||
// Hiding this menu
|
||||
if (hiding) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
customMenu.buttonElement.domFocus();
|
||||
|
||||
let menuHolder = $(customMenu.buttonElement).div({ class: 'menubar-menu-items-holder' });
|
||||
|
||||
$(menuHolder.getHTMLElement().parentElement).addClass('open');
|
||||
|
@ -711,14 +862,12 @@ export class MenubarPart extends Part {
|
|||
let menuWidget = this._register(new Menu(menuHolder.getHTMLElement(), customMenu.actions, menuOptions));
|
||||
|
||||
this._register(menuWidget.onDidCancel(() => {
|
||||
this.cleanupCustomMenu();
|
||||
this.isFocused = false;
|
||||
this.focusState = MenubarState.FOCUSED;
|
||||
}));
|
||||
|
||||
this._register(menuWidget.onDidBlur(() => {
|
||||
setTimeout(() => {
|
||||
this.cleanupCustomMenu();
|
||||
this.isFocused = false;
|
||||
}, 100);
|
||||
}));
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import { IDelegate, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { IVirtualDelegate, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { clearNode, addClass, removeClass, toggleClass, addDisposableListener, EventType, EventHelper } from 'vs/base/browser/dom';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
@ -26,7 +26,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
|||
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
|
||||
import { Severity } from 'vs/platform/notification/common/notification';
|
||||
|
||||
export class NotificationsListDelegate implements IDelegate<INotificationViewItem> {
|
||||
export class NotificationsListDelegate implements IVirtualDelegate<INotificationViewItem> {
|
||||
|
||||
private static readonly ROW_HEIGHT = 42;
|
||||
private static readonly LINE_HEIGHT = 22;
|
||||
|
@ -278,6 +278,10 @@ export class NotificationRenderer implements IRenderer<INotificationViewItem, IN
|
|||
data.renderer.setInput(notification);
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: INotificationTemplateData): void {
|
||||
templateData.toDispose = dispose(templateData.toDispose);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
'use strict';
|
||||
|
||||
import 'vs/css!./quickInput';
|
||||
import { IDelegate, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { IVirtualDelegate, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { WorkbenchList } from 'vs/platform/list/browser/listService';
|
||||
|
@ -127,13 +127,17 @@ class ListElementRenderer implements IRenderer<ListElement, IListElementTemplate
|
|||
data.detail.set(element.item.detail, detailHighlights);
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
disposeTemplate(data: IListElementTemplateData): void {
|
||||
data.toDisposeElement = dispose(data.toDisposeElement);
|
||||
data.toDisposeTemplate = dispose(data.toDisposeTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
class ListElementDelegate implements IDelegate<ListElement> {
|
||||
class ListElementDelegate implements IVirtualDelegate<ListElement> {
|
||||
|
||||
getHeight(element: ListElement): number {
|
||||
return element.item.detail ? 44 : 22;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
.monaco-workbench > .sidebar > .title > .title-label span {
|
||||
.monaco-workbench > .sidebar > .title > .title-label h2 {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-panel-view .panel > .panel-header > .title {
|
||||
.monaco-panel-view .panel > .panel-header h3.title {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
font-size: 11px;
|
||||
-webkit-margin-before: 0;
|
||||
-webkit-margin-after: 0;
|
||||
display: flex;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ export abstract class ViewletPanel extends Panel implements IView {
|
|||
protected renderHeader(container: HTMLElement): void {
|
||||
this.headerContainer = container;
|
||||
|
||||
this.renderHeaderTitle(container);
|
||||
this.renderHeaderTitle(container, this.title);
|
||||
|
||||
const actions = append(container, $('.actions'));
|
||||
this.toolbar = new ToolBar(actions, this.contextMenuService, {
|
||||
|
@ -119,8 +119,8 @@ export abstract class ViewletPanel extends Panel implements IView {
|
|||
this.updateActionsVisibility();
|
||||
}
|
||||
|
||||
protected renderHeaderTitle(container: HTMLElement): void {
|
||||
append(container, $('.title', null, this.title));
|
||||
protected renderHeaderTitle(container: HTMLElement, title: string): void {
|
||||
append(container, $('h3.title', null, title));
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
|
||||
/* Font Families (with CJK support) */
|
||||
|
||||
.monaco-shell { font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Ubuntu", "Droid Sans", sans-serif; }
|
||||
.monaco-shell:lang(zh-Hans) { font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; }
|
||||
.monaco-shell:lang(zh-Hant) { font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Microsoft Jhenghei", "PingFang TC", "Source Han Sans TC", "Source Han Sans", "Source Han Sans TW", sans-serif; }
|
||||
.monaco-shell:lang(ja) { font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Meiryo", "Hiragino Kaku Gothic Pro", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", "Sazanami Gothic", "IPA Gothic", sans-serif; }
|
||||
.monaco-shell:lang(ko) { font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Malgun Gothic", "Nanum Gothic", "Dotom", "Apple SD Gothic Neo", "AppleGothic", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; }
|
||||
.monaco-shell { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Ubuntu", "Droid Sans", sans-serif; }
|
||||
.monaco-shell:lang(zh-Hans) { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; }
|
||||
.monaco-shell:lang(zh-Hant) { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Microsoft Jhenghei", "PingFang TC", "Source Han Sans TC", "Source Han Sans", "Source Han Sans TW", sans-serif; }
|
||||
.monaco-shell:lang(ja) { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Meiryo", "Hiragino Kaku Gothic Pro", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", "Sazanami Gothic", "IPA Gothic", sans-serif; }
|
||||
.monaco-shell:lang(ko) { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", "Noto Sans", "Malgun Gothic", "Nanum Gothic", "Dotom", "Apple SD Gothic Neo", "AppleGothic", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; }
|
||||
|
||||
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
||||
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.monaco-workbench-container {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.monaco-workbench {
|
||||
font-size: 13px;
|
||||
line-height: 1.4em;
|
||||
|
|
|
@ -16,7 +16,6 @@ import { toErrorMessage } from 'vs/base/common/errorMessage';
|
|||
import product from 'vs/platform/node/product';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import pkg from 'vs/platform/node/package';
|
||||
import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService';
|
||||
import { Workbench, IWorkbenchStartedInfo } from 'vs/workbench/electron-browser/workbench';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { NullTelemetryService, configurationTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
|
@ -46,7 +45,6 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
|
|||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ILifecycleService, LifecyclePhase, ShutdownReason, StartupKind } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
@ -93,7 +91,7 @@ import { NotificationService } from 'vs/workbench/services/notification/common/n
|
|||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { DialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService';
|
||||
import { DialogChannel } from 'vs/platform/dialogs/common/dialogIpc';
|
||||
import { EventType, addDisposableListener, addClass, getClientArea } from 'vs/base/browser/dom';
|
||||
import { EventType, addDisposableListener, addClass } from 'vs/base/browser/dom';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { OpenerService } from 'vs/editor/browser/services/openerService';
|
||||
import { SearchHistoryService } from 'vs/workbench/services/search/node/searchHistoryService';
|
||||
|
@ -120,7 +118,6 @@ export class WorkbenchShell extends Disposable {
|
|||
private storageService: IStorageService;
|
||||
private environmentService: IEnvironmentService;
|
||||
private logService: ILogService;
|
||||
private contextViewService: ContextViewService;
|
||||
private configurationService: IConfigurationService;
|
||||
private contextService: IWorkspaceContextService;
|
||||
private telemetryService: ITelemetryService;
|
||||
|
@ -135,8 +132,6 @@ export class WorkbenchShell extends Disposable {
|
|||
private container: HTMLElement;
|
||||
private previousErrorValue: string;
|
||||
private previousErrorTime: number;
|
||||
private content: HTMLElement;
|
||||
private contentsContainer: HTMLElement;
|
||||
|
||||
private configuration: IWindowConfiguration;
|
||||
private workbench: Workbench;
|
||||
|
@ -160,20 +155,15 @@ export class WorkbenchShell extends Disposable {
|
|||
this.previousErrorTime = 0;
|
||||
}
|
||||
|
||||
private createContents(parent: HTMLElement): HTMLElement {
|
||||
|
||||
private renderContents(): void {
|
||||
// ARIA
|
||||
aria.setARIAContainer(document.body);
|
||||
|
||||
// Workbench Container
|
||||
const workbenchContainer = document.createElement('div');
|
||||
parent.appendChild(workbenchContainer);
|
||||
|
||||
// Instantiation service with services
|
||||
const [instantiationService, serviceCollection] = this.initServiceCollection(parent);
|
||||
const [instantiationService, serviceCollection] = this.initServiceCollection(this.container);
|
||||
|
||||
// Workbench
|
||||
this.workbench = this.createWorkbench(instantiationService, serviceCollection, parent, workbenchContainer);
|
||||
this.workbench = this.createWorkbench(instantiationService, serviceCollection, this.container);
|
||||
|
||||
// Window
|
||||
this.workbench.getInstantiationService().createInstance(ElectronWindow);
|
||||
|
@ -186,13 +176,11 @@ export class WorkbenchShell extends Disposable {
|
|||
this.lifecycleService.when(LifecyclePhase.Running).then(() => {
|
||||
clearTimeout(timeoutHandle);
|
||||
});
|
||||
|
||||
return workbenchContainer;
|
||||
}
|
||||
|
||||
private createWorkbench(instantiationService: IInstantiationService, serviceCollection: ServiceCollection, parent: HTMLElement, workbenchContainer: HTMLElement): Workbench {
|
||||
private createWorkbench(instantiationService: IInstantiationService, serviceCollection: ServiceCollection, container: HTMLElement): Workbench {
|
||||
try {
|
||||
const workbench = instantiationService.createInstance(Workbench, parent, workbenchContainer, this.configuration, serviceCollection, this.lifecycleService, this.mainProcessClient);
|
||||
const workbench = instantiationService.createInstance(Workbench, container, this.configuration, serviceCollection, this.lifecycleService, this.mainProcessClient);
|
||||
|
||||
// Set lifecycle phase to `Restoring`
|
||||
this.lifecycleService.phase = LifecyclePhase.Restoring;
|
||||
|
@ -418,9 +406,6 @@ export class WorkbenchShell extends Disposable {
|
|||
|
||||
serviceCollection.set(ICommandService, new SyncDescriptor(CommandService));
|
||||
|
||||
this.contextViewService = instantiationService.createInstance(ContextViewService, this.container);
|
||||
serviceCollection.set(IContextViewService, this.contextViewService);
|
||||
|
||||
serviceCollection.set(IMarkerService, new SyncDescriptor(MarkerService));
|
||||
|
||||
serviceCollection.set(IModeService, new SyncDescriptor(WorkbenchModeServiceImpl));
|
||||
|
@ -472,13 +457,8 @@ export class WorkbenchShell extends Disposable {
|
|||
// Shell Class for CSS Scoping
|
||||
addClass(this.container, 'monaco-shell');
|
||||
|
||||
// Controls
|
||||
this.content = document.createElement('div');
|
||||
addClass(this.content, 'monaco-shell-content');
|
||||
this.container.appendChild(this.content);
|
||||
|
||||
// Create Contents
|
||||
this.contentsContainer = this.createContents(this.content);
|
||||
this.renderContents();
|
||||
|
||||
// Layout
|
||||
this.layout();
|
||||
|
@ -521,12 +501,6 @@ export class WorkbenchShell extends Disposable {
|
|||
}
|
||||
|
||||
private layout(): void {
|
||||
const clientArea = getClientArea(this.container);
|
||||
|
||||
this.contentsContainer.style.width = `${clientArea.width}px`;
|
||||
this.contentsContainer.style.height = `${clientArea.height}px`;
|
||||
|
||||
this.contextViewService.layout();
|
||||
this.workbench.layout();
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,6 @@ export class Workbench extends Disposable implements IPartService {
|
|||
_serviceBrand: any;
|
||||
|
||||
private workbenchParams: WorkbenchParams;
|
||||
private workbenchContainer: Builder;
|
||||
private workbench: Builder;
|
||||
private workbenchStarted: boolean;
|
||||
private workbenchCreated: boolean;
|
||||
|
@ -200,6 +199,7 @@ export class Workbench extends Disposable implements IPartService {
|
|||
private editorService: EditorService;
|
||||
private editorGroupService: IEditorGroupsService;
|
||||
private viewletService: IViewletService;
|
||||
private contextViewService: ContextViewService;
|
||||
private contextKeyService: IContextKeyService;
|
||||
private keybindingService: IKeybindingService;
|
||||
private backupFileService: IBackupFileService;
|
||||
|
@ -236,7 +236,6 @@ export class Workbench extends Disposable implements IPartService {
|
|||
private closeEmptyWindowScheduler: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.onAllEditorsClosed(), 50));
|
||||
|
||||
constructor(
|
||||
private parent: HTMLElement,
|
||||
private container: HTMLElement,
|
||||
private configuration: IWindowConfiguration,
|
||||
serviceCollection: ServiceCollection,
|
||||
|
@ -250,7 +249,6 @@ export class Workbench extends Disposable implements IPartService {
|
|||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@IWindowService private windowService: IWindowService,
|
||||
@INotificationService private notificationService: NotificationService,
|
||||
@IContextViewService private contextViewService: ContextViewService,
|
||||
@ITelemetryService private telemetryService: TelemetryService
|
||||
) {
|
||||
super();
|
||||
|
@ -300,11 +298,10 @@ export class Workbench extends Disposable implements IPartService {
|
|||
}
|
||||
|
||||
private createWorkbench(): void {
|
||||
this.workbenchContainer = $('.monaco-workbench-container');
|
||||
this.workbench = $().div({
|
||||
'class': `monaco-workbench ${isWindows ? 'windows' : isLinux ? 'linux' : 'mac'}`,
|
||||
id: Identifiers.WORKBENCH_CONTAINER
|
||||
}).appendTo(this.workbenchContainer);
|
||||
});
|
||||
}
|
||||
|
||||
private createGlobalActions(): void {
|
||||
|
@ -355,6 +352,10 @@ export class Workbench extends Disposable implements IPartService {
|
|||
// List
|
||||
serviceCollection.set(IListService, this.instantiationService.createInstance(ListService));
|
||||
|
||||
// Context view service
|
||||
this.contextViewService = this.instantiationService.createInstance(ContextViewService, this.workbench.getHTMLElement());
|
||||
serviceCollection.set(IContextViewService, this.contextViewService);
|
||||
|
||||
// Use themable context menus when custom titlebar is enabled to match custom menubar
|
||||
if (!isMacintosh && this.getCustomTitleBarStyle() === 'custom') {
|
||||
serviceCollection.set(IContextMenuService, new SyncDescriptor(HTMLContextMenuService, null, this.telemetryService, this.notificationService, this.contextViewService));
|
||||
|
@ -975,12 +976,6 @@ export class Workbench extends Disposable implements IPartService {
|
|||
// Apply font aliasing
|
||||
this.setFontAliasing(this.fontAliasing);
|
||||
|
||||
// Apply title style if shown
|
||||
const titleStyle = this.getCustomTitleBarStyle();
|
||||
if (titleStyle) {
|
||||
DOM.addClass(this.parent, `titlebar-style-${titleStyle}`);
|
||||
}
|
||||
|
||||
// Apply fullscreen state
|
||||
if (browser.isFullscreen()) {
|
||||
this.workbench.addClass('fullscreen');
|
||||
|
@ -999,7 +994,7 @@ export class Workbench extends Disposable implements IPartService {
|
|||
this.createNotificationsHandlers();
|
||||
|
||||
// Add Workbench to DOM
|
||||
this.workbenchContainer.build(this.container);
|
||||
this.workbench.appendTo(this.container);
|
||||
}
|
||||
|
||||
private createTitlebarPart(): void {
|
||||
|
@ -1292,6 +1287,8 @@ export class Workbench extends Disposable implements IPartService {
|
|||
}
|
||||
|
||||
layout(options?: ILayoutOptions): void {
|
||||
this.contextViewService.layout();
|
||||
|
||||
if (this.workbenchStarted && !this.workbenchShutdown) {
|
||||
this.workbenchLayout.layout(options);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
|
||||
.monaco-editor .review-widget .body .review-comment .review-comment-contents {
|
||||
margin-left: 20px;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.monaco-editor .review-widget .body pre {
|
||||
|
|
|
@ -23,7 +23,7 @@ import { basename } from 'vs/base/common/paths';
|
|||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IDelegate, IListContextMenuEvent, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { IVirtualDelegate, IListContextMenuEvent, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { IEditor } from 'vs/workbench/common/editor';
|
||||
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
|
@ -221,7 +221,7 @@ export class BreakpointsView extends ViewletPanel {
|
|||
}
|
||||
}
|
||||
|
||||
class BreakpointsDelegate implements IDelegate<IEnablement> {
|
||||
class BreakpointsDelegate implements IVirtualDelegate<IEnablement> {
|
||||
|
||||
constructor(private debugService: IDebugService) {
|
||||
// noop
|
||||
|
@ -338,6 +338,10 @@ class BreakpointsRenderer implements IRenderer<IBreakpoint, IBreakpointTemplateD
|
|||
}
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IBreakpointTemplateData): void {
|
||||
dispose(templateData.toDispose);
|
||||
}
|
||||
|
@ -383,6 +387,10 @@ class ExceptionBreakpointsRenderer implements IRenderer<IExceptionBreakpoint, IB
|
|||
data.checkbox.checked = exceptionBreakpoint.enabled;
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IBaseBreakpointTemplateData): void {
|
||||
dispose(templateData.toDispose);
|
||||
}
|
||||
|
@ -440,6 +448,10 @@ class FunctionBreakpointsRenderer implements IRenderer<FunctionBreakpoint, IBase
|
|||
}
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IBaseBreakpointWithIconTemplateData): void {
|
||||
dispose(templateData.toDispose);
|
||||
}
|
||||
|
@ -511,6 +523,10 @@ class FunctionBreakpointInputRenderer implements IRenderer<IFunctionBreakpoint,
|
|||
data.inputBox.select();
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IInputTemplateData): void {
|
||||
dispose(templateData.toDispose);
|
||||
}
|
||||
|
|
|
@ -88,10 +88,10 @@ export class CallStackView extends TreeViewsViewletPanel {
|
|||
}
|
||||
|
||||
protected renderHeaderTitle(container: HTMLElement): void {
|
||||
const title = dom.append(container, $('.title.debug-call-stack-title'));
|
||||
const name = dom.append(title, $('span'));
|
||||
name.textContent = this.options.title;
|
||||
this.pauseMessage = dom.append(title, $('span.pause-message'));
|
||||
let titleContainer = dom.append(container, $('.debug-call-stack-title'));
|
||||
super.renderHeaderTitle(titleContainer, this.options.title);
|
||||
|
||||
this.pauseMessage = dom.append(titleContainer, $('span.pause-message'));
|
||||
this.pauseMessage.hidden = true;
|
||||
this.pauseMessageLabel = dom.append(this.pauseMessage, $('span.label'));
|
||||
}
|
||||
|
|
|
@ -2321,7 +2321,12 @@ export class AddToWorkspaceFolderRecommendationsAction extends AbstractConfigure
|
|||
}
|
||||
|
||||
return this.addExtensionToWorkspaceFolderConfig(configurationFile, extensionId, shouldRecommend).then(() => {
|
||||
this.notificationService.info(localize('AddToWorkspaceFolderRecommendations.success', 'The extension was successfully added to this workspace folder\'s recommendations.'));
|
||||
this.notificationService.prompt(Severity.Info,
|
||||
localize('AddToWorkspaceFolderRecommendations.success', 'The extension was successfully added to this workspace folder\'s recommendations.'),
|
||||
[{
|
||||
label: localize('viewChanges', "View Changes"),
|
||||
run: () => this.openExtensionsFile(configurationFile)
|
||||
}]);
|
||||
}, err => {
|
||||
this.notificationService.error(localize('AddToWorkspaceFolderRecommendations.failure', 'Failed to write to extensions.json. {0}', err));
|
||||
});
|
||||
|
@ -2333,7 +2338,12 @@ export class AddToWorkspaceFolderRecommendationsAction extends AbstractConfigure
|
|||
}
|
||||
|
||||
return this.addExtensionToWorkspaceFolderConfig(configurationFile, extensionId, shouldRecommend).then(() => {
|
||||
this.notificationService.info(localize('AddToWorkspaceFolderIgnoredRecommendations.success', 'The extension was successfully added to this workspace folder\'s unwanted recommendations.'));
|
||||
this.notificationService.prompt(Severity.Info,
|
||||
localize('AddToWorkspaceFolderIgnoredRecommendations.success', 'The extension was successfully added to this workspace folder\'s unwanted recommendations.'),
|
||||
[{
|
||||
label: localize('viewChanges', "View Changes"),
|
||||
run: () => this.openExtensionsFile(configurationFile)
|
||||
}]);
|
||||
}, err => {
|
||||
this.notificationService.error(localize('AddToWorkspaceFolderRecommendations.failure', 'Failed to write to extensions.json. {0}', err));
|
||||
});
|
||||
|
@ -2381,7 +2391,13 @@ export class AddToWorkspaceRecommendationsAction extends AbstractConfigureRecomm
|
|||
}
|
||||
|
||||
return this.addExtensionToWorkspaceConfig(workspaceConfig, extensionId, shouldRecommend).then(() => {
|
||||
this.notificationService.info(localize('AddToWorkspaceRecommendations.success', 'The extension was successfully added to this workspace\'s recommendations.'));
|
||||
this.notificationService.prompt(Severity.Info,
|
||||
localize('AddToWorkspaceRecommendations.success', 'The extension was successfully added to this workspace\'s recommendations.'),
|
||||
[{
|
||||
label: localize('viewChanges', "View Changes"),
|
||||
run: () => this.openWorkspaceConfigurationFile(workspaceConfig)
|
||||
}]);
|
||||
|
||||
}, err => {
|
||||
this.notificationService.error(localize('AddToWorkspaceRecommendations.failure', 'Failed to write. {0}', err));
|
||||
});
|
||||
|
@ -2392,7 +2408,12 @@ export class AddToWorkspaceRecommendationsAction extends AbstractConfigureRecomm
|
|||
}
|
||||
|
||||
return this.addExtensionToWorkspaceConfig(workspaceConfig, extensionId, shouldRecommend).then(() => {
|
||||
this.notificationService.info(localize('AddToWorkspaceUnwantedRecommendations.success', 'The extension was successfully added to this workspace\'s unwanted recommendations.'));
|
||||
this.notificationService.prompt(Severity.Info,
|
||||
localize('AddToWorkspaceUnwantedRecommendations.success', 'The extension was successfully added to this workspace\'s unwanted recommendations.'),
|
||||
[{
|
||||
label: localize('viewChanges', "View Changes"),
|
||||
run: () => this.openWorkspaceConfigurationFile(workspaceConfig)
|
||||
}]);
|
||||
}, err => {
|
||||
this.notificationService.error(localize('AddToWorkspaceRecommendations.failure', 'Failed to write. {0}', err));
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
|||
import { Action } from 'vs/base/common/actions';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { IVirtualDelegate } from 'vs/base/browser/ui/list/list';
|
||||
import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
|
||||
import { once } from 'vs/base/common/event';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
|
@ -38,7 +38,7 @@ export interface ITemplateData {
|
|||
extensionDisposables: IDisposable[];
|
||||
}
|
||||
|
||||
export class Delegate implements IDelegate<IExtension> {
|
||||
export class Delegate implements IVirtualDelegate<IExtension> {
|
||||
getHeight() { return 62; }
|
||||
getTemplateId() { return 'extension'; }
|
||||
}
|
||||
|
@ -194,6 +194,10 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
|
|||
});
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
private updateRecommendationStatus(extension: IExtension, data: ITemplateData) {
|
||||
const extRecommendations = this.extensionTipsService.getAllRecommendationsWithReason();
|
||||
let ariaLabel = extension.displayName + '. ';
|
||||
|
|
|
@ -71,9 +71,8 @@ export class ExtensionsListView extends ViewletPanel {
|
|||
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService);
|
||||
}
|
||||
|
||||
renderHeader(container: HTMLElement): void {
|
||||
const titleDiv = append(container, $('div.title'));
|
||||
append(titleDiv, $('span')).textContent = this.options.title;
|
||||
renderHeaderTitle(container: HTMLElement): void {
|
||||
super.renderHeaderTitle(container, this.options.title);
|
||||
|
||||
this.badgeContainer = append(container, $('.count-badge-wrapper'));
|
||||
this.badge = new CountBadge(this.badgeContainer);
|
||||
|
|
|
@ -6,4 +6,9 @@
|
|||
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-label.extensions {
|
||||
-webkit-mask: url('extensions-dark.svg') no-repeat 50% 50%;
|
||||
-webkit-mask-size: 21px;
|
||||
}
|
||||
|
||||
.extensions .split-view-view .panel-header .count-badge-wrapper {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
}
|
|
@ -21,7 +21,7 @@ import { IExtensionsWorkbenchService, IExtension } from 'vs/workbench/parts/exte
|
|||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IExtensionService, IExtensionDescription, IExtensionsStatus, IExtensionHostProfile } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IDelegate, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { IVirtualDelegate, IRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { WorkbenchList } from 'vs/platform/list/browser/listService';
|
||||
import { append, $, addClass, toggleClass, Dimension } from 'vs/base/browser/dom';
|
||||
import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
|
@ -216,7 +216,7 @@ export class RuntimeExtensionsEditor extends BaseEditor {
|
|||
|
||||
const TEMPLATE_ID = 'runtimeExtensionElementTemplate';
|
||||
|
||||
const delegate = new class implements IDelegate<IRuntimeExtension>{
|
||||
const delegate = new class implements IVirtualDelegate<IRuntimeExtension>{
|
||||
getHeight(element: IRuntimeExtension): number {
|
||||
return 62;
|
||||
}
|
||||
|
@ -369,6 +369,8 @@ export class RuntimeExtensionsEditor extends BaseEditor {
|
|||
}
|
||||
},
|
||||
|
||||
disposeElement: () => null,
|
||||
|
||||
disposeTemplate: (data: IRuntimeExtensionTemplateData): void => {
|
||||
data.disposables = dispose(data.disposables);
|
||||
}
|
||||
|
|
|
@ -436,6 +436,9 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
|||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
when: EditorContextKeys.focus.toNegated(),
|
||||
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_C,
|
||||
win: {
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_C)
|
||||
},
|
||||
id: COPY_RELATIVE_PATH_COMMAND_ID,
|
||||
handler: (accessor, resource: URI | object) => {
|
||||
const resources = getMultiSelectedResources(resource, accessor.get(IListService), accessor.get(IEditorService));
|
||||
|
|
|
@ -251,12 +251,12 @@ configurationRegistry.registerConfiguration({
|
|||
nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'files.autoSave.onWindowChange' }, "A dirty file is automatically saved when the window loses focus.")
|
||||
],
|
||||
'default': AutoSaveConfiguration.OFF,
|
||||
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'autoSave' }, "Controls auto save of dirty files. Accepted values: '{0}', '{1}', '{2}' (editor loses focus), '{3}' (window loses focus). If set to '{4}', you can configure the delay in 'files.autoSaveDelay'.", AutoSaveConfiguration.OFF, AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE, AutoSaveConfiguration.AFTER_DELAY)
|
||||
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'autoSave' }, "Controls auto save of dirty files. Accepted values: '{0}', '{1}', '{2}' (editor loses focus), '{3}' (window loses focus). If set to '{4}', you can configure the delay in [`files.autoSaveDelay`](#files.autoSaveDelay). Read more about autosave [here](https://code.visualstudio.com/docs/editor/codebasics#_save-auto-save)", AutoSaveConfiguration.OFF, AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE, AutoSaveConfiguration.AFTER_DELAY)
|
||||
},
|
||||
'files.autoSaveDelay': {
|
||||
'type': 'number',
|
||||
'default': 1000,
|
||||
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'autoSaveDelay' }, "Controls the delay in ms after which a dirty file is saved automatically. Only applies when 'files.autoSave' is set to '{0}'", AutoSaveConfiguration.AFTER_DELAY)
|
||||
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'autoSaveDelay' }, "Controls the delay in ms after which a dirty file is saved automatically. Only applies when [`files.autoSave`](#files.autoSave) is set to '{0}'", AutoSaveConfiguration.AFTER_DELAY)
|
||||
},
|
||||
'files.watcherExclude': {
|
||||
'type': 'object',
|
||||
|
|
|
@ -26,7 +26,7 @@ import { attachStylerCallback } from 'vs/platform/theme/common/styler';
|
|||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { badgeBackground, badgeForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { WorkbenchList } from 'vs/platform/list/browser/listService';
|
||||
import { IDelegate, IRenderer, IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { IVirtualDelegate, IRenderer, IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { EditorLabel } from 'vs/workbench/browser/labels';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
|
@ -176,8 +176,7 @@ export class OpenEditorsView extends ViewletPanel {
|
|||
}
|
||||
|
||||
protected renderHeaderTitle(container: HTMLElement): void {
|
||||
const title = dom.append(container, $('.title'));
|
||||
dom.append(title, $('span', null, this.title));
|
||||
super.renderHeaderTitle(container, this.title);
|
||||
|
||||
const count = dom.append(container, $('.count'));
|
||||
this.dirtyCountElement = dom.append(count, $('.monaco-count-badge'));
|
||||
|
@ -489,7 +488,7 @@ class OpenEditorActionRunner extends ActionRunner {
|
|||
}
|
||||
}
|
||||
|
||||
class OpenEditorsDelegate implements IDelegate<OpenEditor | IEditorGroup> {
|
||||
class OpenEditorsDelegate implements IVirtualDelegate<OpenEditor | IEditorGroup> {
|
||||
|
||||
public static readonly ITEM_HEIGHT = 22;
|
||||
|
||||
|
@ -595,6 +594,10 @@ class EditorGroupRenderer implements IRenderer<IEditorGroup, IEditorGroupTemplat
|
|||
templateData.actionBar.context = { groupId: editorGroup.id };
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IEditorGroupTemplateData): void {
|
||||
templateData.actionBar.dispose();
|
||||
dispose(templateData.toDispose);
|
||||
|
@ -691,6 +694,10 @@ class OpenEditorRenderer implements IRenderer<OpenEditor, IOpenEditorTemplateDat
|
|||
});
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
// noop
|
||||
}
|
||||
|
||||
disposeTemplate(templateData: IOpenEditorTemplateData): void {
|
||||
templateData.actionBar.dispose();
|
||||
templateData.root.dispose();
|
||||
|
|
|
@ -32,7 +32,7 @@ import {
|
|||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IKeybindingEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
|
||||
import { List } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IDelegate, IRenderer, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { IVirtualDelegate, IRenderer, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
|
@ -614,7 +614,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
|
|||
}
|
||||
}
|
||||
|
||||
class Delegate implements IDelegate<IListEntry> {
|
||||
class Delegate implements IVirtualDelegate<IListEntry> {
|
||||
|
||||
getHeight(element: IListEntry) {
|
||||
if (element.templateId === KEYBINDING_ENTRY_TEMPLATE_ID) {
|
||||
|
@ -667,6 +667,9 @@ class KeybindingHeaderRenderer implements IRenderer<IListEntry, any> {
|
|||
renderElement(entry: IListEntry, index: number, template: any): void {
|
||||
}
|
||||
|
||||
disposeElement(): void {
|
||||
}
|
||||
|
||||
disposeTemplate(template: any): void {
|
||||
}
|
||||
}
|
||||
|
@ -704,6 +707,8 @@ class KeybindingItemRenderer implements IRenderer<IKeybindingItemEntry, Keybindi
|
|||
template.when.render(keybindingEntry);
|
||||
}
|
||||
|
||||
disposeElement(): void { }
|
||||
|
||||
disposeTemplate(template: KeybindingItemTemplate): void {
|
||||
template.actions.dispose();
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
.settings-editor {
|
||||
padding-top: 11px;
|
||||
padding-left: 2px;
|
||||
max-width: 1100px;
|
||||
margin: auto;
|
||||
}
|
||||
|
@ -196,11 +197,18 @@
|
|||
opacity: 0.7;
|
||||
margin-top: 3px;
|
||||
overflow: hidden;
|
||||
white-space: pre;
|
||||
text-overflow: ellipsis;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item .setting-item-description * {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item .setting-item-description code {
|
||||
line-height: 15px; /** For some reason, this is needed, otherwise <code> will take up 20px height */
|
||||
}
|
||||
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-measure-container.monaco-tree-row {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
|
@ -209,7 +217,6 @@
|
|||
.settings-editor > .settings-body > .settings-tree-container .setting-item.is-expanded .setting-item-description,
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item.setting-measure-helper .setting-item-description {
|
||||
height: initial;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.settings-editor > .settings-body > .settings-tree-container .setting-item-bool .setting-item-value-description {
|
||||
|
|
|
@ -33,7 +33,7 @@ import { SearchWidget, SettingsTarget, SettingsTargetsWidget } from 'vs/workbenc
|
|||
import { commonlyUsedData, tocData } from 'vs/workbench/parts/preferences/browser/settingsLayout';
|
||||
import { ISettingsEditorViewState, NonExpandableTree, resolveExtensionsSettings, resolveSettingsTree, SearchResultIdx, SearchResultModel, SettingsAccessibilityProvider, SettingsDataSource, SettingsRenderer, SettingsTreeController, SettingsTreeElement, SettingsTreeFilter, SettingsTreeGroupElement, SettingsTreeModel, SettingsTreeSettingElement } from 'vs/workbench/parts/preferences/browser/settingsTree';
|
||||
import { TOCDataSource, TOCRenderer, TOCTreeModel } from 'vs/workbench/parts/preferences/browser/tocTree';
|
||||
import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_FIRST_ROW_FOCUS, CONTEXT_SETTINGS_SEARCH_FOCUS, IPreferencesSearchService, ISearchProvider, CONTEXT_SETTINGS_ROW_FOCUS, CONTEXT_TOC_ROW_FOCUS } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_FIRST_ROW_FOCUS, CONTEXT_SETTINGS_ROW_FOCUS, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IPreferencesSearchService, ISearchProvider } from 'vs/workbench/parts/preferences/common/preferences';
|
||||
import { IPreferencesService, ISearchResult, ISettingsEditorModel } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput';
|
||||
import { DefaultSettingsEditorModel } from 'vs/workbench/services/preferences/common/preferencesModels';
|
||||
|
@ -234,6 +234,16 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
this._register(DOM.addDisposableListener(this.showConfiguredSettingsOnlyCheckbox, 'change', e => this.onShowConfiguredOnlyClicked()));
|
||||
}
|
||||
|
||||
private revealSetting(settingName: string): void {
|
||||
const element = this.settingsTreeModel.getElementByName(settingName);
|
||||
if (element) {
|
||||
this.settingsTree.setSelection([element]);
|
||||
this.settingsTree.setFocus(element);
|
||||
this.settingsTree.reveal(element, 0);
|
||||
this.settingsTree.domFocus();
|
||||
}
|
||||
}
|
||||
|
||||
private openSettingsFile(): TPromise<IEditor> {
|
||||
const currentSettingsTarget = this.settingsTargetsWidget.settingsTarget;
|
||||
|
||||
|
@ -314,6 +324,7 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
const renderer = this.instantiationService.createInstance(SettingsRenderer, this.settingsTreeContainer);
|
||||
this._register(renderer.onDidChangeSetting(e => this.onDidChangeSetting(e.key, e.value)));
|
||||
this._register(renderer.onDidOpenSettings(() => this.openSettingsFile()));
|
||||
this._register(renderer.onDidClickSettingLink(settingName => this.revealSetting(settingName)));
|
||||
|
||||
const treeClass = 'settings-editor-tree';
|
||||
this.settingsTree = this.instantiationService.createInstance(NonExpandableTree, this.settingsTreeContainer,
|
||||
|
@ -693,7 +704,10 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
// Count unique results
|
||||
const counts = {};
|
||||
const filterResult = results[SearchResultIdx.Local];
|
||||
counts['filterResult'] = filterResult.filterMatches.length;
|
||||
if (filterResult) {
|
||||
counts['filterResult'] = filterResult.filterMatches.length;
|
||||
}
|
||||
|
||||
if (nlpResult) {
|
||||
counts['nlpResult'] = nlpResult.filterMatches.length;
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ export const tocData: ITOCEntry = {
|
|||
{
|
||||
id: 'editor/suggestions',
|
||||
label: localize('suggestions', "Suggestions"),
|
||||
settings: ['editor.*suggestion*']
|
||||
settings: ['editor.*suggest*']
|
||||
},
|
||||
{
|
||||
id: 'editor/files',
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { Button } from 'vs/base/browser/ui/button/button';
|
||||
|
@ -12,11 +13,12 @@ import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
|||
import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import { escapeRegExpCharacters } from 'vs/base/common/strings';
|
||||
import { escapeRegExpCharacters, startsWith } from 'vs/base/common/strings';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IAccessibilityProvider, IDataSource, IFilter, IRenderer, ITree } from 'vs/base/parts/tree/browser/tree';
|
||||
|
@ -24,6 +26,7 @@ import { localize } from 'vs/nls';
|
|||
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { WorkbenchTree, WorkbenchTreeController } from 'vs/platform/list/browser/listService';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { registerColor, selectBackground, selectBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
|
@ -97,6 +100,7 @@ export interface ITOCEntry {
|
|||
export class SettingsTreeModel {
|
||||
private _root: SettingsTreeGroupElement;
|
||||
private _treeElementsById = new Map<string, SettingsTreeElement>();
|
||||
private _treeElementsBySettingName = new Map<string, SettingsTreeElement>();
|
||||
|
||||
constructor(
|
||||
private _viewState: ISettingsEditorViewState,
|
||||
|
@ -125,6 +129,10 @@ export class SettingsTreeModel {
|
|||
return this._treeElementsById.get(id);
|
||||
}
|
||||
|
||||
getElementByName(name: string): SettingsTreeElement {
|
||||
return this._treeElementsBySettingName.get(name);
|
||||
}
|
||||
|
||||
private createSettingsTreeGroupElement(tocEntry: ITOCEntry, parent?: SettingsTreeGroupElement): SettingsTreeGroupElement {
|
||||
const element = new SettingsTreeGroupElement();
|
||||
element.id = tocEntry.id;
|
||||
|
@ -153,6 +161,7 @@ export class SettingsTreeModel {
|
|||
private createSettingsTreeSettingElement(setting: ISetting, parent: SettingsTreeGroupElement): SettingsTreeSettingElement {
|
||||
const element = createSettingsTreeSettingElement(setting, parent, this._viewState.settingsTarget, this._configurationService);
|
||||
this._treeElementsById.set(element.id, element);
|
||||
this._treeElementsBySettingName.set(setting.key, element);
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
@ -444,12 +453,16 @@ export class SettingsRenderer implements IRenderer {
|
|||
private readonly _onDidOpenSettings: Emitter<void> = new Emitter<void>();
|
||||
public readonly onDidOpenSettings: Event<void> = this._onDidOpenSettings.event;
|
||||
|
||||
private readonly _onDidClickSettingLink: Emitter<string> = new Emitter<string>();
|
||||
public readonly onDidClickSettingLink: Event<string> = this._onDidClickSettingLink.event;
|
||||
|
||||
private measureContainer: HTMLElement;
|
||||
|
||||
constructor(
|
||||
_measureContainer: HTMLElement,
|
||||
@IThemeService private themeService: IThemeService,
|
||||
@IContextViewService private contextViewService: IContextViewService
|
||||
@IContextViewService private contextViewService: IContextViewService,
|
||||
@IOpenerService private readonly openerService: IOpenerService,
|
||||
) {
|
||||
this.measureContainer = DOM.append(_measureContainer, $('.setting-measure-container.monaco-tree-row'));
|
||||
}
|
||||
|
@ -677,7 +690,28 @@ export class SettingsRenderer implements IRenderer {
|
|||
|
||||
template.labelElement.textContent = element.displayLabel;
|
||||
template.labelElement.title = titleTooltip;
|
||||
template.descriptionElement.textContent = element.description;
|
||||
|
||||
const enumDescriptionText = element.setting.enumDescriptions ?
|
||||
'\n' + element.setting.enumDescriptions
|
||||
.map((desc, i) => ` - \`${element.setting.enum[i]}\`: ${desc}`)
|
||||
.join('\n') :
|
||||
'';
|
||||
const descriptionText = element.description + enumDescriptionText;
|
||||
const renderedDescription = renderMarkdown({ value: descriptionText }, {
|
||||
actionHandler: {
|
||||
callback: (content: string) => {
|
||||
if (startsWith(content, '#')) {
|
||||
this._onDidClickSettingLink.fire(content.substr(1));
|
||||
} else {
|
||||
this.openerService.open(URI.parse(content)).then(void 0, onUnexpectedError);
|
||||
}
|
||||
},
|
||||
disposeables: template.toDispose
|
||||
}
|
||||
});
|
||||
renderedDescription.classList.add('setting-item-description-markdown');
|
||||
template.descriptionElement.innerHTML = '';
|
||||
template.descriptionElement.appendChild(renderedDescription);
|
||||
|
||||
this.renderValue(element, isSelected, <ISettingItemTemplate>template);
|
||||
|
||||
|
@ -842,6 +876,21 @@ export class SettingsTreeController extends WorkbenchTreeController {
|
|||
) {
|
||||
super({}, configurationService);
|
||||
}
|
||||
|
||||
protected onLeftClick(tree: ITree, element: any, eventish: IMouseEvent, origin?: string): boolean {
|
||||
const isLink = eventish.target.tagName.toLowerCase() === 'a' ||
|
||||
eventish.target.parentElement.tagName.toLowerCase() === 'a'; // <code> inside <a>
|
||||
|
||||
if (isLink && DOM.findParentWithClass(eventish.target, 'setting-item-description-markdown', tree.getHTMLElement())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Without this, clicking on the setting description causes the tree to lose focus. I don't know why.
|
||||
// The superclass does not always call it because of DND which is not used here.
|
||||
eventish.preventDefault();
|
||||
|
||||
return super.onLeftClick(tree, element, eventish, origin);
|
||||
}
|
||||
}
|
||||
|
||||
export class SettingsAccessibilityProvider implements IAccessibilityProvider {
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.scm-viewlet .scm-provider > .name > .type {
|
||||
.scm-viewlet .scm-provider > .type {
|
||||
opacity: 0.7;
|
||||
margin-left: 0.5em;
|
||||
font-size: 0.9em;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue