mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
Merge branch 'master' into joh/extpack
This commit is contained in:
commit
ca3407b4d0
|
@ -10,7 +10,7 @@ import LinkProvider from '../features/documentLinkProvider';
|
|||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
|
||||
|
||||
const testFileName = vscode.Uri.parse('test.md');
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
const noopToken = new class implements vscode.CancellationToken {
|
||||
private _onCancellationRequestedEmitter = new vscode.EventEmitter<void>();
|
||||
|
|
|
@ -11,7 +11,7 @@ import { InMemoryDocument } from './inMemoryDocument';
|
|||
import { createNewMarkdownEngine } from './engine';
|
||||
|
||||
|
||||
const testFileName = vscode.Uri.parse('test.md');
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
|
||||
function getSymbolsForFile(fileContents: string) {
|
||||
|
|
|
@ -11,7 +11,7 @@ import MarkdownFoldingProvider from '../features/foldingProvider';
|
|||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
|
||||
const testFileName = vscode.Uri.parse('test.md');
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
suite('markdown.FoldingProvider', () => {
|
||||
test('Should not return anything for empty document', async () => {
|
||||
|
|
|
@ -11,7 +11,7 @@ import { TableOfContentsProvider } from '../tableOfContentsProvider';
|
|||
import { InMemoryDocument } from './inMemoryDocument';
|
||||
import { createNewMarkdownEngine } from './engine';
|
||||
|
||||
const testFileName = vscode.Uri.parse('test.md');
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
suite('markdown.TableOfContentsProvider', () => {
|
||||
test('Lookup should not return anything for empty document', async () => {
|
||||
|
|
|
@ -22,7 +22,7 @@ suite('markdown.WorkspaceSymbolProvider', () => {
|
|||
});
|
||||
|
||||
test('Should return symbols from workspace with one markdown file', async () => {
|
||||
const testFileName = vscode.Uri.parse('test.md');
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
const provider = new MarkdownWorkspaceSymbolProvider(symbolProvider, new InMemoryWorkspaceMarkdownDocumentProvider([
|
||||
new InMemoryDocument(testFileName, `# header1\nabc\n## header2`)
|
||||
|
@ -49,7 +49,7 @@ suite('markdown.WorkspaceSymbolProvider', () => {
|
|||
});
|
||||
|
||||
test('Should update results when markdown file changes symbols', async () => {
|
||||
const testFileName = vscode.Uri.parse('test.md');
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
const workspaceFileProvider = new InMemoryWorkspaceMarkdownDocumentProvider([
|
||||
new InMemoryDocument(testFileName, `# header1`)
|
||||
|
@ -68,7 +68,7 @@ suite('markdown.WorkspaceSymbolProvider', () => {
|
|||
});
|
||||
|
||||
test('Should remove results when file is deleted', async () => {
|
||||
const testFileName = vscode.Uri.parse('test.md');
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
const workspaceFileProvider = new InMemoryWorkspaceMarkdownDocumentProvider([
|
||||
new InMemoryDocument(testFileName, `# header1`)
|
||||
|
@ -84,7 +84,7 @@ suite('markdown.WorkspaceSymbolProvider', () => {
|
|||
});
|
||||
|
||||
test('Should update results when markdown file is created', async () => {
|
||||
const testFileName = vscode.Uri.parse('test.md');
|
||||
const testFileName = vscode.Uri.file('test.md');
|
||||
|
||||
const workspaceFileProvider = new InMemoryWorkspaceMarkdownDocumentProvider([
|
||||
new InMemoryDocument(testFileName, `# header1`)
|
||||
|
@ -94,7 +94,7 @@ suite('markdown.WorkspaceSymbolProvider', () => {
|
|||
assert.strictEqual((await provider.provideWorkspaceSymbols('')).length, 1);
|
||||
|
||||
// Creat file
|
||||
workspaceFileProvider.createDocument(new InMemoryDocument(vscode.Uri.parse('test2.md'), `# new header\nabc\n## header2`));
|
||||
workspaceFileProvider.createDocument(new InMemoryDocument(vscode.Uri.file('test2.md'), `# new header\nabc\n## header2`));
|
||||
const newSymbols = await provider.provideWorkspaceSymbols('');
|
||||
assert.strictEqual(newSymbols.length, 3);
|
||||
});
|
||||
|
@ -105,7 +105,7 @@ class InMemoryWorkspaceMarkdownDocumentProvider implements WorkspaceMarkdownDocu
|
|||
private readonly _documents = new Map<string, vscode.TextDocument>();
|
||||
|
||||
constructor(documents: vscode.TextDocument[]) {
|
||||
for( const doc of documents) {
|
||||
for (const doc of documents) {
|
||||
this._documents.set(doc.fileName, doc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -688,7 +688,7 @@ suite('window namespace tests', () => {
|
|||
const renderer = window.createTerminalRenderer('foo');
|
||||
});
|
||||
|
||||
test('Terminal.sendText should fire Termnial.onInput', (done) => {
|
||||
test('Terminal.sendText should fire Terminal.onInput', (done) => {
|
||||
const reg1 = window.onDidOpenTerminal(terminal => {
|
||||
reg1.dispose();
|
||||
const reg2 = renderer.onDidAcceptInput(data => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.27.0",
|
||||
"distro": "73cb7173636931afba8d741be343ceafb11a177e",
|
||||
"distro": "a4155d9780fbbc94ead6cb3017dd0fc3806c57b8",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
|
@ -50,7 +50,7 @@
|
|||
"vscode-nsfw": "1.0.17",
|
||||
"vscode-ripgrep": "^1.0.1",
|
||||
"vscode-textmate": "^4.0.1",
|
||||
"vscode-xterm": "3.7.0-beta3",
|
||||
"vscode-xterm": "3.7.0-beta4",
|
||||
"winreg": "^1.2.4",
|
||||
"yauzl": "^2.9.1"
|
||||
},
|
||||
|
|
|
@ -6,10 +6,8 @@
|
|||
'use strict';
|
||||
|
||||
import 'vs/css!./progressbar';
|
||||
import { TPromise, ValueCallback } from 'vs/base/common/winjs.base';
|
||||
import * as assert from 'vs/base/common/assert';
|
||||
import { Builder, $ } from 'vs/base/browser/builder';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
|
@ -41,7 +39,6 @@ export class ProgressBar extends Disposable {
|
|||
private element: Builder;
|
||||
private bit: HTMLElement;
|
||||
private totalWork: number;
|
||||
private animationStopToken: ValueCallback;
|
||||
private progressBarBackground: Color;
|
||||
|
||||
constructor(container: HTMLElement, options?: IProgressBarOptions) {
|
||||
|
@ -60,19 +57,7 @@ export class ProgressBar extends Disposable {
|
|||
private create(container: HTMLElement): void {
|
||||
$(container).div({ 'class': css_progress_container }, builder => {
|
||||
this.element = builder.clone();
|
||||
|
||||
builder.div({ 'class': css_progress_bit }).on([DOM.EventType.ANIMATION_START, DOM.EventType.ANIMATION_END, DOM.EventType.ANIMATION_ITERATION], (e: Event) => {
|
||||
switch (e.type) {
|
||||
case DOM.EventType.ANIMATION_ITERATION:
|
||||
if (this.animationStopToken) {
|
||||
this.animationStopToken(null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}, this.toDispose);
|
||||
|
||||
this.bit = builder.getHTMLElement();
|
||||
this.bit = builder.div({ 'class': css_progress_bit }).getHTMLElement();
|
||||
});
|
||||
|
||||
this.applyStyles();
|
||||
|
@ -111,7 +96,7 @@ export class ProgressBar extends Disposable {
|
|||
this.bit.style.width = 'inherit';
|
||||
|
||||
if (delayed) {
|
||||
TPromise.timeout(200).then(() => this.off());
|
||||
setTimeout(200, () => this.off());
|
||||
} else {
|
||||
this.off();
|
||||
}
|
||||
|
@ -121,7 +106,7 @@ export class ProgressBar extends Disposable {
|
|||
else {
|
||||
this.bit.style.opacity = '0';
|
||||
if (delayed) {
|
||||
TPromise.timeout(200).then(() => this.off());
|
||||
setTimeout(200, () => this.off());
|
||||
} else {
|
||||
this.off();
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { isThenable } from 'vs/base/common/async';
|
||||
|
||||
export interface ITelemetryData {
|
||||
from?: string;
|
||||
|
@ -225,7 +226,7 @@ export class ActionRunner implements IActionRunner {
|
|||
protected runAction(action: IAction, context?: any): TPromise<any> {
|
||||
const res = context ? action.run(context) : action.run();
|
||||
|
||||
if (TPromise.is(res)) {
|
||||
if (isThenable(res)) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -408,8 +408,12 @@ export function timeout(n: number): CancelablePromise<void> {
|
|||
});
|
||||
}
|
||||
|
||||
function isWinJSPromise(candidate: any): candidate is TPromise {
|
||||
return TPromise.is(candidate) && typeof (<TPromise>candidate).done === 'function';
|
||||
/**
|
||||
*
|
||||
* @returns `true` if candidate is a `WinJS.Promise`
|
||||
*/
|
||||
export function isWinJSPromise(candidate: any): candidate is TPromise {
|
||||
return isThenable(candidate) && typeof (<TPromise>candidate).done === 'function';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,7 @@ import * as paths from 'vs/base/common/paths';
|
|||
import { LRUCache } from 'vs/base/common/map';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { isThenable } from 'vs/base/common/async';
|
||||
|
||||
export interface IExpression {
|
||||
[pattern: string]: boolean | SiblingClause | any;
|
||||
|
@ -646,7 +647,7 @@ function parseExpressionPattern(pattern: string, value: any, options: IGlobOptio
|
|||
|
||||
const clausePattern = when.replace('$(basename)', name);
|
||||
const matched = hasSibling(clausePattern);
|
||||
return TPromise.is(matched) ?
|
||||
return isThenable(matched) ?
|
||||
matched.then(m => m ? pattern : null) :
|
||||
matched ? pattern : null;
|
||||
};
|
||||
|
@ -699,4 +700,4 @@ function aggregateBasenameMatches(parsedPatterns: (ParsedStringPattern | ParsedE
|
|||
const aggregatedPatterns = parsedPatterns.filter(parsedPattern => !(<ParsedStringPattern>parsedPattern).basenames);
|
||||
aggregatedPatterns.push(aggregate);
|
||||
return aggregatedPatterns;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ export function dirname(path: string, separator = nativeSep): string {
|
|||
return dirname(path.substring(0, path.length - 1));
|
||||
} else {
|
||||
let res = path.substring(0, ~idx);
|
||||
if (isWindows && res.length === 2 && res[res.length - 1] === ':') {
|
||||
if (isWindows && res[res.length - 1] === ':') {
|
||||
res += separator; // make sure drive letters end with backslash
|
||||
}
|
||||
return res;
|
||||
|
|
|
@ -8,7 +8,7 @@ import * as paths from 'vs/base/common/paths';
|
|||
import URI from 'vs/base/common/uri';
|
||||
import { equalsIgnoreCase } from 'vs/base/common/strings';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { isLinux, isWindows } from 'vs/base/common/platform';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
export function getComparisonKey(resource: URI): string {
|
||||
|
@ -28,9 +28,8 @@ export function basenameOrAuthority(resource: URI): string {
|
|||
export function isEqualOrParent(resource: URI, candidate: URI, ignoreCase?: boolean): boolean {
|
||||
if (resource.scheme === candidate.scheme && resource.authority === candidate.authority) {
|
||||
if (resource.scheme === Schemas.file) {
|
||||
return paths.isEqualOrParent(resource.path, candidate.path, ignoreCase);
|
||||
return paths.isEqualOrParent(resource.fsPath, candidate.fsPath, ignoreCase);
|
||||
}
|
||||
|
||||
return paths.isEqualOrParent(resource.path, candidate.path, ignoreCase, '/');
|
||||
}
|
||||
|
||||
|
@ -82,7 +81,12 @@ export function dirname(resource: URI): URI {
|
|||
* @returns The resulting URI.
|
||||
*/
|
||||
export function joinPath(resource: URI, pathFragment: string): URI {
|
||||
const joinedPath = paths.join(resource.path || '/', pathFragment);
|
||||
let joinedPath: string;
|
||||
if (resource.scheme === Schemas.file) {
|
||||
joinedPath = URI.file(paths.join(resource.fsPath, pathFragment)).path;
|
||||
} else {
|
||||
joinedPath = paths.join(resource.path, pathFragment);
|
||||
}
|
||||
return resource.with({
|
||||
path: joinedPath
|
||||
});
|
||||
|
@ -95,7 +99,12 @@ export function joinPath(resource: URI, pathFragment: string): URI {
|
|||
* @returns The URI with the normalized path.
|
||||
*/
|
||||
export function normalizePath(resource: URI): URI {
|
||||
const normalizedPath = paths.normalize(resource.path, false);
|
||||
let normalizedPath: string;
|
||||
if (resource.scheme === Schemas.file) {
|
||||
normalizedPath = URI.file(paths.normalize(resource.fsPath)).path;
|
||||
} else {
|
||||
normalizedPath = paths.normalize(resource.path);
|
||||
}
|
||||
return resource.with({
|
||||
path: normalizedPath
|
||||
});
|
||||
|
@ -127,3 +136,11 @@ export function distinctParents<T>(items: T[], resourceAccessor: (item: T) => UR
|
|||
|
||||
return distinctParents;
|
||||
}
|
||||
|
||||
export function isMalformedFileUri(candidate: URI): URI | undefined {
|
||||
if (!candidate.scheme || isWindows && candidate.scheme.match(/^[a-zA-Z]$/)) {
|
||||
return URI.file((candidate.scheme ? candidate.scheme + ':' : '') + candidate.path);
|
||||
}
|
||||
return void 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
|
|||
|
||||
/**
|
||||
* Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986.
|
||||
* This class is a simple parser which creates the basic component paths
|
||||
* This class is a simple parser which creates the basic component parts
|
||||
* (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation
|
||||
* and encoding.
|
||||
*
|
||||
|
@ -80,8 +80,6 @@ const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
|
|||
* | _____________________|__
|
||||
* / \ / \
|
||||
* urn:example:animal:ferret:nose
|
||||
*
|
||||
*
|
||||
*/
|
||||
export default class URI implements UriComponents {
|
||||
|
||||
|
@ -165,9 +163,27 @@ export default class URI implements UriComponents {
|
|||
|
||||
/**
|
||||
* Returns a string representing the corresponding file system path of this URI.
|
||||
* Will handle UNC paths and normalize windows drive letters to lower-case. Also
|
||||
* uses the platform specific path separator. Will *not* validate the path for
|
||||
* invalid characters and semantics. Will *not* look at the scheme of this URI.
|
||||
* Will handle UNC paths, normalizes windows drive letters to lower-case, and uses the
|
||||
* platform specific path separator.
|
||||
*
|
||||
* * Will *not* validate the path for invalid characters and semantics.
|
||||
* * Will *not* look at the scheme of this URI.
|
||||
* * The result shall *not* be used for display purposes but for accessing a file on disk.
|
||||
*
|
||||
*
|
||||
* The *difference* to `URI#path` is the use of the platform specific separator and the handling
|
||||
* of UNC paths. See the below sample of a file-uri with an authority (UNC path).
|
||||
*
|
||||
* ```ts
|
||||
const u = URI.parse('file://server/c$/folder/file.txt')
|
||||
u.authority === 'server'
|
||||
u.path === '/shares/c$/file.txt'
|
||||
u.fsPath === '\\server\c$\folder\file.txt'
|
||||
```
|
||||
*
|
||||
* Using `URI#path` to read a file (using fs-apis) would not be enough because parts of the path,
|
||||
* namely the server name, would be missing. Therefore `URI#fsPath` exists - it's sugar to ease working
|
||||
* with URIs that represent files on disk (`file` scheme).
|
||||
*/
|
||||
get fsPath(): string {
|
||||
return _makeFsPath(this);
|
||||
|
@ -175,7 +191,7 @@ export default class URI implements UriComponents {
|
|||
|
||||
// ---- modify to new -------------------------
|
||||
|
||||
public with(change: { scheme?: string; authority?: string; path?: string; query?: string; fragment?: string }): URI {
|
||||
public with(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null }): URI {
|
||||
|
||||
if (!change) {
|
||||
return this;
|
||||
|
@ -222,6 +238,12 @@ export default class URI implements UriComponents {
|
|||
|
||||
// ---- parse & validate ------------------------
|
||||
|
||||
/**
|
||||
* Creates a new URI from a string, e.g. `http://www.msft.com/some/path`,
|
||||
* `file:///usr/home`, or `scheme:with/path`.
|
||||
*
|
||||
* @param value A string which represents an URI (see `URI#toString`).
|
||||
*/
|
||||
public static parse(value: string): URI {
|
||||
const match = _regexp.exec(value);
|
||||
if (!match) {
|
||||
|
@ -236,6 +258,28 @@ export default class URI implements UriComponents {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new URI from a file system path, e.g. `c:\my\files`,
|
||||
* `/usr/home`, or `\\server\share\some\path`.
|
||||
*
|
||||
* The *difference* between `URI#parse` and `URI#file` is that the latter treats the argument
|
||||
* as path, not as stringified-uri. E.g. `URI.file(path)` is **not the same as**
|
||||
* `URI.parse('file://' + path)` because the path might contain characters that are
|
||||
* interpreted (# and ?). See the following sample:
|
||||
* ```ts
|
||||
const good = URI.file('/coding/c#/project1');
|
||||
good.scheme === 'file';
|
||||
good.path === '/coding/c#/project1';
|
||||
good.fragment === '';
|
||||
|
||||
const bad = URI.parse('file://' + '/coding/c#/project1');
|
||||
bad.scheme === 'file';
|
||||
bad.path === '/coding/c'; // path is now broken
|
||||
bad.fragment === '/project1';
|
||||
```
|
||||
*
|
||||
* @param path A file system path (see `URI#fsPath`)
|
||||
*/
|
||||
public static file(path: string): URI {
|
||||
|
||||
let authority = _empty;
|
||||
|
@ -263,7 +307,7 @@ export default class URI implements UriComponents {
|
|||
return new _URI('file', authority, path, _empty, _empty);
|
||||
}
|
||||
|
||||
public static from(components: { scheme?: string; authority?: string; path?: string; query?: string; fragment?: string }): URI {
|
||||
public static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI {
|
||||
return new _URI(
|
||||
components.scheme,
|
||||
components.authority,
|
||||
|
@ -276,6 +320,13 @@ export default class URI implements UriComponents {
|
|||
// ---- printing/externalize ---------------------------
|
||||
|
||||
/**
|
||||
* Creates a string presentation for this URI. It's guardeed that calling
|
||||
* `URI.parse` with the result of this function creates an URI which is equal
|
||||
* to this URI.
|
||||
*
|
||||
* * The result shall *not* be used for display purposes but for externalization or transport.
|
||||
* * The result will be encoded using the percentage encoding and encoding happens mostly
|
||||
* ignore the scheme-specific encoding rules.
|
||||
*
|
||||
* @param skipEncoding Do not encode the result, default is `false`
|
||||
*/
|
||||
|
|
2
src/vs/base/common/winjs.base.d.ts
vendored
2
src/vs/base/common/winjs.base.d.ts
vendored
|
@ -29,8 +29,6 @@ export class Promise<T = any> {
|
|||
public static as<T, SomePromise extends PromiseLike<T>>(value: SomePromise): SomePromise;
|
||||
public static as<T>(value: T): Promise<T>;
|
||||
|
||||
public static is(value: any): value is PromiseLike<any>;
|
||||
|
||||
public static timeout(delay: number): Promise<void>;
|
||||
|
||||
public static join<T1, T2>(promises: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import { Promise as WinJSPromise } from './winjs.base';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { isWinJSPromise } from 'vs/base/common/async';
|
||||
|
||||
/**
|
||||
* A polyfill for the native promises. The implementation is based on
|
||||
|
@ -45,7 +46,7 @@ export class PolyfillPromise<T = any> implements Promise<T> {
|
|||
constructor(callback: (resolve: (value?: T) => void, reject: (err?: any) => void) => any);
|
||||
constructor(initOrPromise: WinJSPromise | ((resolve: (value?: T) => void, reject: (err?: any) => void) => any)) {
|
||||
|
||||
if (WinJSPromise.is(initOrPromise)) {
|
||||
if (isWinJSPromise(initOrPromise)) {
|
||||
this._winjsPromise = initOrPromise;
|
||||
} else {
|
||||
this._winjsPromise = new WinJSPromise((resolve, reject) => {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
import 'vs/css!./quickopen';
|
||||
import * as nls from 'vs/nls';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
|
@ -980,11 +979,8 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
|
|||
}
|
||||
|
||||
this.isLoosingFocus = true;
|
||||
TPromise.timeout(0).then(() => {
|
||||
if (!this.isLoosingFocus) {
|
||||
return;
|
||||
}
|
||||
if (this.isDisposed) {
|
||||
setTimeout(() => {
|
||||
if (!this.isLoosingFocus || this.isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -992,7 +988,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider {
|
|||
if (!veto) {
|
||||
this.hide(HideReason.FOCUS_LOST);
|
||||
}
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { dirname, basename, distinctParents, joinPath, isEqual, isEqualOrParent, hasToIgnoreCase, normalizePath, isAbsolutePath } from 'vs/base/common/resources';
|
||||
import { dirname, basename, distinctParents, joinPath, isEqual, isEqualOrParent, hasToIgnoreCase, normalizePath, isAbsolutePath, isMalformedFileUri } from 'vs/base/common/resources';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
|
||||
|
@ -204,4 +204,24 @@ suite('Resources', () => {
|
|||
assert.equal(isEqualOrParent(fileURI3, fileURI, true), false, '15');
|
||||
assert.equal(isEqualOrParent(fileURI5, fileURI5, true), true, '16');
|
||||
});
|
||||
|
||||
function assertMalformedFileUri(path: string, expected: string) {
|
||||
const newURI = isMalformedFileUri(URI.parse(path));
|
||||
assert.equal(newURI && newURI.toString(), expected);
|
||||
}
|
||||
|
||||
test('isMalformedFileUri', () => {
|
||||
if (isWindows) {
|
||||
assertMalformedFileUri('c:/foo/bar', 'file:///c%3A/foo/bar');
|
||||
assertMalformedFileUri('c:\\foo\\bar', 'file:///c%3A/foo/bar');
|
||||
assertMalformedFileUri('\\\\localhost\\c$\\devel\\test', 'file://localhost/c%24/devel/test');
|
||||
}
|
||||
assertMalformedFileUri('/foo/bar', 'file:///foo/bar');
|
||||
|
||||
assertMalformedFileUri('file:///foo/bar', void 0);
|
||||
assertMalformedFileUri('file:///c%3A/foo/bar', void 0);
|
||||
assertMalformedFileUri('file://localhost/c$/devel/test', void 0);
|
||||
assertMalformedFileUri('foo://dadie/foo/bar', void 0);
|
||||
assertMalformedFileUri('foo:///dadie/foo/bar', void 0);
|
||||
});
|
||||
});
|
|
@ -65,6 +65,7 @@ import { MenubarService } from 'vs/platform/menubar/electron-main/menubarService
|
|||
import { MenubarChannel } from 'vs/platform/menubar/common/menubarIpc';
|
||||
import { IUriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay';
|
||||
import { CodeMenu } from 'vs/code/electron-main/menus';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
|
||||
export class CodeApplication {
|
||||
|
||||
|
@ -529,7 +530,9 @@ export class CodeApplication {
|
|||
this.historyMainService.onRecentlyOpenedChange(() => this.historyMainService.updateWindowsJumpList());
|
||||
|
||||
// Start shared process after a while
|
||||
TPromise.timeout(3000).then(() => this.sharedProcess.spawn());
|
||||
const sharedProcess = new RunOnceScheduler(() => this.sharedProcess.spawn(), 3000);
|
||||
sharedProcess.schedule();
|
||||
this.toDispose.push(sharedProcess);
|
||||
}
|
||||
|
||||
private dispose(): void {
|
||||
|
|
|
@ -944,7 +944,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
|||
clonedOptions.folding = false;
|
||||
clonedOptions.codeLens = false;
|
||||
clonedOptions.fixedOverflowWidgets = true;
|
||||
clonedOptions.lineDecorationsWidth = '2ch';
|
||||
// clonedOptions.lineDecorationsWidth = '2ch';
|
||||
if (!clonedOptions.minimap) {
|
||||
clonedOptions.minimap = {};
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
opacity: 0.7;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50% 50%;
|
||||
background-position: center;
|
||||
background-size: 11px 11px;
|
||||
}
|
||||
.monaco-editor.hc-black .insert-sign,
|
||||
.monaco-diff-editor.hc-black .insert-sign,
|
||||
|
|
|
@ -28,6 +28,7 @@ import { overviewRulerWarning, overviewRulerError, overviewRulerInfo } from 'vs/
|
|||
import { ITextModel, IModelDeltaDecoration, IModelDecorationOptions, TrackedRangeStickiness, OverviewRulerLane, DefaultEndOfLine, ITextModelCreationOptions, EndOfLineSequence, IIdentifiedSingleEditOperation, ITextBufferFactory, ITextBuffer, EndOfLinePreference } from 'vs/editor/common/model';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
import { basename } from 'vs/base/common/paths';
|
||||
import { isThenable } from 'vs/base/common/async';
|
||||
|
||||
function MODEL_ID(resource: URI): string {
|
||||
return resource.toString();
|
||||
|
@ -500,7 +501,7 @@ export class ModelServiceImpl implements IModelService {
|
|||
public createModel(value: string | ITextBufferFactory, modeOrPromise: TPromise<IMode> | IMode, resource: URI, isForSimpleWidget: boolean = false): ITextModel {
|
||||
let modelData: ModelData;
|
||||
|
||||
if (!modeOrPromise || TPromise.is(modeOrPromise)) {
|
||||
if (!modeOrPromise || isThenable(modeOrPromise)) {
|
||||
modelData = this._createModelData(value, PLAINTEXT_LANGUAGE_IDENTIFIER, resource, isForSimpleWidget);
|
||||
this.setMode(modelData.model, modeOrPromise);
|
||||
} else {
|
||||
|
@ -521,7 +522,7 @@ export class ModelServiceImpl implements IModelService {
|
|||
if (!modeOrPromise) {
|
||||
return;
|
||||
}
|
||||
if (TPromise.is(modeOrPromise)) {
|
||||
if (isThenable(modeOrPromise)) {
|
||||
modeOrPromise.then((mode) => {
|
||||
if (!model.isDisposed()) {
|
||||
model.setMode(mode.getLanguageIdentifier());
|
||||
|
|
|
@ -332,10 +332,13 @@ export class FoldingController implements IEditorContribution {
|
|||
switch (e.target.type) {
|
||||
case MouseTargetType.GUTTER_LINE_DECORATIONS:
|
||||
const data = e.target.detail as IMarginData;
|
||||
const gutterOffsetX = data.offsetX - data.glyphMarginWidth - data.lineNumbersWidth - data.glyphMarginLeft;
|
||||
const offsetLeftInGutter = (e.target.element as HTMLElement).offsetLeft;
|
||||
const gutterOffsetX = data.offsetX - offsetLeftInGutter;
|
||||
|
||||
// const gutterOffsetX = data.offsetX - data.glyphMarginWidth - data.lineNumbersWidth - data.glyphMarginLeft;
|
||||
|
||||
// TODO@joao TODO@alex TODO@martin this is such that we don't collide with dirty diff
|
||||
if (gutterOffsetX <= 10) {
|
||||
if (gutterOffsetX < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import { ITextModel, IWordAtPosition } from 'vs/editor/common/model';
|
|||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { createCancelablePromise } from 'vs/base/common/async';
|
||||
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
|
||||
export class DefinitionActionConfig {
|
||||
|
||||
|
@ -375,3 +376,31 @@ registerEditorAction(GoToImplementationAction);
|
|||
registerEditorAction(PeekImplementationAction);
|
||||
registerEditorAction(GoToTypeDefinitionAction);
|
||||
registerEditorAction(PeekTypeDefinitionAction);
|
||||
|
||||
// Go to menu
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'editor.action.goToDeclaration',
|
||||
title: nls.localize({ key: 'miGotoDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Definition")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'editor.action.goToTypeDefinition',
|
||||
title: nls.localize({ key: 'miGotoTypeDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Type Definition")
|
||||
},
|
||||
order: 5
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'editor.action.goToImplementation',
|
||||
title: nls.localize({ key: 'miGotoImplementation', comment: ['&& denotes a mnemonic'] }, "Go to &&Implementation")
|
||||
},
|
||||
order: 6
|
||||
});
|
|
@ -8,7 +8,6 @@
|
|||
import 'vs/css!./parameterHints';
|
||||
import * as nls from 'vs/nls';
|
||||
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import * as aria from 'vs/base/browser/ui/aria/aria';
|
||||
import { SignatureHelp, SignatureInformation, SignatureHelpProviderRegistry } from 'vs/editor/common/modes';
|
||||
|
@ -294,7 +293,7 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable {
|
|||
|
||||
this.keyVisible.set(true);
|
||||
this.visible = true;
|
||||
TPromise.timeout(100).done(() => dom.addClass(this.element, 'visible'));
|
||||
setTimeout(() => dom.addClass(this.element, 'visible'), 100);
|
||||
this.editor.layoutContentWidget(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import { LineTokens, IViewLineTokens } from 'vs/editor/common/core/lineTokens';
|
|||
import * as strings from 'vs/base/common/strings';
|
||||
import { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService';
|
||||
import { ViewLineRenderingData } from 'vs/editor/common/viewModel/viewModel';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
export interface IColorizerOptions {
|
||||
tabSize?: number;
|
||||
|
@ -85,7 +86,7 @@ export class Colorizer {
|
|||
}
|
||||
|
||||
// wait 500ms for mode to load, then give up
|
||||
return TPromise.any([this._tokenizationSupportChangedPromise(language), TPromise.timeout(500)]).then(_ => {
|
||||
return TPromise.any([this._tokenizationSupportChangedPromise(language), timeout(500)]).then(_ => {
|
||||
let tokenizationSupport = TokenizationRegistry.get(language);
|
||||
if (tokenizationSupport) {
|
||||
return _colorize(lines, options.tabSize, tokenizationSupport);
|
||||
|
|
|
@ -50,7 +50,7 @@ export class EditorActionCommandEntry extends QuickOpenEntryGroup {
|
|||
if (mode === Mode.OPEN) {
|
||||
|
||||
// Use a timeout to give the quick open widget a chance to close itself first
|
||||
TPromise.timeout(50).done(() => {
|
||||
setTimeout(() => {
|
||||
|
||||
// Some actions are enabled only when editor has focus
|
||||
this.editor.focus();
|
||||
|
@ -61,7 +61,7 @@ export class EditorActionCommandEntry extends QuickOpenEntryGroup {
|
|||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
}
|
||||
}, onUnexpectedError);
|
||||
}, 50);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
75
src/vs/monaco.d.ts
vendored
75
src/vs/monaco.d.ts
vendored
|
@ -72,8 +72,6 @@ declare namespace monaco {
|
|||
public static as<T, SomePromise extends PromiseLike<T>>(value: SomePromise): SomePromise;
|
||||
public static as<T>(value: T): Promise<T>;
|
||||
|
||||
public static is(value: any): value is PromiseLike<any>;
|
||||
|
||||
public static timeout(delay: number): Promise<void>;
|
||||
|
||||
public static join<T1, T2>(promises: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
|
||||
|
@ -102,7 +100,7 @@ declare namespace monaco {
|
|||
}
|
||||
/**
|
||||
* Uniform Resource Identifier (Uri) http://tools.ietf.org/html/rfc3986.
|
||||
* This class is a simple parser which creates the basic component paths
|
||||
* This class is a simple parser which creates the basic component parts
|
||||
* (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation
|
||||
* and encoding.
|
||||
*
|
||||
|
@ -113,8 +111,6 @@ declare namespace monaco {
|
|||
* | _____________________|__
|
||||
* / \ / \
|
||||
* urn:example:animal:ferret:nose
|
||||
*
|
||||
*
|
||||
*/
|
||||
export class Uri implements UriComponents {
|
||||
static isUri(thing: any): thing is Uri;
|
||||
|
@ -142,28 +138,81 @@ declare namespace monaco {
|
|||
readonly fragment: string;
|
||||
/**
|
||||
* Returns a string representing the corresponding file system path of this Uri.
|
||||
* Will handle UNC paths and normalize windows drive letters to lower-case. Also
|
||||
* uses the platform specific path separator. Will *not* validate the path for
|
||||
* invalid characters and semantics. Will *not* look at the scheme of this Uri.
|
||||
* Will handle UNC paths, normalizes windows drive letters to lower-case, and uses the
|
||||
* platform specific path separator.
|
||||
*
|
||||
* * Will *not* validate the path for invalid characters and semantics.
|
||||
* * Will *not* look at the scheme of this Uri.
|
||||
* * The result shall *not* be used for display purposes but for accessing a file on disk.
|
||||
*
|
||||
*
|
||||
* The *difference* to `Uri#path` is the use of the platform specific separator and the handling
|
||||
* of UNC paths. See the below sample of a file-uri with an authority (UNC path).
|
||||
*
|
||||
* ```ts
|
||||
const u = Uri.parse('file://server/c$/folder/file.txt')
|
||||
u.authority === 'server'
|
||||
u.path === '/shares/c$/file.txt'
|
||||
u.fsPath === '\\server\c$\folder\file.txt'
|
||||
```
|
||||
*
|
||||
* Using `Uri#path` to read a file (using fs-apis) would not be enough because parts of the path,
|
||||
* namely the server name, would be missing. Therefore `Uri#fsPath` exists - it's sugar to ease working
|
||||
* with URIs that represent files on disk (`file` scheme).
|
||||
*/
|
||||
readonly fsPath: string;
|
||||
with(change: {
|
||||
scheme?: string;
|
||||
authority?: string;
|
||||
path?: string;
|
||||
query?: string;
|
||||
fragment?: string;
|
||||
authority?: string | null;
|
||||
path?: string | null;
|
||||
query?: string | null;
|
||||
fragment?: string | null;
|
||||
}): Uri;
|
||||
/**
|
||||
* Creates a new Uri from a string, e.g. `http://www.msft.com/some/path`,
|
||||
* `file:///usr/home`, or `scheme:with/path`.
|
||||
*
|
||||
* @param value A string which represents an Uri (see `Uri#toString`).
|
||||
*/
|
||||
static parse(value: string): Uri;
|
||||
/**
|
||||
* Creates a new Uri from a file system path, e.g. `c:\my\files`,
|
||||
* `/usr/home`, or `\\server\share\some\path`.
|
||||
*
|
||||
* The *difference* between `Uri#parse` and `Uri#file` is that the latter treats the argument
|
||||
* as path, not as stringified-uri. E.g. `Uri.file(path)` is **not the same as**
|
||||
* `Uri.parse('file://' + path)` because the path might contain characters that are
|
||||
* interpreted (# and ?). See the following sample:
|
||||
* ```ts
|
||||
const good = Uri.file('/coding/c#/project1');
|
||||
good.scheme === 'file';
|
||||
good.path === '/coding/c#/project1';
|
||||
good.fragment === '';
|
||||
|
||||
const bad = Uri.parse('file://' + '/coding/c#/project1');
|
||||
bad.scheme === 'file';
|
||||
bad.path === '/coding/c'; // path is now broken
|
||||
bad.fragment === '/project1';
|
||||
```
|
||||
*
|
||||
* @param path A file system path (see `Uri#fsPath`)
|
||||
*/
|
||||
static file(path: string): Uri;
|
||||
static from(components: {
|
||||
scheme?: string;
|
||||
scheme: string;
|
||||
authority?: string;
|
||||
path?: string;
|
||||
query?: string;
|
||||
fragment?: string;
|
||||
}): Uri;
|
||||
/**
|
||||
* Creates a string presentation for this Uri. It's guardeed that calling
|
||||
* `Uri.parse` with the result of this function creates an Uri which is equal
|
||||
* to this Uri.
|
||||
*
|
||||
* * The result shall *not* be used for display purposes but for externalization or transport.
|
||||
* * The result will be encoded using the percentage encoding and encoding happens mostly
|
||||
* ignore the scheme-specific encoding rules.
|
||||
*
|
||||
* @param skipEncoding Do not encode the result, default is `false`
|
||||
*/
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { isThenable } from 'vs/base/common/async';
|
||||
|
||||
export const ILifecycleService = createDecorator<ILifecycleService>('lifecycleService');
|
||||
|
||||
|
@ -23,7 +24,7 @@ export interface ShutdownEvent {
|
|||
/**
|
||||
* Allows to veto the shutdown. The veto can be a long running operation.
|
||||
*/
|
||||
veto(value: boolean | TPromise<boolean>): void;
|
||||
veto(value: boolean | Thenable<boolean>): void;
|
||||
|
||||
/**
|
||||
* The reason why Code is shutting down.
|
||||
|
@ -108,12 +109,12 @@ export const NullLifecycleService: ILifecycleService = {
|
|||
};
|
||||
|
||||
// Shared veto handling across main and renderer
|
||||
export function handleVetos(vetos: (boolean | TPromise<boolean>)[], onError: (error: Error) => void): TPromise<boolean /* veto */> {
|
||||
export function handleVetos(vetos: (boolean | Thenable<boolean>)[], onError: (error: Error) => void): TPromise<boolean /* veto */> {
|
||||
if (vetos.length === 0) {
|
||||
return TPromise.as(false);
|
||||
}
|
||||
|
||||
const promises: TPromise<void>[] = [];
|
||||
const promises: Thenable<void>[] = [];
|
||||
let lazyValue = false;
|
||||
|
||||
for (let valueOrPromise of vetos) {
|
||||
|
@ -123,7 +124,7 @@ export function handleVetos(vetos: (boolean | TPromise<boolean>)[], onError: (er
|
|||
return TPromise.as(true);
|
||||
}
|
||||
|
||||
if (TPromise.is(valueOrPromise)) {
|
||||
if (isThenable(valueOrPromise)) {
|
||||
promises.push(valueOrPromise.then(value => {
|
||||
if (value) {
|
||||
lazyValue = true; // veto, done
|
||||
|
|
|
@ -83,7 +83,7 @@ export class LifecycleService implements ILifecycleService {
|
|||
}
|
||||
|
||||
private onBeforeUnload(reason: ShutdownReason): TPromise<boolean> {
|
||||
const vetos: (boolean | TPromise<boolean>)[] = [];
|
||||
const vetos: (boolean | Thenable<boolean>)[] = [];
|
||||
|
||||
this._onWillShutdown.fire({
|
||||
veto(value) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import URI from 'vs/base/common/uri';
|
|||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export interface IQuickPickItem {
|
||||
type?: 'item';
|
||||
id?: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
|
@ -21,6 +22,17 @@ export interface IQuickPickItem {
|
|||
picked?: boolean;
|
||||
}
|
||||
|
||||
export interface IQuickPickSeparator {
|
||||
type: 'separator';
|
||||
border?: boolean;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export interface IKeyMods {
|
||||
readonly ctrlCmd: boolean;
|
||||
readonly alt: boolean;
|
||||
}
|
||||
|
||||
export interface IQuickNavigateConfiguration {
|
||||
keybindings: ResolvedKeybinding[];
|
||||
}
|
||||
|
@ -67,6 +79,7 @@ export interface IPickOptions<T extends IQuickPickItem> {
|
|||
*/
|
||||
activeItem?: TPromise<T> | T;
|
||||
|
||||
onKeyMods?: (keyMods: IKeyMods) => void;
|
||||
onDidFocus?: (entry: T) => void;
|
||||
onDidTriggerItemButton?: (context: IQuickPickItemButtonContext<T>) => void;
|
||||
}
|
||||
|
@ -147,7 +160,7 @@ export interface IQuickPick<T extends IQuickPickItem> extends IQuickInput {
|
|||
|
||||
readonly onDidTriggerItemButton: Event<IQuickPickItemButtonEvent<T>>;
|
||||
|
||||
items: ReadonlyArray<T>;
|
||||
items: ReadonlyArray<T | IQuickPickSeparator>;
|
||||
|
||||
canSelectMany: boolean;
|
||||
|
||||
|
@ -164,6 +177,8 @@ export interface IQuickPick<T extends IQuickPickItem> extends IQuickInput {
|
|||
selectedItems: ReadonlyArray<T>;
|
||||
|
||||
readonly onDidChangeSelection: Event<T[]>;
|
||||
|
||||
readonly keyMods: IKeyMods;
|
||||
}
|
||||
|
||||
export interface IInputBox extends IQuickInput {
|
||||
|
@ -208,6 +223,8 @@ export const IQuickInputService = createDecorator<IQuickInputService>('quickInpu
|
|||
|
||||
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
|
||||
export type QuickPickInput<T = IQuickPickItem> = T | IQuickPickSeparator;
|
||||
|
||||
export interface IQuickInputService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
@ -215,9 +232,9 @@ export interface IQuickInputService {
|
|||
/**
|
||||
* Opens the quick input box for selecting items and returns a promise with the user selected item(s) if any.
|
||||
*/
|
||||
pick<T extends IQuickPickItem>(picks: TPromise<T[]> | T[], options?: IPickOptions<T> & { canPickMany: true }, token?: CancellationToken): TPromise<T[]>;
|
||||
pick<T extends IQuickPickItem>(picks: TPromise<T[]> | T[], options?: IPickOptions<T> & { canPickMany: false }, token?: CancellationToken): TPromise<T>;
|
||||
pick<T extends IQuickPickItem>(picks: TPromise<T[]> | T[], options?: Omit<IPickOptions<T>, 'canPickMany'>, token?: CancellationToken): TPromise<T>;
|
||||
pick<T extends IQuickPickItem>(picks: TPromise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: IPickOptions<T> & { canPickMany: true }, token?: CancellationToken): TPromise<T[]>;
|
||||
pick<T extends IQuickPickItem>(picks: TPromise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: IPickOptions<T> & { canPickMany: false }, token?: CancellationToken): TPromise<T>;
|
||||
pick<T extends IQuickPickItem>(picks: TPromise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: Omit<IPickOptions<T>, 'canPickMany'>, token?: CancellationToken): TPromise<T>;
|
||||
|
||||
/**
|
||||
* Opens the quick input box for text input and returns a promise with the user typed value if any.
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
'use strict';
|
||||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { isMalformedFileUri } from 'vs/base/common/resources';
|
||||
import * as vscode from 'vscode';
|
||||
import * as typeConverters from 'vs/workbench/api/node/extHostTypeConverters';
|
||||
import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands';
|
||||
|
@ -48,9 +49,11 @@ export class OpenFolderAPICommand {
|
|||
if (!uri) {
|
||||
return executor.executeCommand('_files.pickFolderAndOpen', forceNewWindow);
|
||||
}
|
||||
if (!uri.scheme) {
|
||||
console.warn(`'vscode.openFolder' command invoked with an invalid URI (scheme missing): '${uri}'. Converted to a 'file://' URI.`);
|
||||
uri = URI.file(uri.toString());
|
||||
let correctedUri = isMalformedFileUri(uri);
|
||||
if (correctedUri) {
|
||||
// workaround for #55916 and #55891, will be removed in 1.28
|
||||
console.warn(`'vscode.openFolder' command invoked with an invalid URI (file:// scheme missing): '${uri}'. Converted to a 'file://' URI: ${correctedUri}`);
|
||||
uri = correctedUri;
|
||||
}
|
||||
|
||||
return executor.executeCommand('_files.windowOpen', [uri], forceNewWindow);
|
||||
|
|
|
@ -21,7 +21,7 @@ import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colo
|
|||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { ActivityAction, ActivityActionItem, ICompositeBarColors, ToggleCompositePinnedAction, ICompositeBar } from 'vs/workbench/browser/parts/compositebar/compositeBarActions';
|
||||
import { ActivityAction, ActivityActionItem, ICompositeBarColors, ToggleCompositePinnedAction, ICompositeBar } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/
|
|||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { CompositeBar } from 'vs/workbench/browser/parts/compositebar/compositeBar';
|
||||
import { CompositeBar } from 'vs/workbench/browser/parts/compositeBar';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { scheduleAtNextAnimationFrame, Dimension, addClass } from 'vs/base/browser/dom';
|
||||
|
@ -30,7 +30,7 @@ import { Color } from 'vs/base/common/color';
|
|||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions';
|
||||
import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
|
||||
|
||||
interface IPlaceholderComposite {
|
||||
|
|
|
@ -14,7 +14,7 @@ import { IBadge } from 'vs/workbench/services/activity/common/activity';
|
|||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ActionBar, ActionsOrientation, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem, ActivityAction, ICompositeBar, ICompositeBarColors } from 'vs/workbench/browser/parts/compositebar/compositeBarActions';
|
||||
import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem, ActivityAction, ICompositeBar, ICompositeBarColors } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Dimension, $, addDisposableListener, EventType, EventHelper } from 'vs/base/browser/dom';
|
||||
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
|
|
@ -671,3 +671,177 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
|
|||
},
|
||||
order: 9
|
||||
});
|
||||
|
||||
// Main Menu Bar Contributions:
|
||||
|
||||
// Forward/Back
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '1_fwd_back',
|
||||
command: {
|
||||
id: 'workbench.action.navigateBack',
|
||||
title: nls.localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back"),
|
||||
precondition: ContextKeyExpr.has('canNavigateBack')
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '1_fwd_back',
|
||||
command: {
|
||||
id: 'workbench.action.navigateForward',
|
||||
title: nls.localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward"),
|
||||
precondition: ContextKeyExpr.has('canNavigateForward')
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
// Switch Editor
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
|
||||
group: '1_any',
|
||||
command: {
|
||||
id: 'workbench.action.nextEditor',
|
||||
title: nls.localize({ key: 'miNextEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Editor")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
|
||||
group: '1_any',
|
||||
command: {
|
||||
id: 'workbench.action.previousEditor',
|
||||
title: nls.localize({ key: 'miPreviousEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
|
||||
group: '2_used',
|
||||
command: {
|
||||
id: 'workbench.action.openNextRecentlyUsedEditorInGroup',
|
||||
title: nls.localize({ key: 'miNextEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor in Group")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
|
||||
group: '2_used',
|
||||
command: {
|
||||
id: 'workbench.action.openPreviousRecentlyUsedEditorInGroup',
|
||||
title: nls.localize({ key: 'miPreviousEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor in Group")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '2_switch',
|
||||
title: nls.localize({ key: 'miSwitchEditor', comment: ['&& denotes a mnemonic'] }, "Switch &&Editor"),
|
||||
submenu: MenuId.MenubarSwitchEditorMenu,
|
||||
order: 1
|
||||
});
|
||||
|
||||
// Switch Group
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '1_focus_index',
|
||||
command: {
|
||||
id: 'workbench.action.focusFirstEditorGroup',
|
||||
title: nls.localize({ key: 'miFocusFirstGroup', comment: ['&& denotes a mnemonic'] }, "Group &&1")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '1_focus_index',
|
||||
command: {
|
||||
id: 'workbench.action.focusSecondEditorGroup',
|
||||
title: nls.localize({ key: 'miFocusSecondGroup', comment: ['&& denotes a mnemonic'] }, "Group &&2")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '1_focus_index',
|
||||
command: {
|
||||
id: 'workbench.action.focusThirdEditorGroup',
|
||||
title: nls.localize({ key: 'miFocusThirdGroup', comment: ['&& denotes a mnemonic'] }, "Group &&3")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '1_focus_index',
|
||||
command: {
|
||||
id: 'workbench.action.focusFourthEditorGroup',
|
||||
title: nls.localize({ key: 'miFocusFourthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&4")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '1_focus_index',
|
||||
command: {
|
||||
id: 'workbench.action.focusFifthEditorGroup',
|
||||
title: nls.localize({ key: 'miFocusFifthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&5")
|
||||
},
|
||||
order: 5
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '2_next_prev',
|
||||
command: {
|
||||
id: 'workbench.action.focusNextGroup',
|
||||
title: nls.localize({ key: 'miNextGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Group")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '2_next_prev',
|
||||
command: {
|
||||
id: 'workbench.action.focusPreviousGroup',
|
||||
title: nls.localize({ key: 'miPreviousGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Group")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '3_directional',
|
||||
command: {
|
||||
id: 'workbench.action.focusLeftGroup',
|
||||
title: nls.localize({ key: 'miFocusLeftGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Left")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '3_directional',
|
||||
command: {
|
||||
id: 'workbench.action.focusRightGroup',
|
||||
title: nls.localize({ key: 'miFocusRightGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Right")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '3_directional',
|
||||
command: {
|
||||
id: 'workbench.action.focusAboveGroup',
|
||||
title: nls.localize({ key: 'miFocusAboveGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Above")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '3_directional',
|
||||
command: {
|
||||
id: 'workbench.action.focusBelowGroup',
|
||||
title: nls.localize({ key: 'miFocusBelowGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Below")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '2_switch',
|
||||
title: nls.localize({ key: 'miSwitchGroup', comment: ['&& denotes a mnemonic'] }, "Switch &&Group"),
|
||||
submenu: MenuId.MenubarSwitchGroupMenu,
|
||||
order: 2
|
||||
});
|
|
@ -31,7 +31,7 @@ import { IndentUsingSpaces, IndentUsingTabs, DetectIndentation, IndentationToSpa
|
|||
import { BaseBinaryResourceEditor } from 'vs/workbench/browser/parts/editor/binaryEditor';
|
||||
import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IQuickOpenService, IPickOpenEntry, IFilePickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { SUPPORTED_ENCODINGS, IFileService, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
@ -58,7 +58,8 @@ import { Schemas } from 'vs/base/common/network';
|
|||
import { IAnchor } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { Themable } from 'vs/workbench/common/theme';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { getIconClasses } from 'vs/workbench/browser/labels';
|
||||
|
||||
class SideBySideEditorEncodingSupport implements IEncodingSupport {
|
||||
constructor(private master: IEncodingSupport, private details: IEncodingSupport) { }
|
||||
|
@ -834,7 +835,6 @@ export class ChangeModeAction extends Action {
|
|||
@IModelService private modelService: IModelService,
|
||||
@IEditorService private editorService: IEditorService,
|
||||
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService,
|
||||
@IQuickInputService private quickInputService: IQuickInputService,
|
||||
@IPreferencesService private preferencesService: IPreferencesService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
|
@ -867,7 +867,7 @@ export class ChangeModeAction extends Action {
|
|||
|
||||
// All languages are valid picks
|
||||
const languages = this.modeService.getRegisteredLanguageNames();
|
||||
const picks: IPickOpenEntry[] = languages.sort().map((lang, index) => {
|
||||
const picks: QuickPickInput[] = languages.sort().map((lang, index) => {
|
||||
let description: string;
|
||||
if (currentModeId === lang) {
|
||||
description = nls.localize('languageDescription', "({0}) - Configured Language", this.modeService.getModeIdForLanguageName(lang.toLowerCase()));
|
||||
|
@ -887,20 +887,20 @@ export class ChangeModeAction extends Action {
|
|||
}
|
||||
}
|
||||
|
||||
return <IFilePickOpenEntry>{
|
||||
return <IQuickPickItem>{
|
||||
label: lang,
|
||||
resource: fakeResource,
|
||||
iconClasses: getIconClasses(this.modelService, this.modeService, fakeResource),
|
||||
description
|
||||
};
|
||||
});
|
||||
|
||||
if (hasLanguageSupport) {
|
||||
picks[0].separator = { border: true, label: nls.localize('languagesPicks', "languages (identifier)") };
|
||||
picks.unshift({ type: 'separator', border: true, label: nls.localize('languagesPicks', "languages (identifier)") });
|
||||
}
|
||||
|
||||
// Offer action to configure via settings
|
||||
let configureModeAssociations: IPickOpenEntry;
|
||||
let configureModeSettings: IPickOpenEntry;
|
||||
let configureModeAssociations: IQuickPickItem;
|
||||
let configureModeSettings: IQuickPickItem;
|
||||
let galleryAction: Action;
|
||||
if (hasLanguageSupport) {
|
||||
const ext = paths.extname(resource.fsPath) || paths.basename(resource.fsPath);
|
||||
|
@ -917,7 +917,7 @@ export class ChangeModeAction extends Action {
|
|||
}
|
||||
|
||||
// Offer to "Auto Detect"
|
||||
const autoDetectMode: IPickOpenEntry = {
|
||||
const autoDetectMode: IQuickPickItem = {
|
||||
label: nls.localize('autoDetect', "Auto Detect")
|
||||
};
|
||||
|
||||
|
@ -925,7 +925,7 @@ export class ChangeModeAction extends Action {
|
|||
picks.unshift(autoDetectMode);
|
||||
}
|
||||
|
||||
return this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickLanguage', "Select Language Mode"), matchOnDescription: true }).then(pick => {
|
||||
return this.quickInputService.pick(picks, { placeHolder: nls.localize('pickLanguage', "Select Language Mode"), matchOnDescription: true }).then(pick => {
|
||||
if (!pick) {
|
||||
return;
|
||||
}
|
||||
|
@ -999,7 +999,7 @@ export class ChangeModeAction extends Action {
|
|||
};
|
||||
});
|
||||
|
||||
TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).done(() => {
|
||||
setTimeout(() => {
|
||||
this.quickInputService.pick(picks, { placeHolder: nls.localize('pickLanguageToConfigure', "Select Language Mode to Associate with '{0}'", extension || basename) }).done(language => {
|
||||
if (language) {
|
||||
const fileAssociationsConfig = this.configurationService.inspect(FILES_ASSOCIATIONS_CONFIG);
|
||||
|
@ -1027,8 +1027,8 @@ export class ChangeModeAction extends Action {
|
|||
|
||||
this.configurationService.updateValue(FILES_ASSOCIATIONS_CONFIG, currentAssociations, target);
|
||||
}
|
||||
});
|
||||
});
|
||||
}, error => errors.onUnexpectedError(error));
|
||||
}, 50 /* quick open is sensitive to being opened so soon after another */);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1045,7 +1045,6 @@ class ChangeIndentationAction extends Action {
|
|||
actionId: string,
|
||||
actionLabel: string,
|
||||
@IEditorService private editorService: IEditorService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService,
|
||||
@IQuickInputService private quickInputService: IQuickInputService
|
||||
) {
|
||||
super(actionId, actionLabel);
|
||||
|
@ -1061,7 +1060,7 @@ class ChangeIndentationAction extends Action {
|
|||
return this.quickInputService.pick([{ label: nls.localize('noWritableCodeEditor', "The active code editor is read-only.") }]);
|
||||
}
|
||||
|
||||
const picks = [
|
||||
const picks: QuickPickInput<IQuickPickItem & { run(): void }>[] = [
|
||||
activeTextEditorWidget.getAction(IndentUsingSpaces.ID),
|
||||
activeTextEditorWidget.getAction(IndentUsingTabs.ID),
|
||||
activeTextEditorWidget.getAction(DetectIndentation.ID),
|
||||
|
@ -1080,10 +1079,10 @@ class ChangeIndentationAction extends Action {
|
|||
};
|
||||
});
|
||||
|
||||
(<IPickOpenEntry>picks[0]).separator = { label: nls.localize('indentView', "change view") };
|
||||
(<IPickOpenEntry>picks[3]).separator = { label: nls.localize('indentConvert', "convert file"), border: true };
|
||||
picks.splice(3, 0, { type: 'separator', label: nls.localize('indentConvert', "convert file"), border: true });
|
||||
picks.unshift({ type: 'separator', label: nls.localize('indentView', "change view") });
|
||||
|
||||
return this.quickOpenService.pick(picks, { placeHolder: nls.localize('pickAction', "Select Action"), matchOnDetail: true }).then(action => action && action.run());
|
||||
return this.quickInputService.pick(picks, { placeHolder: nls.localize('pickAction', "Select Action"), matchOnDetail: true }).then(action => action && action.run());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1141,7 +1140,6 @@ export class ChangeEncodingAction extends Action {
|
|||
actionId: string,
|
||||
actionLabel: string,
|
||||
@IEditorService private editorService: IEditorService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService,
|
||||
@IQuickInputService private quickInputService: IQuickInputService,
|
||||
@ITextResourceConfigurationService private textResourceConfigurationService: ITextResourceConfigurationService,
|
||||
@IFileService private fileService: IFileService
|
||||
|
@ -1204,7 +1202,7 @@ export class ChangeEncodingAction extends Action {
|
|||
let aliasMatchIndex: number;
|
||||
|
||||
// All encodings are valid picks
|
||||
const picks: IPickOpenEntry[] = Object.keys(SUPPORTED_ENCODINGS)
|
||||
const picks: QuickPickInput[] = Object.keys(SUPPORTED_ENCODINGS)
|
||||
.sort((k1, k2) => {
|
||||
if (k1 === configuredEncoding) {
|
||||
return -1;
|
||||
|
@ -1233,13 +1231,14 @@ export class ChangeEncodingAction extends Action {
|
|||
|
||||
// If we have a guessed encoding, show it first unless it matches the configured encoding
|
||||
if (guessedEncoding && configuredEncoding !== guessedEncoding && SUPPORTED_ENCODINGS[guessedEncoding]) {
|
||||
picks[0].separator = { border: true };
|
||||
picks.unshift({ type: 'separator', border: true });
|
||||
picks.unshift({ id: guessedEncoding, label: SUPPORTED_ENCODINGS[guessedEncoding].labelLong, description: nls.localize('guessedEncoding', "Guessed from content") });
|
||||
}
|
||||
|
||||
return this.quickOpenService.pick(picks, {
|
||||
const items = picks.filter(p => p.type !== 'separator') as IQuickPickItem[];
|
||||
return this.quickInputService.pick(picks, {
|
||||
placeHolder: isReopenWithEncoding ? nls.localize('pickEncodingForReopen', "Select File Encoding to Reopen File") : nls.localize('pickEncodingForSave', "Select File Encoding to Save with"),
|
||||
autoFocus: { autoFocusIndex: typeof directMatchIndex === 'number' ? directMatchIndex : typeof aliasMatchIndex === 'number' ? aliasMatchIndex : void 0 }
|
||||
activeItem: items[typeof directMatchIndex === 'number' ? directMatchIndex : typeof aliasMatchIndex === 'number' ? aliasMatchIndex : -1]
|
||||
}).then(encoding => {
|
||||
if (encoding) {
|
||||
activeControl = this.editorService.activeControl;
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
display: flex;
|
||||
flex: initial;
|
||||
opacity: 0.5;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content .editor-group-container.active > .title .title-actions {
|
||||
|
|
|
@ -232,6 +232,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
|
|||
const options: IDiffEditorOptions = super.getConfigurationOverrides();
|
||||
|
||||
options.readOnly = this.isReadOnly();
|
||||
options.lineDecorationsWidth = '2ch';
|
||||
|
||||
return options;
|
||||
}
|
||||
|
|
|
@ -1,50 +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.menubar {
|
||||
display: flex;
|
||||
flex-shrink: 1;
|
||||
box-sizing: border-box;
|
||||
height: 30px;
|
||||
-webkit-app-region: no-drag;
|
||||
overflow: hidden;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.monaco-workbench.fullscreen .part.menubar {
|
||||
margin: 0px;
|
||||
padding: 0px 5px;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button {
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 0px 8px;
|
||||
cursor: default;
|
||||
-webkit-app-region: no-drag;
|
||||
zoom: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.menubar .menubar-menu-items-holder {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
opacity: 1;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.menubar .menubar-menu-items-holder.monaco-menu-container {
|
||||
font-family: "Segoe WPC", "Segoe UI", ".SFNSDisplay-Light", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback";
|
||||
outline: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.menubar .menubar-menu-items-holder.monaco-menu-container :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .part.menubar .menubar-menu-items-holder.monaco-menu-container {
|
||||
border: 2px solid #6FC3DF;
|
||||
}
|
|
@ -1,402 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
|
||||
goMenuRegistration();
|
||||
|
||||
if (isMacintosh) {
|
||||
windowMenuRegistration();
|
||||
}
|
||||
|
||||
helpMenuRegistration();
|
||||
|
||||
// Menu registration
|
||||
function goMenuRegistration() {
|
||||
// Forward/Back
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '1_fwd_back',
|
||||
command: {
|
||||
id: 'workbench.action.navigateBack',
|
||||
title: nls.localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '1_fwd_back',
|
||||
command: {
|
||||
id: 'workbench.action.navigateForward',
|
||||
title: nls.localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
// Switch Editor
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
|
||||
group: '1_any',
|
||||
command: {
|
||||
id: 'workbench.action.nextEditor',
|
||||
title: nls.localize({ key: 'miNextEditor', comment: ['&& denotes a mnemonic'] }, "&&Next Editor")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
|
||||
group: '1_any',
|
||||
command: {
|
||||
id: 'workbench.action.previousEditor',
|
||||
title: nls.localize({ key: 'miPreviousEditor', comment: ['&& denotes a mnemonic'] }, "&&Previous Editor")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
|
||||
group: '2_used',
|
||||
command: {
|
||||
id: 'workbench.action.openNextRecentlyUsedEditorInGroup',
|
||||
title: nls.localize({ key: 'miNextEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Used Editor in Group")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
|
||||
group: '2_used',
|
||||
command: {
|
||||
id: 'workbench.action.openPreviousRecentlyUsedEditorInGroup',
|
||||
title: nls.localize({ key: 'miPreviousEditorInGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Used Editor in Group")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '2_switch',
|
||||
title: nls.localize({ key: 'miSwitchEditor', comment: ['&& denotes a mnemonic'] }, "Switch &&Editor"),
|
||||
submenu: MenuId.MenubarSwitchEditorMenu,
|
||||
order: 1
|
||||
});
|
||||
|
||||
// Switch Group
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '1_focus_index',
|
||||
command: {
|
||||
id: 'workbench.action.focusFirstEditorGroup',
|
||||
title: nls.localize({ key: 'miFocusFirstGroup', comment: ['&& denotes a mnemonic'] }, "Group &&1")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '1_focus_index',
|
||||
command: {
|
||||
id: 'workbench.action.focusSecondEditorGroup',
|
||||
title: nls.localize({ key: 'miFocusSecondGroup', comment: ['&& denotes a mnemonic'] }, "Group &&2")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '1_focus_index',
|
||||
command: {
|
||||
id: 'workbench.action.focusThirdEditorGroup',
|
||||
title: nls.localize({ key: 'miFocusThirdGroup', comment: ['&& denotes a mnemonic'] }, "Group &&3")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '1_focus_index',
|
||||
command: {
|
||||
id: 'workbench.action.focusFourthEditorGroup',
|
||||
title: nls.localize({ key: 'miFocusFourthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&4")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '1_focus_index',
|
||||
command: {
|
||||
id: 'workbench.action.focusFifthEditorGroup',
|
||||
title: nls.localize({ key: 'miFocusFifthGroup', comment: ['&& denotes a mnemonic'] }, "Group &&5")
|
||||
},
|
||||
order: 5
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '2_next_prev',
|
||||
command: {
|
||||
id: 'workbench.action.focusNextGroup',
|
||||
title: nls.localize({ key: 'miNextGroup', comment: ['&& denotes a mnemonic'] }, "&&Next Group")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '2_next_prev',
|
||||
command: {
|
||||
id: 'workbench.action.focusPreviousGroup',
|
||||
title: nls.localize({ key: 'miPreviousGroup', comment: ['&& denotes a mnemonic'] }, "&&Previous Group")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '3_directional',
|
||||
command: {
|
||||
id: 'workbench.action.focusLeftGroup',
|
||||
title: nls.localize({ key: 'miFocusLeftGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Left")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '3_directional',
|
||||
command: {
|
||||
id: 'workbench.action.focusRightGroup',
|
||||
title: nls.localize({ key: 'miFocusRightGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Right")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '3_directional',
|
||||
command: {
|
||||
id: 'workbench.action.focusAboveGroup',
|
||||
title: nls.localize({ key: 'miFocusAboveGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Above")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
|
||||
group: '3_directional',
|
||||
command: {
|
||||
id: 'workbench.action.focusBelowGroup',
|
||||
title: nls.localize({ key: 'miFocusBelowGroup', comment: ['&& denotes a mnemonic'] }, "Group &&Below")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: '2_switch',
|
||||
title: nls.localize({ key: 'miSwitchGroup', comment: ['&& denotes a mnemonic'] }, "Switch &&Group"),
|
||||
submenu: MenuId.MenubarSwitchGroupMenu,
|
||||
order: 2
|
||||
});
|
||||
|
||||
// Go to
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'workbench.action.quickOpen',
|
||||
title: nls.localize({ key: 'miGotoFile', comment: ['&& denotes a mnemonic'] }, "Go to &&File...")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'workbench.action.gotoSymbol',
|
||||
title: nls.localize({ key: 'miGotoSymbolInFile', comment: ['&& denotes a mnemonic'] }, "Go to &&Symbol in File...")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'workbench.action.showAllSymbols',
|
||||
title: nls.localize({ key: 'miGotoSymbolInWorkspace', comment: ['&& denotes a mnemonic'] }, "Go to Symbol in &&Workspace...")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'editor.action.goToDeclaration',
|
||||
title: nls.localize({ key: 'miGotoDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Definition")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'editor.action.goToTypeDefinition',
|
||||
title: nls.localize({ key: 'miGotoTypeDefinition', comment: ['&& denotes a mnemonic'] }, "Go to &&Type Definition")
|
||||
},
|
||||
order: 5
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'editor.action.goToImplementation',
|
||||
title: nls.localize({ key: 'miGotoImplementation', comment: ['&& denotes a mnemonic'] }, "Go to &&Implementation")
|
||||
},
|
||||
order: 6
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'workbench.action.gotoLine',
|
||||
title: nls.localize({ key: 'miGotoLine', comment: ['&& denotes a mnemonic'] }, "Go to &&Line...")
|
||||
},
|
||||
order: 7
|
||||
});
|
||||
}
|
||||
|
||||
function windowMenuRegistration() {
|
||||
|
||||
}
|
||||
|
||||
function helpMenuRegistration() {
|
||||
// Welcome
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '1_welcome',
|
||||
command: {
|
||||
id: 'workbench.action.showWelcomePage',
|
||||
title: nls.localize({ key: 'miWelcome', comment: ['&& denotes a mnemonic'] }, "&&Welcome")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '1_welcome',
|
||||
command: {
|
||||
id: 'workbench.action.showInteractivePlayground',
|
||||
title: nls.localize({ key: 'miInteractivePlayground', comment: ['&& denotes a mnemonic'] }, "&&Interactive Playground")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '1_welcome',
|
||||
command: {
|
||||
id: 'workbench.action.openDocumentationUrl',
|
||||
title: nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '1_welcome',
|
||||
command: {
|
||||
id: 'update.showCurrentReleaseNotes',
|
||||
title: nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
// Reference
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '2_reference',
|
||||
command: {
|
||||
id: 'workbench.action.keybindingsReference',
|
||||
title: nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '2_reference',
|
||||
command: {
|
||||
id: 'workbench.action.openIntroductoryVideosUrl',
|
||||
title: nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '2_reference',
|
||||
command: {
|
||||
id: 'workbench.action.openTipsAndTricksUrl',
|
||||
title: nls.localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "&&Tips and Tricks")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
// Feedback
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '3_feedback',
|
||||
command: {
|
||||
id: 'workbench.action.openTwitterUrl',
|
||||
title: nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join us on Twitter")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '3_feedback',
|
||||
command: {
|
||||
id: 'workbench.action.openRequestFeatureUrl',
|
||||
title: nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '3_feedback',
|
||||
command: {
|
||||
id: 'workbench.action.openIssueReporter',
|
||||
title: nls.localize({ key: 'miReportIssue', comment: ['&& denotes a mnemonic', 'Translate this to "Report Issue in English" in all languages please!'] }, "Report &&Issue")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
// Legal
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '4_legal',
|
||||
command: {
|
||||
id: 'workbench.action.openLicenseUrl',
|
||||
title: nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '4_legal',
|
||||
command: {
|
||||
id: 'workbench.action.openPrivacyStatementUrl',
|
||||
title: nls.localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "&&Privacy Statement")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
// Tools
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '5_tools',
|
||||
command: {
|
||||
id: 'workbench.action.toggleDevTools',
|
||||
title: nls.localize({ key: 'miToggleDevTools', comment: ['&& denotes a mnemonic'] }, "&&Toggle Developer Tools")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '5_tools',
|
||||
command: {
|
||||
id: 'workbench.action.openProcessExplorer',
|
||||
title: nls.localize({ key: 'miOpenProcessExplorerer', comment: ['&& denotes a mnemonic'] }, "Open &&Process Explorer")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
if (!isMacintosh) {
|
||||
// About
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: 'z_about',
|
||||
command: {
|
||||
id: 'workbench.action.showAboutDialog',
|
||||
title: nls.localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/
|
|||
import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/actions';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IPartService, Parts, Position } from 'vs/workbench/services/part/common/partService';
|
||||
import { ActivityAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions';
|
||||
import { ActivityAction } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
import { IActivity } from 'vs/workbench/common/activity';
|
||||
|
||||
export class ClosePanelAction extends Action {
|
||||
|
|
|
@ -23,8 +23,8 @@ import { ClosePanelAction, TogglePanelPositionAction, PanelActivityAction, Toggl
|
|||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { activeContrastBorder, focusBorder, contrastBorder, editorBackground, badgeBackground, badgeForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { CompositeBar } from 'vs/workbench/browser/parts/compositebar/compositeBar';
|
||||
import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositebar/compositeBarActions';
|
||||
import { CompositeBar } from 'vs/workbench/browser/parts/compositeBar';
|
||||
import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
import { IBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { Dimension } from 'vs/base/browser/dom';
|
||||
|
|
|
@ -170,6 +170,21 @@
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-separator {
|
||||
margin-right: 18px;
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry.has-actions:hover .quick-input-list-separator,
|
||||
.quick-input-list .monaco-list-row.focused .quick-input-list-entry.has-actions .quick-input-list-separator {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-separator-border {
|
||||
border-top-width: 1px;
|
||||
border-top-style: solid;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry-action-bar {
|
||||
display: none;
|
||||
flex: 0;
|
||||
|
@ -184,8 +199,16 @@
|
|||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry-action-bar {
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry-action-bar ul:first-child .action-label.icon {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry-action-bar ul:last-child .action-label.icon {
|
||||
margin-right: 3px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.quick-input-list .quick-input-list-entry:hover .quick-input-list-entry-action-bar,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import 'vs/css!./quickInput';
|
||||
import { Component } from 'vs/workbench/common/component';
|
||||
import { IQuickInputService, IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IInputBox, IQuickPickItemButtonEvent } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IQuickInputService, IQuickPickItem, IPickOptions, IInputOptions, IQuickNavigateConfiguration, IQuickPick, IQuickInput, IQuickInputButton, IInputBox, IQuickPickItemButtonEvent, QuickPickInput, IQuickPickSeparator, IKeyMods } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
@ -46,6 +46,8 @@ import { getIconClass } from 'vs/workbench/browser/parts/quickinput/quickInputUt
|
|||
|
||||
const $ = dom.$;
|
||||
|
||||
type Writeable<T> = { -readonly [P in keyof T]: T[P] };
|
||||
|
||||
const backButton = {
|
||||
iconPath: {
|
||||
dark: URI.parse(require.toUrl('vs/workbench/browser/parts/quickinput/media/dark/arrow-left.svg')),
|
||||
|
@ -70,6 +72,7 @@ interface QuickInputUI {
|
|||
onDidAccept: Event<void>;
|
||||
onDidTriggerButton: Event<IQuickInputButton>;
|
||||
ignoreFocusOut: boolean;
|
||||
keyMods: Writeable<IKeyMods>;
|
||||
show(controller: QuickInput): void;
|
||||
setVisibilities(visibilities: Visibilities): void;
|
||||
setEnabled(enabled: boolean): void;
|
||||
|
@ -298,7 +301,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
|||
private _placeholder;
|
||||
private onDidChangeValueEmitter = new Emitter<string>();
|
||||
private onDidAcceptEmitter = new Emitter<string>();
|
||||
private _items: T[] = [];
|
||||
private _items: (T | IQuickPickSeparator)[] = [];
|
||||
private itemsUpdated = false;
|
||||
private _canSelectMany = false;
|
||||
private _matchOnDescription = false;
|
||||
|
@ -352,7 +355,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
|||
return this._items;
|
||||
}
|
||||
|
||||
set items(items: T[]) {
|
||||
set items(items: (T | IQuickPickSeparator)[]) {
|
||||
this._items = items;
|
||||
this.itemsUpdated = true;
|
||||
this.update();
|
||||
|
@ -407,6 +410,10 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
|
|||
this.update();
|
||||
}
|
||||
|
||||
get keyMods() {
|
||||
return this.ui.keyMods;
|
||||
}
|
||||
|
||||
onDidChangeSelection = this.onDidChangeSelectionEmitter.event;
|
||||
|
||||
onDidTriggerItemButton = this.onDidTriggerItemButtonEmitter.event;
|
||||
|
@ -950,6 +957,30 @@ export class QuickInputService extends Component implements IQuickInputService {
|
|||
break;
|
||||
}
|
||||
}));
|
||||
this._register(dom.addDisposableListener(container, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
switch (event.keyCode) {
|
||||
case KeyCode.Ctrl:
|
||||
case KeyCode.Meta:
|
||||
this.ui.keyMods.ctrlCmd = true;
|
||||
break;
|
||||
case KeyCode.Alt:
|
||||
this.ui.keyMods.alt = true;
|
||||
break;
|
||||
}
|
||||
}));
|
||||
this._register(dom.addDisposableListener(container, dom.EventType.KEY_UP, (e: KeyboardEvent) => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
switch (event.keyCode) {
|
||||
case KeyCode.Ctrl:
|
||||
case KeyCode.Meta:
|
||||
this.ui.keyMods.ctrlCmd = false;
|
||||
break;
|
||||
case KeyCode.Alt:
|
||||
this.ui.keyMods.alt = false;
|
||||
break;
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this.quickOpenService.onShow(() => this.hide(true)));
|
||||
|
||||
|
@ -968,6 +999,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
|||
onDidAccept: this.onDidAcceptEmitter.event,
|
||||
onDidTriggerButton: this.onDidTriggerButtonEmitter.event,
|
||||
ignoreFocusOut: false,
|
||||
keyMods: { ctrlCmd: false, alt: false },
|
||||
show: controller => this.show(controller),
|
||||
hide: () => this.hide(),
|
||||
setVisibilities: visibilities => this.setVisibilities(visibilities),
|
||||
|
@ -977,8 +1009,15 @@ export class QuickInputService extends Component implements IQuickInputService {
|
|||
this.updateStyles();
|
||||
}
|
||||
|
||||
pick<T extends IQuickPickItem, O extends IPickOptions<T>>(picks: TPromise<T[]> | T[], options: O = <O>{}, token: CancellationToken = CancellationToken.None): TPromise<O extends { canPickMany: true } ? T[] : T> {
|
||||
return new TPromise<O extends { canPickMany: true } ? T[] : T>((resolve, reject) => {
|
||||
pick<T extends IQuickPickItem, O extends IPickOptions<T>>(picks: TPromise<QuickPickInput<T>[]> | QuickPickInput<T>[], options: O = <O>{}, token: CancellationToken = CancellationToken.None): TPromise<O extends { canPickMany: true } ? T[] : T> {
|
||||
return new TPromise<O extends { canPickMany: true } ? T[] : T>((doResolve, reject) => {
|
||||
let resolve = (result: any) => {
|
||||
resolve = doResolve;
|
||||
if (options.onKeyMods) {
|
||||
options.onKeyMods(input.keyMods);
|
||||
}
|
||||
doResolve(result);
|
||||
};
|
||||
if (token.isCancellationRequested) {
|
||||
resolve(undefined);
|
||||
return;
|
||||
|
@ -1045,7 +1084,7 @@ export class QuickInputService extends Component implements IQuickInputService {
|
|||
input.busy = false;
|
||||
input.items = items;
|
||||
if (input.canSelectMany) {
|
||||
input.selectedItems = items.filter(item => item.picked);
|
||||
input.selectedItems = items.filter(item => item.type !== 'separator' && item.picked) as T[];
|
||||
}
|
||||
if (activeItem) {
|
||||
input.activeItems = [activeItem];
|
||||
|
@ -1154,6 +1193,8 @@ export class QuickInputService extends Component implements IQuickInputService {
|
|||
this.ui.list.matchOnDescription = false;
|
||||
this.ui.list.matchOnDetail = false;
|
||||
this.ui.ignoreFocusOut = false;
|
||||
this.ui.keyMods.ctrlCmd = false;
|
||||
this.ui.keyMods.alt = false;
|
||||
|
||||
const keybinding = this.keybindingService.lookupKeybinding(BackAction.ID);
|
||||
backButton.tooltip = keybinding ? localize('quickInput.backWithKeybinding', "Back ({0})", keybinding.getLabel()) : localize('quickInput.back', "Back");
|
||||
|
|
|
@ -11,7 +11,7 @@ import * as dom from 'vs/base/browser/dom';
|
|||
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { WorkbenchList } from 'vs/platform/list/browser/listService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IQuickPickItem, IQuickPickItemButtonEvent } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IMatch } from 'vs/base/common/filters';
|
||||
import { matchesFuzzyOcticonAware, parseOcticons } from 'vs/base/common/octicon';
|
||||
import { compareAnything } from 'vs/base/common/comparers';
|
||||
|
@ -24,7 +24,7 @@ import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlighte
|
|||
import { memoize } from 'vs/base/common/decorators';
|
||||
import { range } from 'vs/base/common/arrays';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { listFocusBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { listFocusBackground, pickerGroupBorder, pickerGroupForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
|
@ -36,6 +36,7 @@ interface IListElement {
|
|||
index: number;
|
||||
item: IQuickPickItem;
|
||||
checked: boolean;
|
||||
separator: IQuickPickSeparator;
|
||||
fireButtonTriggered: (event: IQuickPickItemButtonEvent<IQuickPickItem>) => void;
|
||||
}
|
||||
|
||||
|
@ -56,6 +57,7 @@ class ListElement implements IListElement {
|
|||
this._onChecked.fire(value);
|
||||
}
|
||||
}
|
||||
separator: IQuickPickSeparator;
|
||||
labelHighlights?: IMatch[];
|
||||
descriptionHighlights?: IMatch[];
|
||||
detailHighlights?: IMatch[];
|
||||
|
@ -67,9 +69,11 @@ class ListElement implements IListElement {
|
|||
}
|
||||
|
||||
interface IListElementTemplateData {
|
||||
entry: HTMLDivElement;
|
||||
checkbox: HTMLInputElement;
|
||||
label: IconLabel;
|
||||
detail: HighlightedLabel;
|
||||
separator: HTMLDivElement;
|
||||
actionBar: ActionBar;
|
||||
element: ListElement;
|
||||
toDisposeElement: IDisposable[];
|
||||
|
@ -89,10 +93,10 @@ class ListElementRenderer implements IRenderer<ListElement, IListElementTemplate
|
|||
data.toDisposeElement = [];
|
||||
data.toDisposeTemplate = [];
|
||||
|
||||
const entry = dom.append(container, $('.quick-input-list-entry'));
|
||||
data.entry = dom.append(container, $('.quick-input-list-entry'));
|
||||
|
||||
// Checkbox
|
||||
const label = dom.append(entry, $('label.quick-input-list-label'));
|
||||
const label = dom.append(data.entry, $('label.quick-input-list-label'));
|
||||
data.checkbox = <HTMLInputElement>dom.append(label, $('input.quick-input-list-checkbox'));
|
||||
data.checkbox.type = 'checkbox';
|
||||
data.toDisposeTemplate.push(dom.addStandardDisposableListener(data.checkbox, dom.EventType.CHANGE, e => {
|
||||
|
@ -111,8 +115,11 @@ class ListElementRenderer implements IRenderer<ListElement, IListElementTemplate
|
|||
const detailContainer = dom.append(row2, $('.quick-input-list-label-meta'));
|
||||
data.detail = new HighlightedLabel(detailContainer);
|
||||
|
||||
// Separator
|
||||
data.separator = dom.append(data.entry, $('.quick-input-list-separator'));
|
||||
|
||||
// Actions
|
||||
data.actionBar = new ActionBar(entry);
|
||||
data.actionBar = new ActionBar(data.entry);
|
||||
data.actionBar.domNode.classList.add('quick-input-list-entry-action-bar');
|
||||
data.toDisposeTemplate.push(data.actionBar);
|
||||
|
||||
|
@ -138,10 +145,24 @@ class ListElementRenderer implements IRenderer<ListElement, IListElementTemplate
|
|||
// Meta
|
||||
data.detail.set(element.item.detail, detailHighlights);
|
||||
|
||||
// Separator
|
||||
if (element.separator && element.separator.label) {
|
||||
data.separator.textContent = element.separator.label;
|
||||
data.separator.style.display = null;
|
||||
} else {
|
||||
data.separator.style.display = 'none';
|
||||
}
|
||||
if (element.separator && element.separator.border) {
|
||||
dom.addClass(data.entry, 'quick-input-list-separator-border');
|
||||
} else {
|
||||
dom.removeClass(data.entry, 'quick-input-list-separator-border');
|
||||
}
|
||||
|
||||
// Actions
|
||||
data.actionBar.clear();
|
||||
if (element.item.buttons) {
|
||||
data.actionBar.push(element.item.buttons.map((button, index) => {
|
||||
const buttons = element.item.buttons;
|
||||
if (buttons && buttons.length) {
|
||||
data.actionBar.push(buttons.map((button, index) => {
|
||||
const action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath), true, () => {
|
||||
element.fireButtonTriggered({
|
||||
button,
|
||||
|
@ -152,6 +173,9 @@ class ListElementRenderer implements IRenderer<ListElement, IListElementTemplate
|
|||
action.tooltip = button.tooltip;
|
||||
return action;
|
||||
}), { icon: true, label: false });
|
||||
dom.addClass(data.entry, 'has-actions');
|
||||
} else {
|
||||
dom.removeClass(data.entry, 'has-actions');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +204,7 @@ export class QuickInputList {
|
|||
|
||||
private container: HTMLElement;
|
||||
private list: WorkbenchList<ListElement>;
|
||||
private inputElements: (IQuickPickItem | IQuickPickSeparator)[];
|
||||
private elements: ListElement[] = [];
|
||||
private elementsToIndexes = new Map<IQuickPickItem, number>();
|
||||
matchOnDescription = false;
|
||||
|
@ -314,15 +339,23 @@ export class QuickInputList {
|
|||
}
|
||||
}
|
||||
|
||||
setElements(elements: IQuickPickItem[]): void {
|
||||
setElements(inputElements: (IQuickPickItem | IQuickPickSeparator)[]): void {
|
||||
this.elementDisposables = dispose(this.elementDisposables);
|
||||
const fireButtonTriggered = (event: IQuickPickItemButtonEvent<IQuickPickItem>) => this.fireButtonTriggered(event);
|
||||
this.elements = elements.map((item, index) => new ListElement({
|
||||
index,
|
||||
item,
|
||||
checked: false,
|
||||
fireButtonTriggered
|
||||
}));
|
||||
this.inputElements = inputElements;
|
||||
this.elements = inputElements.reduce((result, item, index) => {
|
||||
if (item.type !== 'separator') {
|
||||
const previous = index && inputElements[index - 1];
|
||||
result.push(new ListElement({
|
||||
index,
|
||||
item,
|
||||
checked: false,
|
||||
separator: previous && previous.type === 'separator' ? previous : undefined,
|
||||
fireButtonTriggered
|
||||
}));
|
||||
}
|
||||
return result;
|
||||
}, [] as ListElement[]);
|
||||
this.elementDisposables.push(...this.elements.map(element => element.onChecked(() => this.fireCheckedEvents())));
|
||||
|
||||
this.elementsToIndexes = this.elements.reduce((map, element, index) => {
|
||||
|
@ -419,6 +452,8 @@ export class QuickInputList {
|
|||
element.descriptionHighlights = undefined;
|
||||
element.detailHighlights = undefined;
|
||||
element.hidden = false;
|
||||
const previous = element.index && this.inputElements[element.index - 1];
|
||||
element.separator = previous && previous.type === 'separator' ? previous : undefined;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -440,19 +475,19 @@ export class QuickInputList {
|
|||
element.detailHighlights = undefined;
|
||||
element.hidden = true;
|
||||
}
|
||||
element.separator = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
const shownElements = this.elements.filter(element => !element.hidden);
|
||||
|
||||
// Sort by value
|
||||
const normalizedSearchValue = query.toLowerCase();
|
||||
shownElements.sort((a, b) => {
|
||||
if (!query) {
|
||||
return a.index - b.index; // restore natural order
|
||||
}
|
||||
return compareEntries(a, b, normalizedSearchValue);
|
||||
});
|
||||
if (query) {
|
||||
const normalizedSearchValue = query.toLowerCase();
|
||||
shownElements.sort((a, b) => {
|
||||
return compareEntries(a, b, normalizedSearchValue);
|
||||
});
|
||||
}
|
||||
|
||||
this.elementsToIndexes = shownElements.reduce((map, element, index) => {
|
||||
map.set(element.item, index);
|
||||
|
@ -528,4 +563,12 @@ registerThemingParticipant((theme, collector) => {
|
|||
collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused { background-color: ${listInactiveFocusBackground}; }`);
|
||||
collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused:hover { background-color: ${listInactiveFocusBackground}; }`);
|
||||
}
|
||||
const pickerGroupBorderColor = theme.getColor(pickerGroupBorder);
|
||||
if (pickerGroupBorderColor) {
|
||||
collector.addRule(`.quick-input-list .quick-input-list-entry { border-top-color: ${pickerGroupBorderColor}; }`);
|
||||
}
|
||||
const pickerGroupForegroundColor = theme.getColor(pickerGroupForeground);
|
||||
if (pickerGroupForegroundColor) {
|
||||
collector.addRule(`.quick-input-list .quick-input-list-separator { color: ${pickerGroupForegroundColor}; }`);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -56,6 +56,7 @@ import { Dimension, addClass } from 'vs/base/browser/dom';
|
|||
import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
import { IUriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay';
|
||||
import { isThenable, timeout } from 'vs/base/common/async';
|
||||
|
||||
const HELP_PREFIX = '?';
|
||||
|
||||
|
@ -157,7 +158,7 @@ export class QuickOpenController extends Component implements IQuickOpenService
|
|||
let arrayPromise: TPromise<string[] | IPickOpenEntry[]>;
|
||||
if (Array.isArray(arg1)) {
|
||||
arrayPromise = TPromise.as(arg1);
|
||||
} else if (TPromise.is(arg1)) {
|
||||
} else if (isThenable(arg1)) {
|
||||
arrayPromise = arg1;
|
||||
} else {
|
||||
throw new Error('illegal input');
|
||||
|
@ -393,11 +394,11 @@ export class QuickOpenController extends Component implements IQuickOpenService
|
|||
});
|
||||
|
||||
// Progress if task takes a long time
|
||||
TPromise.timeout(800).then(() => {
|
||||
setTimeout(() => {
|
||||
if (!picksPromiseDone && this.currentPickerToken === currentPickerToken) {
|
||||
this.pickOpenWidget.getProgressBar().infinite().show();
|
||||
}
|
||||
});
|
||||
}, 800);
|
||||
|
||||
// Show picker empty if resolving takes a while
|
||||
if (!picksPromiseDone) {
|
||||
|
@ -669,11 +670,11 @@ export class QuickOpenController extends Component implements IQuickOpenService
|
|||
this.previousActiveHandlerDescriptor = handlerDescriptor;
|
||||
|
||||
// Progress if task takes a long time
|
||||
TPromise.timeout(instantProgress ? 0 : 800).then(() => {
|
||||
setTimeout(() => {
|
||||
if (!resultPromiseDone && currentResultToken === this.currentResultToken) {
|
||||
this.quickOpenWidget.getProgressBar().infinite().show();
|
||||
}
|
||||
});
|
||||
}, instantProgress ? 0 : 800);
|
||||
|
||||
// Promise done handling
|
||||
resultPromise.done(() => {
|
||||
|
@ -708,7 +709,14 @@ export class QuickOpenController extends Component implements IQuickOpenService
|
|||
const previousInput = this.quickOpenWidget.getInput();
|
||||
const wasShowingHistory = previousInput && previousInput.entries && previousInput.entries.some(e => e instanceof EditorHistoryEntry || e instanceof EditorHistoryEntryGroup);
|
||||
if (wasShowingHistory || matchingHistoryEntries.length > 0) {
|
||||
(resolvedHandler.hasShortResponseTime() ? TPromise.timeout(QuickOpenController.MAX_SHORT_RESPONSE_TIME) : TPromise.as(undefined)).then(() => {
|
||||
let responseDelay: Thenable<void>;
|
||||
if (resolvedHandler.hasShortResponseTime()) {
|
||||
responseDelay = timeout(QuickOpenController.MAX_SHORT_RESPONSE_TIME);
|
||||
} else {
|
||||
responseDelay = Promise.resolve(void 0);
|
||||
}
|
||||
|
||||
responseDelay.then(() => {
|
||||
if (this.currentResultToken === currentResultToken && !inputSet) {
|
||||
this.quickOpenWidget.setInput(quickOpenModel, { autoFocusFirstEntry: true });
|
||||
inputSet = true;
|
||||
|
@ -1074,7 +1082,17 @@ class EditorHistoryHandler {
|
|||
// Massage search for scoring
|
||||
const query = prepareQuery(searchValue);
|
||||
|
||||
const history = this.historyService.getHistory()
|
||||
// Just return all if we are not searching
|
||||
const history = this.historyService.getHistory();
|
||||
if (!query.value) {
|
||||
return history.map(input => this.instantiationService.createInstance(EditorHistoryEntry, input));
|
||||
}
|
||||
|
||||
// Otherwise filter by search value and sort by score. Include matches on description
|
||||
// in case the user is explicitly including path separators.
|
||||
const accessor = query.containsPathSeparator ? MatchOnDescription : DoNotMatchOnDescription;
|
||||
return history
|
||||
|
||||
// For now, only support to match on inputs that provide resource information
|
||||
.filter(input => {
|
||||
let resource: URI;
|
||||
|
@ -1088,17 +1106,8 @@ class EditorHistoryHandler {
|
|||
})
|
||||
|
||||
// Conver to quick open entries
|
||||
.map(input => this.instantiationService.createInstance(EditorHistoryEntry, input));
|
||||
.map(input => this.instantiationService.createInstance(EditorHistoryEntry, input))
|
||||
|
||||
// Just return all if we are not searching
|
||||
if (!query.value) {
|
||||
return history;
|
||||
}
|
||||
|
||||
// Otherwise filter by search value and sort by score. Include matches on description
|
||||
// in case the user is explicitly including path separators.
|
||||
const accessor = query.containsPathSeparator ? MatchOnDescription : DoNotMatchOnDescription;
|
||||
return history
|
||||
// Make sure the search value is matching
|
||||
.filter(e => {
|
||||
const itemScore = scoreItem(e, query, false, accessor, this.scorerCache);
|
||||
|
|
|
@ -150,4 +150,52 @@
|
|||
|
||||
.monaco-workbench > .part.titlebar > .window-controls-container .window-icon.window-close:hover {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/* Menubar styles */
|
||||
|
||||
.monaco-workbench .menubar {
|
||||
display: flex;
|
||||
flex-shrink: 1;
|
||||
box-sizing: border-box;
|
||||
height: 30px;
|
||||
-webkit-app-region: no-drag;
|
||||
overflow: hidden;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.monaco-workbench.fullscreen .menubar {
|
||||
margin: 0px;
|
||||
padding: 0px 5px;
|
||||
}
|
||||
|
||||
.monaco-workbench .menubar > .menubar-menu-button {
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 0px 8px;
|
||||
cursor: default;
|
||||
-webkit-app-region: no-drag;
|
||||
zoom: 1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.monaco-workbench .menubar .menubar-menu-items-holder {
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
opacity: 1;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.monaco-workbench .menubar .menubar-menu-items-holder.monaco-menu-container {
|
||||
font-family: "Segoe WPC", "Segoe UI", ".SFNSDisplay-Light", "SFUIText-Light", "HelveticaNeue-Light", sans-serif, "Droid Sans Fallback";
|
||||
outline: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.monaco-workbench .menubar .menubar-menu-items-holder.monaco-menu-container :focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .menubar .menubar-menu-items-holder.monaco-menu-container {
|
||||
border: 2px solid #6FC3DF;
|
||||
}
|
|
@ -5,11 +5,8 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
import 'vs/workbench/browser/parts/menubar/menubar.contribution';
|
||||
import 'vs/css!./media/menubarpart';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { IMenubarMenu, IMenubarMenuItemAction, IMenubarMenuItemSubmenu, IMenubarKeybinding } from 'vs/platform/menubar/common/menubar';
|
||||
import { IMenuService, MenuId, IMenu, SubmenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
|
@ -26,7 +23,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
|
|||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, Disposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IRecentlyOpened } from 'vs/platform/history/common/history';
|
||||
import { IWorkspaceIdentifier, getWorkspaceLabel, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
|
@ -52,7 +49,7 @@ enum MenubarState {
|
|||
OPEN
|
||||
}
|
||||
|
||||
export class MenubarPart extends Part {
|
||||
export class MenubarControl extends Disposable {
|
||||
|
||||
private keys = [
|
||||
'files.autoSave',
|
||||
|
@ -126,7 +123,8 @@ export class MenubarPart extends Part {
|
|||
@IUriDisplayService private uriDisplayService: IUriDisplayService,
|
||||
@IUpdateService private updateService: IUpdateService
|
||||
) {
|
||||
super(id, { hasTitle: false }, themeService);
|
||||
|
||||
super();
|
||||
|
||||
this.topLevelMenus = {
|
||||
'File': this._register(this.menuService.createMenu(MenuId.MenubarFileMenu, this.contextKeyService)),
|
||||
|
@ -315,7 +313,6 @@ export class MenubarPart extends Part {
|
|||
|
||||
private onDidChangeFullscreen(): void {
|
||||
this.setUnfocusedState();
|
||||
this.updateStyles();
|
||||
}
|
||||
|
||||
private onDidChangeWindowFocus(hasFocus: boolean): void {
|
||||
|
@ -525,7 +522,7 @@ export class MenubarPart extends Part {
|
|||
const result: IAction[] = [];
|
||||
|
||||
if (workspaces.length > 0) {
|
||||
for (let i = 0; i < MenubarPart.MAX_MENU_RECENT_ENTRIES && i < workspaces.length; i++) {
|
||||
for (let i = 0; i < MenubarControl.MAX_MENU_RECENT_ENTRIES && i < workspaces.length; i++) {
|
||||
result.push(this.createOpenRecentMenuAction(workspaces[i], 'openRecentWorkspace', false));
|
||||
}
|
||||
|
||||
|
@ -533,7 +530,7 @@ export class MenubarPart extends Part {
|
|||
}
|
||||
|
||||
if (files.length > 0) {
|
||||
for (let i = 0; i < MenubarPart.MAX_MENU_RECENT_ENTRIES && i < files.length; i++) {
|
||||
for (let i = 0; i < MenubarControl.MAX_MENU_RECENT_ENTRIES && i < files.length; i++) {
|
||||
result.push(this.createOpenRecentMenuAction(files[i], 'openRecentFile', false));
|
||||
}
|
||||
|
||||
|
@ -991,14 +988,16 @@ export class MenubarPart extends Part {
|
|||
return this._onVisibilityChange.event;
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): Dimension[] {
|
||||
public layout(dimension: Dimension) {
|
||||
if (this.container) {
|
||||
this.container.style({ height: `${dimension.height}px` });
|
||||
}
|
||||
|
||||
if (!this.isVisible) {
|
||||
this.hideMenubar();
|
||||
} else {
|
||||
this.showMenubar();
|
||||
}
|
||||
|
||||
return super.layout(dimension);
|
||||
}
|
||||
|
||||
public getMenubarItemsDimensions(): Dimension {
|
||||
|
@ -1011,7 +1010,7 @@ export class MenubarPart extends Part {
|
|||
return new Dimension(0, 0);
|
||||
}
|
||||
|
||||
public createContentArea(parent: HTMLElement): HTMLElement {
|
||||
public create(parent: HTMLElement): HTMLElement {
|
||||
this.container = $(parent);
|
||||
|
||||
// Build the menubar
|
||||
|
@ -1031,7 +1030,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
|||
const menubarActiveWindowFgColor = theme.getColor(TITLE_BAR_ACTIVE_FOREGROUND);
|
||||
if (menubarActiveWindowFgColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button {
|
||||
.monaco-workbench .menubar > .menubar-menu-button {
|
||||
color: ${menubarActiveWindowFgColor};
|
||||
}
|
||||
`);
|
||||
|
@ -1040,7 +1039,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
|||
const menubarInactiveWindowFgColor = theme.getColor(TITLE_BAR_INACTIVE_FOREGROUND);
|
||||
if (menubarInactiveWindowFgColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .part.menubar.inactive > .menubar-menu-button {
|
||||
.monaco-workbench .menubar.inactive > .menubar-menu-button {
|
||||
color: ${menubarInactiveWindowFgColor};
|
||||
}
|
||||
`);
|
||||
|
@ -1050,9 +1049,9 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
|||
const menubarSelectedFgColor = theme.getColor(MENUBAR_SELECTION_FOREGROUND);
|
||||
if (menubarSelectedFgColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button.open,
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button:focus,
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button:hover {
|
||||
.monaco-workbench .menubar > .menubar-menu-button.open,
|
||||
.monaco-workbench .menubar > .menubar-menu-button:focus,
|
||||
.monaco-workbench .menubar > .menubar-menu-button:hover {
|
||||
color: ${menubarSelectedFgColor};
|
||||
}
|
||||
`);
|
||||
|
@ -1061,9 +1060,9 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
|||
const menubarSelectedBgColor = theme.getColor(MENUBAR_SELECTION_BACKGROUND);
|
||||
if (menubarSelectedBgColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button.open,
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button:focus,
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button:hover {
|
||||
.monaco-workbench .menubar > .menubar-menu-button.open,
|
||||
.monaco-workbench .menubar > .menubar-menu-button:focus,
|
||||
.monaco-workbench .menubar > .menubar-menu-button:hover {
|
||||
background-color: ${menubarSelectedBgColor};
|
||||
}
|
||||
`);
|
||||
|
@ -1072,18 +1071,18 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
|
|||
const menubarSelectedBorderColor = theme.getColor(MENUBAR_SELECTION_BORDER);
|
||||
if (menubarSelectedBorderColor) {
|
||||
collector.addRule(`
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button:hover {
|
||||
.monaco-workbench .menubar > .menubar-menu-button:hover {
|
||||
outline: dashed 1px;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button.open,
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button:focus {
|
||||
.monaco-workbench .menubar > .menubar-menu-button.open,
|
||||
.monaco-workbench .menubar > .menubar-menu-button:focus {
|
||||
outline: solid 1px;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button.open,
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button:focus,
|
||||
.monaco-workbench .part.menubar > .menubar-menu-button:hover {
|
||||
.monaco-workbench .menubar > .menubar-menu-button.open,
|
||||
.monaco-workbench .menubar > .menubar-menu-button:focus,
|
||||
.monaco-workbench .menubar > .menubar-menu-button:hover {
|
||||
outline-offset: -1px;
|
||||
outline-color: ${menubarSelectedBorderColor};
|
||||
}
|
|
@ -31,7 +31,7 @@ import URI from 'vs/base/common/uri';
|
|||
import { Color } from 'vs/base/common/color';
|
||||
import { trim } from 'vs/base/common/strings';
|
||||
import { addDisposableListener, EventType, EventHelper, Dimension } from 'vs/base/browser/dom';
|
||||
import { MenubarPart } from 'vs/workbench/browser/parts/menubar/menubarPart';
|
||||
import { MenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { template, getBaseLabel } from 'vs/base/common/labels';
|
||||
import { IUriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay';
|
||||
|
@ -52,7 +52,7 @@ export class TitlebarPart extends Part implements ITitleService {
|
|||
private windowControls: Builder;
|
||||
private maxRestoreControl: Builder;
|
||||
private appIcon: Builder;
|
||||
private menubarPart: MenubarPart;
|
||||
private menubarPart: MenubarControl;
|
||||
private menubar: Builder;
|
||||
private resizer: Builder;
|
||||
|
||||
|
@ -273,10 +273,10 @@ export class TitlebarPart extends Part implements ITitleService {
|
|||
}
|
||||
|
||||
// Menubar: the menubar part which is responsible for populating both the custom and native menubars
|
||||
this.menubarPart = this.instantiationService.createInstance(MenubarPart, 'workbench.parts.menubar');
|
||||
this.menubarPart = this.instantiationService.createInstance(MenubarControl, 'workbench.parts.titlebar.menubar');
|
||||
this.menubar = $(this.titleContainer).div({
|
||||
'class': ['part', 'menubar'],
|
||||
id: 'workbench.parts.menubar',
|
||||
'class': ['menubar'],
|
||||
id: 'workbench.parts.titlebar.menubar',
|
||||
role: 'menubar'
|
||||
});
|
||||
|
||||
|
|
|
@ -504,7 +504,7 @@ class TreeRenderer implements IRenderer {
|
|||
|
||||
if ((resource || node.themeIcon) && !icon) {
|
||||
const fileDecorations = this.configurationService.getValue<{ colors: boolean, badges: boolean }>('explorer.decorations');
|
||||
templateData.resourceLabel.setLabel({ name: label, resource: resource ? resource : URI.parse('_icon_resource') }, { fileKind: this.getFileKind(node), title, fileDecorations: fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'] });
|
||||
templateData.resourceLabel.setLabel({ name: label, resource: resource ? resource : URI.parse('missing:_icon_resource') }, { fileKind: this.getFileKind(node), title, fileDecorations: fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'] });
|
||||
} else {
|
||||
templateData.resourceLabel.setLabel({ name: label }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'] });
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import 'vs/css!./media/actions';
|
|||
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { IWindowService, IWindowsService, MenuBarVisibility } from 'vs/platform/windows/common/windows';
|
||||
import * as nls from 'vs/nls';
|
||||
import product from 'vs/platform/node/product';
|
||||
|
@ -20,10 +20,8 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
|
|||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { isMacintosh, isLinux, language } from 'vs/base/common/platform';
|
||||
import { IQuickOpenService, IFilePickOpenEntry, ISeparator, IPickOpenAction, IPickOpenItem } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import * as browser from 'vs/base/browser/browser';
|
||||
import { IIntegrityService } from 'vs/platform/integrity/common/integrity';
|
||||
import { IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
|
||||
import { ITimerService, IStartupMetrics } from 'vs/workbench/services/timer/common/timerService';
|
||||
import { IEditorGroupsService, GroupDirection, GroupLocation, IFindGroupScope } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
|
@ -37,7 +35,6 @@ import { IViewlet } from 'vs/workbench/common/viewlet';
|
|||
import { IPanel } from 'vs/workbench/common/panel';
|
||||
import { IWorkspaceIdentifier, getWorkspaceLabel, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { FileKind } from 'vs/platform/files/common/files';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtensionService, ActivationTimes } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { getEntries } from 'vs/base/common/performance';
|
||||
import { IssueType } from 'vs/platform/issue/common/issue';
|
||||
|
@ -53,7 +50,7 @@ import { IUriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay';
|
|||
import { dirname } from 'vs/base/common/resources';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IQuickInputService, IQuickPickItem, IQuickInputButton } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IQuickInputService, IQuickPickItem, IQuickInputButton, IQuickPickSeparator, IKeyMods } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { getIconClasses } from 'vs/workbench/browser/labels';
|
||||
|
||||
// --- actions
|
||||
|
@ -654,7 +651,6 @@ export class SwitchWindow extends BaseSwitchWindow {
|
|||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IModelService modelService: IModelService,
|
||||
@IModeService modeService: IModeService,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super(id, label, windowsService, windowService, quickInputService, keybindingService, modelService, modeService);
|
||||
}
|
||||
|
@ -678,7 +674,6 @@ export class QuickSwitchWindow extends BaseSwitchWindow {
|
|||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IModelService modelService: IModelService,
|
||||
@IModeService modeService: IModeService,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super(id, label, windowsService, windowService, quickInputService, keybindingService, modelService, modeService);
|
||||
}
|
||||
|
@ -692,16 +687,23 @@ export const inRecentFilesPickerContextKey = 'inRecentFilesPicker';
|
|||
|
||||
export abstract class BaseOpenRecentAction extends Action {
|
||||
|
||||
private removeFromRecentlyOpened: IQuickInputButton = {
|
||||
iconClass: 'action-remove-from-recently-opened',
|
||||
tooltip: nls.localize('remove', "Remove from Recently Opened")
|
||||
};
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
private windowService: IWindowService,
|
||||
private quickOpenService: IQuickOpenService,
|
||||
private windowsService: IWindowsService,
|
||||
private quickInputService: IQuickInputService,
|
||||
private contextService: IWorkspaceContextService,
|
||||
private environmentService: IEnvironmentService,
|
||||
private uriDisplayService: IUriDisplayService,
|
||||
private keybindingService: IKeybindingService,
|
||||
private instantiationService: IInstantiationService
|
||||
private modelService: IModelService,
|
||||
private modeService: IModeService,
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
@ -715,7 +717,7 @@ export abstract class BaseOpenRecentAction extends Action {
|
|||
|
||||
private openRecent(recentWorkspaces: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier)[], recentFiles: string[]): void {
|
||||
|
||||
function toPick(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | string, separator: ISeparator, fileKind: FileKind, environmentService: IEnvironmentService, uriDisplayService: IUriDisplayService, action: IAction): IFilePickOpenEntry {
|
||||
const toPick = (workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | string, fileKind: FileKind, environmentService: IEnvironmentService, uriDisplayService: IUriDisplayService, buttons: IQuickInputButton[]) => {
|
||||
let resource: URI;
|
||||
let label: string;
|
||||
let description: string;
|
||||
|
@ -734,63 +736,51 @@ export abstract class BaseOpenRecentAction extends Action {
|
|||
}
|
||||
|
||||
return {
|
||||
resource,
|
||||
fileKind,
|
||||
iconClasses: getIconClasses(this.modelService, this.modeService, resource, fileKind),
|
||||
label,
|
||||
description,
|
||||
separator,
|
||||
run: context => {
|
||||
setTimeout(() => {
|
||||
// Bug: somehow when not running this code in a timeout, it is not possible to use this picker
|
||||
// with quick navigate keys (not able to trigger quick navigate once running it once).
|
||||
runPick(resource, fileKind === FileKind.FILE, context);
|
||||
});
|
||||
},
|
||||
action
|
||||
buttons,
|
||||
workspace,
|
||||
resource,
|
||||
fileKind,
|
||||
};
|
||||
}
|
||||
|
||||
const runPick = (resource: URI, isFile: boolean, context: IEntryRunContext) => {
|
||||
const forceNewWindow = context.keymods.ctrlCmd;
|
||||
this.windowService.openWindow([resource], { forceNewWindow, forceOpenWorkspaceAsFile: isFile });
|
||||
};
|
||||
|
||||
const workspacePicks: IFilePickOpenEntry[] = recentWorkspaces.map((workspace, index) => toPick(workspace, index === 0 ? { label: nls.localize('workspaces', "workspaces") } : void 0, isSingleFolderWorkspaceIdentifier(workspace) ? FileKind.FOLDER : FileKind.ROOT_FOLDER, this.environmentService, this.uriDisplayService, !this.isQuickNavigate() ? this.instantiationService.createInstance(RemoveFromRecentlyOpened, workspace) : void 0));
|
||||
const filePicks: IFilePickOpenEntry[] = recentFiles.map((p, index) => toPick(p, index === 0 ? { label: nls.localize('files', "files"), border: true } : void 0, FileKind.FILE, this.environmentService, this.uriDisplayService, !this.isQuickNavigate() ? this.instantiationService.createInstance(RemoveFromRecentlyOpened, p) : void 0));
|
||||
const runPick = (resource: URI, isFile: boolean, keyMods: IKeyMods) => {
|
||||
const forceNewWindow = keyMods.ctrlCmd;
|
||||
return this.windowService.openWindow([resource], { forceNewWindow, forceOpenWorkspaceAsFile: isFile });
|
||||
};
|
||||
|
||||
const workspacePicks = recentWorkspaces.map(workspace => toPick(workspace, isSingleFolderWorkspaceIdentifier(workspace) ? FileKind.FOLDER : FileKind.ROOT_FOLDER, this.environmentService, this.uriDisplayService, !this.isQuickNavigate() ? [this.removeFromRecentlyOpened] : void 0));
|
||||
const filePicks = recentFiles.map(p => toPick(p, FileKind.FILE, this.environmentService, this.uriDisplayService, !this.isQuickNavigate() ? [this.removeFromRecentlyOpened] : void 0));
|
||||
|
||||
// focus second entry if the first recent workspace is the current workspace
|
||||
let autoFocusSecondEntry: boolean = recentWorkspaces[0] && this.contextService.isCurrentWorkspace(recentWorkspaces[0]);
|
||||
|
||||
this.quickOpenService.pick([...workspacePicks, ...filePicks], {
|
||||
let keyMods: IKeyMods;
|
||||
const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('workspaces', "workspaces") };
|
||||
const fileSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('files', "files"), border: true };
|
||||
const picks = [workspaceSeparator, ...workspacePicks, fileSeparator, ...filePicks];
|
||||
this.quickInputService.pick(picks, {
|
||||
contextKey: inRecentFilesPickerContextKey,
|
||||
autoFocus: { autoFocusFirstEntry: !autoFocusSecondEntry, autoFocusSecondEntry: autoFocusSecondEntry },
|
||||
activeItem: [...workspacePicks, ...filePicks][autoFocusSecondEntry ? 1 : 0],
|
||||
placeHolder: isMacintosh ? nls.localize('openRecentPlaceHolderMac', "Select to open (hold Cmd-key to open in new window)") : nls.localize('openRecentPlaceHolder', "Select to open (hold Ctrl-key to open in new window)"),
|
||||
matchOnDescription: true,
|
||||
quickNavigateConfiguration: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : void 0
|
||||
}).done(null, errors.onUnexpectedError);
|
||||
}
|
||||
}
|
||||
|
||||
class RemoveFromRecentlyOpened extends Action implements IPickOpenAction {
|
||||
|
||||
static readonly ID = 'workbench.action.removeFromRecentlyOpened';
|
||||
static readonly LABEL = nls.localize('remove', "Remove from Recently Opened");
|
||||
|
||||
constructor(
|
||||
private path: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | string),
|
||||
@IWindowsService private windowsService: IWindowsService
|
||||
) {
|
||||
super(RemoveFromRecentlyOpened.ID, RemoveFromRecentlyOpened.LABEL);
|
||||
|
||||
this.class = 'action-remove-from-recently-opened';
|
||||
}
|
||||
|
||||
run(item: IPickOpenItem): TPromise<boolean> {
|
||||
return this.windowsService.removeFromRecentlyOpened([this.path]).then(() => {
|
||||
item.remove();
|
||||
|
||||
return true;
|
||||
});
|
||||
onKeyMods: mods => keyMods = mods,
|
||||
quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : void 0,
|
||||
onDidTriggerItemButton: context => {
|
||||
this.windowsService.removeFromRecentlyOpened([context.item.workspace]).then(() => {
|
||||
context.removeItem();
|
||||
}).then(null, errors.onUnexpectedError);
|
||||
}
|
||||
})
|
||||
.then(pick => {
|
||||
if (pick) {
|
||||
return runPick(pick.resource, pick.fileKind === FileKind.FILE, keyMods);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.done(null, errors.onUnexpectedError);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -803,14 +793,16 @@ export class OpenRecentAction extends BaseOpenRecentAction {
|
|||
id: string,
|
||||
label: string,
|
||||
@IWindowService windowService: IWindowService,
|
||||
@IQuickOpenService quickOpenService: IQuickOpenService,
|
||||
@IWindowsService windowsService: IWindowsService,
|
||||
@IQuickInputService quickInputService: IQuickInputService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IModelService modelService: IModelService,
|
||||
@IModeService modeService: IModeService,
|
||||
@IUriDisplayService uriDisplayService: IUriDisplayService
|
||||
) {
|
||||
super(id, label, windowService, quickOpenService, contextService, environmentService, uriDisplayService, keybindingService, instantiationService);
|
||||
super(id, label, windowService, windowsService, quickInputService, contextService, environmentService, uriDisplayService, keybindingService, modelService, modeService);
|
||||
}
|
||||
|
||||
protected isQuickNavigate(): boolean {
|
||||
|
@ -827,14 +819,16 @@ export class QuickOpenRecentAction extends BaseOpenRecentAction {
|
|||
id: string,
|
||||
label: string,
|
||||
@IWindowService windowService: IWindowService,
|
||||
@IQuickOpenService quickOpenService: IQuickOpenService,
|
||||
@IWindowsService windowsService: IWindowsService,
|
||||
@IQuickInputService quickInputService: IQuickInputService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IEnvironmentService environmentService: IEnvironmentService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IModelService modelService: IModelService,
|
||||
@IModeService modeService: IModeService,
|
||||
@IUriDisplayService uriDisplayService: IUriDisplayService
|
||||
) {
|
||||
super(id, label, windowService, quickOpenService, contextService, environmentService, uriDisplayService, keybindingService, instantiationService);
|
||||
super(id, label, windowService, windowsService, quickInputService, contextService, environmentService, uriDisplayService, keybindingService, modelService, modeService);
|
||||
}
|
||||
|
||||
protected isQuickNavigate(): boolean {
|
||||
|
|
|
@ -341,6 +341,131 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
|
|||
order: 3
|
||||
});
|
||||
|
||||
// Help
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '1_welcome',
|
||||
command: {
|
||||
id: 'workbench.action.openDocumentationUrl',
|
||||
title: nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '1_welcome',
|
||||
command: {
|
||||
id: 'update.showCurrentReleaseNotes',
|
||||
title: nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")
|
||||
},
|
||||
order: 4
|
||||
});
|
||||
|
||||
// Reference
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '2_reference',
|
||||
command: {
|
||||
id: 'workbench.action.keybindingsReference',
|
||||
title: nls.localize({ key: 'miKeyboardShortcuts', comment: ['&& denotes a mnemonic'] }, "&&Keyboard Shortcuts Reference")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '2_reference',
|
||||
command: {
|
||||
id: 'workbench.action.openIntroductoryVideosUrl',
|
||||
title: nls.localize({ key: 'miIntroductoryVideos', comment: ['&& denotes a mnemonic'] }, "Introductory &&Videos")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '2_reference',
|
||||
command: {
|
||||
id: 'workbench.action.openTipsAndTricksUrl',
|
||||
title: nls.localize({ key: 'miTipsAndTricks', comment: ['&& denotes a mnemonic'] }, "&&Tips and Tricks")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
// Feedback
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '3_feedback',
|
||||
command: {
|
||||
id: 'workbench.action.openTwitterUrl',
|
||||
title: nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join us on Twitter")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '3_feedback',
|
||||
command: {
|
||||
id: 'workbench.action.openRequestFeatureUrl',
|
||||
title: nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Search Feature Requests")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '3_feedback',
|
||||
command: {
|
||||
id: 'workbench.action.openIssueReporter',
|
||||
title: nls.localize({ key: 'miReportIssue', comment: ['&& denotes a mnemonic', 'Translate this to "Report Issue in English" in all languages please!'] }, "Report &&Issue")
|
||||
},
|
||||
order: 3
|
||||
});
|
||||
|
||||
// Legal
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '4_legal',
|
||||
command: {
|
||||
id: 'workbench.action.openLicenseUrl',
|
||||
title: nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "View &&License")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '4_legal',
|
||||
command: {
|
||||
id: 'workbench.action.openPrivacyStatementUrl',
|
||||
title: nls.localize({ key: 'miPrivacyStatement', comment: ['&& denotes a mnemonic'] }, "&&Privacy Statement")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
// Tools
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '5_tools',
|
||||
command: {
|
||||
id: 'workbench.action.toggleDevTools',
|
||||
title: nls.localize({ key: 'miToggleDevTools', comment: ['&& denotes a mnemonic'] }, "&&Toggle Developer Tools")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '5_tools',
|
||||
command: {
|
||||
id: 'workbench.action.openProcessExplorer',
|
||||
title: nls.localize({ key: 'miOpenProcessExplorerer', comment: ['&& denotes a mnemonic'] }, "Open &&Process Explorer")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
// About
|
||||
if (!isMacintosh) {
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: 'z_about',
|
||||
command: {
|
||||
id: 'workbench.action.showAboutDialog',
|
||||
title: nls.localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
}
|
||||
|
||||
// Configuration: Workbench
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
|
||||
|
@ -510,7 +635,11 @@ configurationRegistry.registerConfiguration({
|
|||
},
|
||||
'workbench.settings.settingsSearchTocBehavior': {
|
||||
'type': 'string',
|
||||
'enum': ['hide', 'filter', 'show'],
|
||||
'enum': ['hide', 'filter'],
|
||||
'enumDescriptions': [
|
||||
nls.localize('settingsSearchTocBehavior.hide', "Hide the Table of Contents while searching."),
|
||||
nls.localize('settingsSearchTocBehavior.filter', "Filter the Table of Contents to just categories that have matching settings. Clicking a category will filter the results to that category."),
|
||||
],
|
||||
'description': nls.localize('settingsSearchTocBehavior', "Controls the behavior of the settings editor Table of Contents while searching."),
|
||||
'default': 'filter',
|
||||
'scope': ConfigurationScope.WINDOW
|
||||
|
|
|
@ -9,6 +9,7 @@ import * as nls from 'vs/nls';
|
|||
import URI from 'vs/base/common/uri';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
|
@ -41,6 +42,8 @@ import { AccessibilitySupport, isRootUser, isWindows, isMacintosh } from 'vs/bas
|
|||
import product from 'vs/platform/node/product';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
|
||||
const TextInputActions: IAction[] = [
|
||||
new Action('undo', nls.localize('undo', "Undo"), null, true, () => document.execCommand('undo') && TPromise.as(true)),
|
||||
|
@ -74,7 +77,9 @@ export class ElectronWindow extends Themable {
|
|||
@IWorkbenchThemeService protected themeService: IWorkbenchThemeService,
|
||||
@INotificationService private notificationService: INotificationService,
|
||||
@ICommandService private commandService: ICommandService,
|
||||
@IExtensionService private extensionService: IExtensionService,
|
||||
@IContextMenuService private contextMenuService: IContextMenuService,
|
||||
@IKeybindingService private keybindingService: IKeybindingService,
|
||||
@ITelemetryService private telemetryService: ITelemetryService,
|
||||
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
|
||||
@IFileService private fileService: IFileService,
|
||||
|
@ -136,6 +141,22 @@ export class ElectronWindow extends Themable {
|
|||
});
|
||||
});
|
||||
|
||||
// Support resolve keybindings event
|
||||
ipc.on('vscode:resolveKeybindings', (event: any, rawActionIds: string) => {
|
||||
let actionIds: string[] = [];
|
||||
try {
|
||||
actionIds = JSON.parse(rawActionIds);
|
||||
} catch (error) {
|
||||
// should not happen
|
||||
}
|
||||
// Resolve keys using the keybinding service and send back to browser process
|
||||
this.resolveKeybindings(actionIds).done(keybindings => {
|
||||
if (keybindings.length) {
|
||||
ipc.send('vscode:keybindingsResolved', JSON.stringify(keybindings));
|
||||
}
|
||||
}, () => errors.onUnexpectedError);
|
||||
});
|
||||
|
||||
ipc.on('vscode:reportError', (event: any, error: string) => {
|
||||
if (error) {
|
||||
const errorParsed = JSON.parse(error);
|
||||
|
@ -354,6 +375,28 @@ export class ElectronWindow extends Themable {
|
|||
}
|
||||
}
|
||||
|
||||
private resolveKeybindings(actionIds: string[]): TPromise<{ id: string; label: string, isNative: boolean; }[]> {
|
||||
return TPromise.join([this.lifecycleService.when(LifecyclePhase.Running), this.extensionService.whenInstalledExtensionsRegistered()]).then(() => {
|
||||
return arrays.coalesce(actionIds.map(id => {
|
||||
const binding = this.keybindingService.lookupKeybinding(id);
|
||||
if (!binding) {
|
||||
return null;
|
||||
}
|
||||
// first try to resolve a native accelerator
|
||||
const electronAccelerator = binding.getElectronAccelerator();
|
||||
if (electronAccelerator) {
|
||||
return { id, label: electronAccelerator, isNative: true };
|
||||
}
|
||||
// we need this fallback to support keybindings that cannot show in electron menus (e.g. chords)
|
||||
const acceleratorLabel = binding.getLabel();
|
||||
if (acceleratorLabel) {
|
||||
return { id, label: acceleratorLabel, isNative: false };
|
||||
}
|
||||
return null;
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
private onAddFoldersRequest(request: IAddFoldersRequest): void {
|
||||
|
||||
// Buffer all pending requests
|
||||
|
|
|
@ -24,6 +24,7 @@ import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
|
|||
import { RPCProtocol } from 'vs/workbench/services/extensions/node/rpcProtocol';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
const nativeExit = process.exit.bind(process);
|
||||
function patchProcess(allowExit: boolean) {
|
||||
|
@ -179,7 +180,7 @@ export class ExtensionHostMain {
|
|||
|
||||
// Give extensions 1 second to wrap up any async dispose, then exit
|
||||
setTimeout(() => {
|
||||
TPromise.any<void>([TPromise.timeout(4000), extensionsDeactivated]).then(() => exit(), () => exit());
|
||||
TPromise.any<void>([timeout(4000), extensionsDeactivated]).then(() => exit(), () => exit());
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,37 +4,38 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { ICodeEditor, IContentWidget, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
|
||||
export class CommentGlyphWidget implements IContentWidget {
|
||||
private _id: string;
|
||||
export class CommentGlyphWidget {
|
||||
private _lineNumber: number;
|
||||
private _domNode: HTMLDivElement;
|
||||
private _editor: ICodeEditor;
|
||||
private commentsDecorations: string[] = [];
|
||||
private _commentsOptions: ModelDecorationOptions;
|
||||
|
||||
constructor(id: string, editor: ICodeEditor, lineNumber: number, disabled: boolean, onClick: () => void) {
|
||||
this._id = id;
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.className = disabled ? 'comment-hint commenting-disabled' : 'comment-hint';
|
||||
this._domNode.addEventListener('click', onClick);
|
||||
|
||||
constructor(editor: ICodeEditor, lineNumber: number, commentsOptions: ModelDecorationOptions, onClick: () => void) {
|
||||
this._commentsOptions = commentsOptions;
|
||||
this._lineNumber = lineNumber;
|
||||
|
||||
this._editor = editor;
|
||||
this._editor.addContentWidget(this);
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
getDomNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
}
|
||||
update() {
|
||||
let commentsDecorations = [{
|
||||
range: {
|
||||
startLineNumber: this._lineNumber, startColumn: 1,
|
||||
endLineNumber: this._lineNumber, endColumn: 1
|
||||
},
|
||||
options: this._commentsOptions
|
||||
}];
|
||||
|
||||
getId(): string {
|
||||
return this._id;
|
||||
this.commentsDecorations = this._editor.getModel().deltaDecorations(this.commentsDecorations, commentsDecorations);
|
||||
}
|
||||
|
||||
setLineNumber(lineNumber: number): void {
|
||||
this._lineNumber = lineNumber;
|
||||
this.update();
|
||||
}
|
||||
|
||||
getPosition(): IContentWidgetPosition {
|
||||
|
@ -46,4 +47,10 @@ export class CommentGlyphWidget implements IContentWidget {
|
|||
preference: [ContentWidgetPositionPreference.EXACT]
|
||||
};
|
||||
}
|
||||
|
||||
dispose() {
|
||||
if (this.commentsDecorations) {
|
||||
this._editor.deltaDecorations(this.commentsDecorations, []);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
|||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { SimpleCommentEditor } from './simpleCommentEditor';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { transparent, editorForeground, textLinkActiveForeground, textLinkForeground, focusBorder, textBlockQuoteBackground, textBlockQuoteBorder, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { transparent, editorForeground, textLinkActiveForeground, textLinkForeground, focusBorder, textBlockQuoteBackground, textBlockQuoteBorder, contrastBorder, inputValidationErrorBorder, inputValidationErrorBackground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
|
@ -34,6 +34,8 @@ import { Range, IRange } from 'vs/editor/common/core/range';
|
|||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer';
|
||||
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
|
||||
export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration';
|
||||
const EXPAND_ACTION_CLASS = 'expand-review-action octicon octicon-chevron-down';
|
||||
|
@ -45,9 +47,11 @@ export class CommentNode {
|
|||
private _body: HTMLElement;
|
||||
private _md: HTMLElement;
|
||||
private _clearTimeout: any;
|
||||
|
||||
public get domNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
}
|
||||
|
||||
constructor(
|
||||
public comment: modes.Comment,
|
||||
private markdownRenderer: MarkdownRenderer,
|
||||
|
@ -115,6 +119,7 @@ export class ReviewZoneWidget extends ZoneWidget {
|
|||
private _localToDispose: IDisposable[];
|
||||
private _markdownRenderer: MarkdownRenderer;
|
||||
private _styleElement: HTMLStyleElement;
|
||||
private _error: HTMLElement;
|
||||
|
||||
public get owner(): number {
|
||||
return this._owner;
|
||||
|
@ -284,14 +289,13 @@ export class ReviewZoneWidget extends ZoneWidget {
|
|||
}
|
||||
|
||||
protected _doLayout(heightInPixel: number, widthInPixel: number): void {
|
||||
this._commentEditor.layout({ height: (this._commentEditor.hasWidgetFocus() ? 5 : 1) * 18, width: widthInPixel - 40 /* margin */ });
|
||||
this._commentEditor.layout({ height: (this._commentEditor.hasWidgetFocus() ? 5 : 1) * 18, width: widthInPixel - 42 /* margin */ });
|
||||
}
|
||||
|
||||
display(lineNumber: number) {
|
||||
this._commentGlyph = new CommentGlyphWidget(`review_${lineNumber}`, this.editor, lineNumber, false, () => {
|
||||
display(lineNumber: number, commentsOptions: ModelDecorationOptions) {
|
||||
this._commentGlyph = new CommentGlyphWidget(this.editor, lineNumber, commentsOptions, () => {
|
||||
this.toggleExpand();
|
||||
});
|
||||
this.editor.layoutContentWidget(this._commentGlyph);
|
||||
|
||||
this._localToDispose.push(this.editor.onMouseDown(e => this.onEditorMouseDown(e)));
|
||||
this._localToDispose.push(this.editor.onMouseUp(e => this.onEditorMouseUp(e)));
|
||||
|
@ -300,7 +304,6 @@ export class ReviewZoneWidget extends ZoneWidget {
|
|||
if (this.position) {
|
||||
if (this.position.lineNumber !== this._commentGlyph.getPosition().position.lineNumber) {
|
||||
this._commentGlyph.setLineNumber(this.position.lineNumber);
|
||||
this.editor.layoutContentWidget(this._commentGlyph);
|
||||
}
|
||||
} else {
|
||||
// Otherwise manually calculate position change :(
|
||||
|
@ -312,7 +315,6 @@ export class ReviewZoneWidget extends ZoneWidget {
|
|||
}
|
||||
}).reduce((prev, curr) => prev + curr, 0);
|
||||
this._commentGlyph.setLineNumber(this._commentGlyph.getPosition().position.lineNumber + positionChange);
|
||||
this.editor.layoutContentWidget(this._commentGlyph);
|
||||
}
|
||||
}));
|
||||
var headHeight = Math.ceil(this.editor.getConfiguration().lineHeight * 1.2);
|
||||
|
@ -364,8 +366,15 @@ export class ReviewZoneWidget extends ZoneWidget {
|
|||
this.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
if (this._commentEditor.getModel().getValueLength() !== 0 && ev.keyCode === KeyCode.Enter && ev.ctrlKey) {
|
||||
let lineNumber = this._commentGlyph.getPosition().position.lineNumber;
|
||||
this.createComment(lineNumber);
|
||||
}
|
||||
}));
|
||||
|
||||
this._error = $('.validation-error.hidden').appendTo(this._commentForm).getHTMLElement();
|
||||
|
||||
const formActions = $('.form-actions').appendTo(this._commentForm).getHTMLElement();
|
||||
|
||||
const button = new Button(formActions);
|
||||
|
@ -382,36 +391,8 @@ export class ReviewZoneWidget extends ZoneWidget {
|
|||
}));
|
||||
|
||||
button.onDidClick(async () => {
|
||||
let newCommentThread;
|
||||
if (this._commentThread.threadId) {
|
||||
// reply
|
||||
newCommentThread = await this.commentService.replyToCommentThread(
|
||||
this._owner,
|
||||
this.editor.getModel().uri,
|
||||
new Range(lineNumber, 1, lineNumber, 1),
|
||||
this._commentThread,
|
||||
this._commentEditor.getValue()
|
||||
);
|
||||
} else {
|
||||
newCommentThread = await this.commentService.createNewCommentThread(
|
||||
this._owner,
|
||||
this.editor.getModel().uri,
|
||||
new Range(lineNumber, 1, lineNumber, 1),
|
||||
this._commentEditor.getValue()
|
||||
);
|
||||
|
||||
this.createReplyButton();
|
||||
this.createParticipantsLabel();
|
||||
}
|
||||
|
||||
this._commentEditor.setValue('');
|
||||
if (dom.hasClass(this._commentForm, 'expand')) {
|
||||
dom.removeClass(this._commentForm, 'expand');
|
||||
}
|
||||
|
||||
if (newCommentThread) {
|
||||
this.update(newCommentThread);
|
||||
}
|
||||
let lineNumber = this._commentGlyph.getPosition().position.lineNumber;
|
||||
this.createComment(lineNumber);
|
||||
});
|
||||
|
||||
this._resizeObserver = new MutationObserver(this._refresh.bind(this));
|
||||
|
@ -433,6 +414,52 @@ export class ReviewZoneWidget extends ZoneWidget {
|
|||
}
|
||||
}
|
||||
|
||||
private async createComment(lineNumber: number): Promise<void> {
|
||||
try {
|
||||
let newCommentThread;
|
||||
|
||||
if (this._commentThread.threadId) {
|
||||
// reply
|
||||
newCommentThread = await this.commentService.replyToCommentThread(
|
||||
this._owner,
|
||||
this.editor.getModel().uri,
|
||||
new Range(lineNumber, 1, lineNumber, 1),
|
||||
this._commentThread,
|
||||
this._commentEditor.getValue()
|
||||
);
|
||||
} else {
|
||||
newCommentThread = await this.commentService.createNewCommentThread(
|
||||
this._owner,
|
||||
this.editor.getModel().uri,
|
||||
new Range(lineNumber, 1, lineNumber, 1),
|
||||
this._commentEditor.getValue()
|
||||
);
|
||||
|
||||
if (newCommentThread) {
|
||||
this.createReplyButton();
|
||||
this.createParticipantsLabel();
|
||||
}
|
||||
}
|
||||
|
||||
if (newCommentThread) {
|
||||
this._commentEditor.setValue('');
|
||||
if (dom.hasClass(this._commentForm, 'expand')) {
|
||||
dom.removeClass(this._commentForm, 'expand');
|
||||
}
|
||||
this._commentEditor.getDomNode().style.outline = '';
|
||||
this._error.textContent = '';
|
||||
dom.addClass(this._error, 'hidden');
|
||||
this.update(newCommentThread);
|
||||
}
|
||||
} catch (e) {
|
||||
this._error.textContent = e.message
|
||||
? nls.localize('commentCreationError', "Adding a comment failed: {0}.", e.message)
|
||||
: nls.localize('commentCreationDefaultError', "Adding a comment failed. Please try again or report an issue with the extension if the problem persists.");
|
||||
this._commentEditor.getDomNode().style.outline = `1px solid ${this.themeService.getTheme().getColor(inputValidationErrorBorder)}`;
|
||||
dom.removeClass(this._error, 'hidden');
|
||||
}
|
||||
}
|
||||
|
||||
createParticipantsLabel() {
|
||||
const primaryHeading = 'Participants:';
|
||||
$(this._primaryHeading).safeInnerHtml(primaryHeading);
|
||||
|
@ -480,7 +507,7 @@ export class ReviewZoneWidget extends ZoneWidget {
|
|||
if (model) {
|
||||
let valueLength = model.getValueLength();
|
||||
const hasExistingComments = this._commentThread.comments.length > 0;
|
||||
let placeholder = valueLength > 0 ? '' : (hasExistingComments ? 'Reply...' : 'Type a new comment');
|
||||
let placeholder = valueLength > 0 ? '' : (hasExistingComments ? 'Reply... (press Ctrl+Enter to submit)' : 'Type a new comment (press Ctrl+Enter to submit)');
|
||||
const decorations = [{
|
||||
range: {
|
||||
startLineNumber: 0,
|
||||
|
@ -500,61 +527,72 @@ export class ReviewZoneWidget extends ZoneWidget {
|
|||
}
|
||||
}
|
||||
|
||||
private mouseDownInfo: { lineNumber: number, iconClicked: boolean };
|
||||
private mouseDownInfo: { lineNumber: number };
|
||||
|
||||
private onEditorMouseDown(e: IEditorMouseEvent): void {
|
||||
if (!e.event.leftButton) {
|
||||
return;
|
||||
}
|
||||
this.mouseDownInfo = null;
|
||||
|
||||
const range = e.target.range;
|
||||
|
||||
let range = e.target.range;
|
||||
if (!range) {
|
||||
return;
|
||||
}
|
||||
|
||||
let iconClicked = false;
|
||||
switch (e.target.type) {
|
||||
case MouseTargetType.GUTTER_GLYPH_MARGIN:
|
||||
iconClicked = true;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
if (!e.event.leftButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.mouseDownInfo = { lineNumber: range.startLineNumber, iconClicked };
|
||||
if (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = e.target.detail as IMarginData;
|
||||
const gutterOffsetX = data.offsetX - data.glyphMarginWidth - data.lineNumbersWidth - data.glyphMarginLeft;
|
||||
|
||||
// don't collide with folding and git decorations
|
||||
if (gutterOffsetX > 14) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.mouseDownInfo = { lineNumber: range.startLineNumber };
|
||||
}
|
||||
|
||||
private onEditorMouseUp(e: IEditorMouseEvent): void {
|
||||
if (!this.mouseDownInfo) {
|
||||
return;
|
||||
}
|
||||
let lineNumber = this.mouseDownInfo.lineNumber;
|
||||
let iconClicked = this.mouseDownInfo.iconClicked;
|
||||
|
||||
let range = e.target.range;
|
||||
const { lineNumber } = this.mouseDownInfo;
|
||||
this.mouseDownInfo = null;
|
||||
|
||||
const range = e.target.range;
|
||||
|
||||
if (!range || range.startLineNumber !== lineNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.position && this.position.lineNumber !== lineNumber) {
|
||||
if (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.position && lineNumber !== this._commentThread.range.startLineNumber) {
|
||||
if (!e.target.element) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (iconClicked) {
|
||||
if (e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN) {
|
||||
return;
|
||||
if (this._commentGlyph && this._commentGlyph.getPosition().position.lineNumber !== lineNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target.element.className.indexOf('comment-thread') >= 0) {
|
||||
if (this._isCollapsed) {
|
||||
this.show({ lineNumber: lineNumber, column: 1 }, 2);
|
||||
} else {
|
||||
this.hide();
|
||||
if (this._commentThread === null) {
|
||||
this.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this._isCollapsed) {
|
||||
this.show({ lineNumber: lineNumber, column: 1 }, 2);
|
||||
} else {
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
|
||||
private _applyTheme(theme: ITheme) {
|
||||
|
@ -597,6 +635,16 @@ export class ReviewZoneWidget extends ZoneWidget {
|
|||
content.push(`.monaco-editor .review-widget .body .comment-form .monaco-editor { outline: 1px solid ${hcBorder}; }`);
|
||||
}
|
||||
|
||||
const errorBorder = theme.getColor(inputValidationErrorBorder);
|
||||
if (errorBorder) {
|
||||
content.push(`.monaco-editor .review-widget .body .comment-form .validation-error { border: 1px solid ${errorBorder}; }`);
|
||||
}
|
||||
|
||||
const errorBackground = theme.getColor(inputValidationErrorBackground);
|
||||
if (errorBackground) {
|
||||
content.push(`.monaco-editor .review-widget .body .comment-form .validation-error { background: ${errorBackground}; }`);
|
||||
}
|
||||
|
||||
this._styleElement.innerHTML = content.join('\n');
|
||||
|
||||
// Editor decorations should also be responsive to theme changes
|
||||
|
@ -622,7 +670,7 @@ export class ReviewZoneWidget extends ZoneWidget {
|
|||
}
|
||||
|
||||
if (this._commentGlyph) {
|
||||
this.editor.removeContentWidget(this._commentGlyph);
|
||||
this._commentGlyph.dispose();
|
||||
this._commentGlyph = null;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,27 +10,30 @@ import { $ } from 'vs/base/browser/builder';
|
|||
import { findFirstInSorted } from 'vs/base/common/arrays';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ICodeEditor, IEditorMouseEvent, IViewZone } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICodeEditor, IEditorMouseEvent, IViewZone, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { registerEditorContribution, EditorAction, registerEditorAction } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { peekViewEditorBackground, peekViewResultsBackground, peekViewResultsSelectionBackground } from 'vs/editor/contrib/referenceSearch/referencesWidget';
|
||||
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { editorForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { editorForeground, registerColor } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { CommentThreadCollapsibleState } from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ReviewModel } from 'vs/workbench/parts/comments/common/reviewModel';
|
||||
import { CommentGlyphWidget } from 'vs/workbench/parts/comments/electron-browser/commentGlyphWidget';
|
||||
import { ReviewZoneWidget, COMMENTEDITOR_DECORATION_KEY } from 'vs/workbench/parts/comments/electron-browser/commentThreadWidget';
|
||||
import { ICommentService } from 'vs/workbench/parts/comments/electron-browser/commentService';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { IModelDecorationOptions } from 'vs/editor/common/model';
|
||||
import { Color, RGBA } from 'vs/base/common/color';
|
||||
import { IMarginData } from 'vs/editor/browser/controller/mouseTarget';
|
||||
|
||||
export const ctxReviewPanelVisible = new RawContextKey<boolean>('reviewPanelVisible', false);
|
||||
|
||||
|
@ -53,6 +56,103 @@ export class ReviewViewZone implements IViewZone {
|
|||
}
|
||||
}
|
||||
|
||||
const overviewRulerDefault = new Color(new RGBA(197, 197, 197, 1));
|
||||
|
||||
export const overviewRulerCommentingRangeForeground = registerColor('editorGutter.commentRangeForeground', { dark: overviewRulerDefault, light: overviewRulerDefault, hc: overviewRulerDefault }, nls.localize('editorGutterCommentRangeForeground', 'Editor gutter decoration color for commenting ranges.'));
|
||||
|
||||
class CommentingRangeDecoration {
|
||||
private _decorationId: string;
|
||||
|
||||
constructor(private _editor: ICodeEditor, private _ownerId: number, private _range: IRange, private _reply: modes.Command, commentingOptions: ModelDecorationOptions) {
|
||||
const startLineNumber = _range.startLineNumber;
|
||||
const endLineNumber = _range.endLineNumber;
|
||||
let commentingRangeDecorations = [{
|
||||
range: {
|
||||
startLineNumber: startLineNumber, startColumn: 1,
|
||||
endLineNumber: endLineNumber, endColumn: 1
|
||||
},
|
||||
options: commentingOptions
|
||||
}];
|
||||
|
||||
let model = this._editor.getModel();
|
||||
if (model) {
|
||||
this._decorationId = model.deltaDecorations([this._decorationId], commentingRangeDecorations)[0];
|
||||
}
|
||||
}
|
||||
|
||||
getCommentAction(): { replyCommand: modes.Command, ownerId: number } {
|
||||
return {
|
||||
replyCommand: this._reply,
|
||||
ownerId: this._ownerId
|
||||
};
|
||||
}
|
||||
|
||||
getOriginalRange() {
|
||||
return this._range;
|
||||
}
|
||||
|
||||
getActiveRange() {
|
||||
return this._editor.getModel().getDecorationRange(this._decorationId);
|
||||
}
|
||||
}
|
||||
class CommentingRangeDecorator {
|
||||
|
||||
static createDecoration(className: string, foregroundColor: string, options: { gutter: boolean, overview: boolean }): ModelDecorationOptions {
|
||||
const decorationOptions: IModelDecorationOptions = {
|
||||
isWholeLine: true,
|
||||
};
|
||||
|
||||
decorationOptions.linesDecorationsClassName = `comment-range-glyph ${className}`;
|
||||
return ModelDecorationOptions.createDynamic(decorationOptions);
|
||||
}
|
||||
|
||||
private commentingOptions: ModelDecorationOptions;
|
||||
public commentsOptions: ModelDecorationOptions;
|
||||
private commentingRangeDecorations: CommentingRangeDecoration[] = [];
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
constructor(
|
||||
) {
|
||||
const options = { gutter: true, overview: false };
|
||||
this.commentingOptions = CommentingRangeDecorator.createDecoration('comment-diff-added', overviewRulerCommentingRangeForeground, options);
|
||||
this.commentsOptions = CommentingRangeDecorator.createDecoration('comment-thread', overviewRulerCommentingRangeForeground, options);
|
||||
}
|
||||
|
||||
update(editor: ICodeEditor, commentInfos: modes.CommentInfo[]) {
|
||||
let model = editor.getModel();
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
let commentingRangeDecorations = [];
|
||||
for (let i = 0; i < commentInfos.length; i++) {
|
||||
let info = commentInfos[i];
|
||||
info.commentingRanges.forEach(range => {
|
||||
commentingRangeDecorations.push(new CommentingRangeDecoration(editor, info.owner, range, info.reply, this.commentingOptions));
|
||||
});
|
||||
}
|
||||
|
||||
this.commentingRangeDecorations = commentingRangeDecorations;
|
||||
}
|
||||
|
||||
getMatchedCommentAction(line: number) {
|
||||
for (let i = 0; i < this.commentingRangeDecorations.length; i++) {
|
||||
let range = this.commentingRangeDecorations[i].getActiveRange();
|
||||
|
||||
if (range.startLineNumber <= line && line <= range.endLineNumber) {
|
||||
return this.commentingRangeDecorations[i].getCommentAction();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
this.commentingRangeDecorations = [];
|
||||
}
|
||||
}
|
||||
|
||||
export class ReviewController implements IEditorContribution {
|
||||
private globalToDispose: IDisposable[];
|
||||
private localToDispose: IDisposable[];
|
||||
|
@ -62,15 +162,17 @@ export class ReviewController implements IEditorContribution {
|
|||
private _reviewPanelVisible: IContextKey<boolean>;
|
||||
private _commentInfos: modes.CommentInfo[];
|
||||
private _reviewModel: ReviewModel;
|
||||
private _newCommentGlyph: CommentGlyphWidget;
|
||||
private _hasSetComments: boolean;
|
||||
// private _hasSetComments: boolean;
|
||||
private _commentingRangeDecorator: CommentingRangeDecorator;
|
||||
private mouseDownInfo: { lineNumber: number } | null = null;
|
||||
private _commentingRangeSpaceReserved = false;
|
||||
|
||||
|
||||
constructor(
|
||||
editor: ICodeEditor,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IThemeService private themeService: IThemeService,
|
||||
@ICommentService private commentService: ICommentService,
|
||||
@INotificationService private notificationService: INotificationService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IModeService private modeService: IModeService,
|
||||
@IModelService private modelService: IModelService,
|
||||
|
@ -83,11 +185,11 @@ export class ReviewController implements IEditorContribution {
|
|||
this._commentInfos = [];
|
||||
this._commentWidgets = [];
|
||||
this._newCommentWidget = null;
|
||||
this._newCommentGlyph = null;
|
||||
this._hasSetComments = false;
|
||||
// this._hasSetComments = false;
|
||||
|
||||
this._reviewPanelVisible = ctxReviewPanelVisible.bindTo(contextKeyService);
|
||||
this._reviewModel = new ReviewModel();
|
||||
this._commentingRangeDecorator = new CommentingRangeDecorator();
|
||||
|
||||
this._reviewModel.onDidChangeStyle(style => {
|
||||
if (this._newCommentWidget) {
|
||||
|
@ -102,7 +204,7 @@ export class ReviewController implements IEditorContribution {
|
|||
this._commentInfos.forEach(info => {
|
||||
info.threads.forEach(thread => {
|
||||
let zoneWidget = new ReviewZoneWidget(this.instantiationService, this.modeService, this.modelService, this.themeService, this.commentService, this.openerService, this.editor, info.owner, thread, {});
|
||||
zoneWidget.display(thread.range.startLineNumber);
|
||||
zoneWidget.display(thread.range.startLineNumber, this._commentingRangeDecorator.commentsOptions);
|
||||
this._commentWidgets.push(zoneWidget);
|
||||
});
|
||||
});
|
||||
|
@ -115,11 +217,6 @@ export class ReviewController implements IEditorContribution {
|
|||
this._newCommentWidget = null;
|
||||
}
|
||||
|
||||
if (this._newCommentGlyph) {
|
||||
this.editor.removeContentWidget(this._newCommentGlyph);
|
||||
this._newCommentGlyph = null;
|
||||
}
|
||||
|
||||
this.getComments();
|
||||
}));
|
||||
|
||||
|
@ -232,23 +329,14 @@ export class ReviewController implements IEditorContribution {
|
|||
this._newCommentWidget = null;
|
||||
}
|
||||
|
||||
if (this._newCommentGlyph) {
|
||||
this.editor.removeContentWidget(this._newCommentGlyph);
|
||||
this._newCommentGlyph = null;
|
||||
}
|
||||
|
||||
this._commentWidgets.forEach(zone => {
|
||||
zone.dispose();
|
||||
});
|
||||
this._commentWidgets = [];
|
||||
|
||||
this.localToDispose.push(this.editor.onMouseMove(e => this.onEditorMouseMove(e)));
|
||||
this.localToDispose.push(this.editor.onMouseLeave(() => this.onMouseLeave()));
|
||||
this.localToDispose.push(this.editor.onMouseDown(e => this.onEditorMouseDown(e)));
|
||||
this.localToDispose.push(this.editor.onMouseUp(e => this.onEditorMouseUp(e)));
|
||||
this.localToDispose.push(this.editor.onDidChangeModelContent(() => {
|
||||
if (this._newCommentGlyph) {
|
||||
this.editor.removeContentWidget(this._newCommentGlyph);
|
||||
this._newCommentGlyph = null;
|
||||
}
|
||||
}));
|
||||
this.localToDispose.push(this.commentService.onDidUpdateCommentThreads(e => {
|
||||
const editorURI = this.editor && this.editor.getModel() && this.editor.getModel().uri;
|
||||
|
@ -277,7 +365,7 @@ export class ReviewController implements IEditorContribution {
|
|||
});
|
||||
added.forEach(thread => {
|
||||
let zoneWidget = new ReviewZoneWidget(this.instantiationService, this.modeService, this.modelService, this.themeService, this.commentService, this.openerService, this.editor, e.owner, thread, {});
|
||||
zoneWidget.display(thread.range.startLineNumber);
|
||||
zoneWidget.display(thread.range.startLineNumber, this._commentingRangeDecorator.commentsOptions);
|
||||
this._commentWidgets.push(zoneWidget);
|
||||
this._commentInfos.filter(info => info.owner === e.owner)[0].threads.push(thread);
|
||||
});
|
||||
|
@ -285,7 +373,7 @@ export class ReviewController implements IEditorContribution {
|
|||
}
|
||||
|
||||
private addComment(lineNumber: number) {
|
||||
let newCommentInfo = this.getNewCommentAction(lineNumber);
|
||||
let newCommentInfo = this._commentingRangeDecorator.getMatchedCommentAction(lineNumber);
|
||||
if (!newCommentInfo) {
|
||||
return;
|
||||
}
|
||||
|
@ -310,82 +398,91 @@ export class ReviewController implements IEditorContribution {
|
|||
this._newCommentWidget.onDidClose(e => {
|
||||
this._newCommentWidget = null;
|
||||
});
|
||||
this._newCommentWidget.display(lineNumber);
|
||||
this._newCommentWidget.display(lineNumber, this._commentingRangeDecorator.commentsOptions);
|
||||
}
|
||||
|
||||
private onEditorMouseMove(e: IEditorMouseEvent): void {
|
||||
if (!this._hasSetComments) {
|
||||
private onEditorMouseDown(e: IEditorMouseEvent): void {
|
||||
this.mouseDownInfo = null;
|
||||
|
||||
const range = e.target.range;
|
||||
|
||||
if (!range) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hasCommentingRanges = this._commentInfos.length && this._commentInfos.some(info => !!info.commentingRanges.length);
|
||||
if (hasCommentingRanges && e.target.position && e.target.position.lineNumber !== undefined) {
|
||||
if (this._newCommentGlyph && e.target.element.className !== 'comment-hint') {
|
||||
this.editor.removeContentWidget(this._newCommentGlyph);
|
||||
}
|
||||
if (!e.event.leftButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = e.target.detail as IMarginData;
|
||||
const gutterOffsetX = data.offsetX - data.glyphMarginWidth - data.lineNumbersWidth - data.glyphMarginLeft;
|
||||
|
||||
// don't collide with folding and git decorations
|
||||
if (gutterOffsetX > 14) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.mouseDownInfo = { lineNumber: range.startLineNumber };
|
||||
}
|
||||
|
||||
private onEditorMouseUp(e: IEditorMouseEvent): void {
|
||||
if (!this.mouseDownInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { lineNumber } = this.mouseDownInfo;
|
||||
this.mouseDownInfo = null;
|
||||
|
||||
const range = e.target.range;
|
||||
|
||||
if (!range || range.startLineNumber !== lineNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target.type !== MouseTargetType.GUTTER_LINE_DECORATIONS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.target.element) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target.element.className.indexOf('comment-diff-added') >= 0) {
|
||||
const lineNumber = e.target.position.lineNumber;
|
||||
if (!this.isExistingCommentThreadAtLine(lineNumber)) {
|
||||
this._newCommentGlyph = this.isLineInCommentingRange(lineNumber)
|
||||
? this._newCommentGlyph = new CommentGlyphWidget('comment-hint', this.editor, lineNumber, false, () => {
|
||||
this.addComment(lineNumber);
|
||||
})
|
||||
: this._newCommentGlyph = new CommentGlyphWidget('comment-hint', this.editor, lineNumber, true, () => {
|
||||
this.notificationService.warn('Commenting is not supported outside of diff hunk areas.');
|
||||
});
|
||||
|
||||
this.editor.layoutContentWidget(this._newCommentGlyph);
|
||||
}
|
||||
this.addComment(lineNumber);
|
||||
}
|
||||
}
|
||||
|
||||
private onMouseLeave(): void {
|
||||
if (this._newCommentGlyph) {
|
||||
this.editor.removeContentWidget(this._newCommentGlyph);
|
||||
}
|
||||
}
|
||||
|
||||
private getNewCommentAction(line: number): { replyCommand: modes.Command, ownerId: number } {
|
||||
for (let i = 0; i < this._commentInfos.length; i++) {
|
||||
const commentInfo = this._commentInfos[i];
|
||||
const lineWithinRange = commentInfo.commentingRanges.some(range =>
|
||||
range.startLineNumber <= line && line <= range.endLineNumber
|
||||
);
|
||||
|
||||
if (lineWithinRange) {
|
||||
return {
|
||||
replyCommand: commentInfo.reply,
|
||||
ownerId: commentInfo.owner
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private isLineInCommentingRange(line: number): boolean {
|
||||
return this._commentInfos.some(commentInfo => {
|
||||
return commentInfo.commentingRanges.some(range =>
|
||||
range.startLineNumber <= line && line <= range.endLineNumber
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private isExistingCommentThreadAtLine(line: number): boolean {
|
||||
const existingThread = this._commentInfos.some(commentInfo => {
|
||||
return commentInfo.threads.some(thread =>
|
||||
thread.range.startLineNumber === line
|
||||
);
|
||||
});
|
||||
|
||||
const existingNewComment = this._newCommentWidget && this._newCommentWidget.position && this._newCommentWidget.position.lineNumber === line;
|
||||
|
||||
return existingThread || existingNewComment;
|
||||
}
|
||||
|
||||
setComments(commentInfos: modes.CommentInfo[]): void {
|
||||
this._commentInfos = commentInfos;
|
||||
this._hasSetComments = true;
|
||||
let lineDecorationsWidth: number = this.editor.getConfiguration().layoutInfo.decorationsWidth;
|
||||
|
||||
if (this._commentInfos.some(info => Boolean(info.commentingRanges && info.commentingRanges.length))) {
|
||||
if (!this._commentingRangeSpaceReserved) {
|
||||
this._commentingRangeSpaceReserved = true;
|
||||
let extraEditorClassName = [];
|
||||
if (this.editor.getRawConfiguration().extraEditorClassName) {
|
||||
extraEditorClassName = this.editor.getRawConfiguration().extraEditorClassName.split(' ');
|
||||
}
|
||||
|
||||
if (this.editor.getConfiguration().contribInfo.folding) {
|
||||
lineDecorationsWidth -= 16;
|
||||
}
|
||||
lineDecorationsWidth += 9;
|
||||
extraEditorClassName.push('inline-comment');
|
||||
this.editor.updateOptions({
|
||||
extraEditorClassName: extraEditorClassName.join(' '),
|
||||
lineDecorationsWidth: lineDecorationsWidth
|
||||
});
|
||||
this.editor.layout();
|
||||
}
|
||||
}
|
||||
|
||||
// this._hasSetComments = true;
|
||||
|
||||
// create viewzones
|
||||
this._commentWidgets.forEach(zone => {
|
||||
|
@ -395,12 +492,17 @@ export class ReviewController implements IEditorContribution {
|
|||
this._commentInfos.forEach(info => {
|
||||
info.threads.forEach(thread => {
|
||||
let zoneWidget = new ReviewZoneWidget(this.instantiationService, this.modeService, this.modelService, this.themeService, this.commentService, this.openerService, this.editor, info.owner, thread, {});
|
||||
zoneWidget.display(thread.range.startLineNumber);
|
||||
zoneWidget.display(thread.range.startLineNumber, this._commentingRangeDecorator.commentsOptions);
|
||||
this._commentWidgets.push(zoneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const commentingRanges = [];
|
||||
this._commentInfos.forEach(info => {
|
||||
commentingRanges.push(...info.commentingRanges);
|
||||
});
|
||||
this._commentingRangeDecorator.update(this.editor, this._commentInfos);
|
||||
}
|
||||
|
||||
public closeWidget(): void {
|
||||
this._reviewPanelVisible.reset();
|
||||
|
@ -518,4 +620,22 @@ registerThemingParticipant((theme, collector) => {
|
|||
`}`
|
||||
);
|
||||
}
|
||||
|
||||
const commentingRangeForeground = theme.getColor(overviewRulerCommentingRangeForeground);
|
||||
if (commentingRangeForeground) {
|
||||
collector.addRule(`
|
||||
.monaco-editor .comment-diff-added {
|
||||
border-left: 3px solid ${commentingRangeForeground};
|
||||
}
|
||||
.monaco-editor .comment-diff-added:before {
|
||||
background: ${commentingRangeForeground};
|
||||
}
|
||||
.monaco-editor .comment-thread {
|
||||
border-left: 3px solid ${commentingRangeForeground};
|
||||
}
|
||||
.monaco-editor .comment-thread:before {
|
||||
background: ${commentingRangeForeground};
|
||||
}
|
||||
`);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
background-position: center center;
|
||||
}
|
||||
|
||||
.monaco-editor .comment-hint{
|
||||
.monaco-editor .comment-hint {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
padding-left: 2px;
|
||||
|
@ -126,6 +126,29 @@
|
|||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.monaco-editor .review-widget .body .comment-form .validation-error {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
-o-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
padding: 0.4em;
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
min-height: 34px;
|
||||
margin-top: -1px;
|
||||
margin-left: -1px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.monaco-editor .review-widget .body .comment-form .validation-error.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.monaco-editor .review-widget .body .comment-form.expand .review-thread-reply-button {
|
||||
display: none;
|
||||
}
|
||||
|
@ -239,4 +262,52 @@
|
|||
.monaco-editor .review-widget>.body {
|
||||
border-top: 1px solid;
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.monaco-editor .comment-range-glyph {
|
||||
margin-left: 5px;
|
||||
width: 4px !important;
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.monaco-editor .comment-range-glyph:before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
height: 100%;
|
||||
width: 0;
|
||||
left: -2px;
|
||||
transition: width 80ms linear, left 80ms linear;
|
||||
}
|
||||
|
||||
.monaco-editor .margin-view-overlays>div:hover>.comment-range-glyph.comment-diff-added:before {
|
||||
position: absolute;
|
||||
content: '+';
|
||||
height: 100%;
|
||||
width: 9px;
|
||||
left: -6px;
|
||||
z-index: 10;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.monaco-editor .comment-range-glyph.comment-thread {
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.monaco-editor .comment-range-glyph.comment-thread:before {
|
||||
position: absolute;
|
||||
content: '·';
|
||||
height: 100%;
|
||||
width: 9px;
|
||||
left: -6px;
|
||||
z-index: 20;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.monaco-editor.inline-comment .margin-view-overlays .folding {
|
||||
margin-left: 14px;
|
||||
}
|
||||
|
||||
.monaco-editor.inline-comment .margin-view-overlays .dirty-diff-glyph {
|
||||
margin-left: 14px;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
|
|||
import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IAdapterExecutable, IDebugAdapterProvider, IDebugAdapter, ITerminalSettings, ITerminalLauncher } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { Debugger } from 'vs/workbench/parts/debug/node/debugger';
|
||||
import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
|
||||
|
@ -33,6 +32,7 @@ import { TerminalLauncher } from 'vs/workbench/parts/debug/electron-browser/term
|
|||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { launchSchema, debuggersExtPoint, breakpointsExtPoint } from 'vs/workbench/parts/debug/common/debugSchemas';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
|
||||
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
|
||||
jsonRegistry.registerSchema(launchSchemaId, launchSchema);
|
||||
|
@ -57,7 +57,7 @@ export class ConfigurationManager implements IConfigurationManager {
|
|||
@IWorkspaceContextService private contextService: IWorkspaceContextService,
|
||||
@IEditorService private editorService: IEditorService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService,
|
||||
@IQuickInputService private quickInputService: IQuickInputService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@ICommandService private commandService: ICommandService,
|
||||
@IStorageService private storageService: IStorageService,
|
||||
|
@ -347,10 +347,11 @@ export class ConfigurationManager implements IConfigurationManager {
|
|||
}
|
||||
|
||||
candidates = candidates.sort((first, second) => first.label.localeCompare(second.label));
|
||||
return this.quickOpenService.pick([...candidates, { label: 'More...', separator: { border: true } }], { placeHolder: nls.localize('selectDebug', "Select Environment") })
|
||||
const picks = candidates.map(c => ({ label: c.label, debugger: c }));
|
||||
return this.quickInputService.pick<(typeof picks)[0]>([...picks, { type: 'separator', border: true }, { label: 'More...', debugger: undefined }], { placeHolder: nls.localize('selectDebug', "Select Environment") })
|
||||
.then(picked => {
|
||||
if (picked instanceof Debugger) {
|
||||
return picked;
|
||||
if (picked.debugger) {
|
||||
return picked.debugger;
|
||||
}
|
||||
if (picked) {
|
||||
this.commandService.executeCommand('debug.installAdditionalDebuggers');
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
|
@ -27,7 +26,7 @@ import { IWindowService } from 'vs/platform/windows/common/windows';
|
|||
import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/parts/files/common/files';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
import { ResourceQueue } from 'vs/base/common/async';
|
||||
import { ResourceQueue, timeout } from 'vs/base/common/async';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
|
||||
export class FileEditorTracker extends Disposable implements IWorkbenchContribution {
|
||||
|
@ -170,14 +169,14 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut
|
|||
// file is really gone and not just a faulty file event.
|
||||
// This only applies to external file events, so we need to check for the isExternal
|
||||
// flag.
|
||||
let checkExists: TPromise<boolean>;
|
||||
let checkExists: Thenable<boolean>;
|
||||
if (isExternal) {
|
||||
checkExists = TPromise.timeout(100).then(() => this.fileService.existsFile(resource));
|
||||
checkExists = timeout(100).then(() => this.fileService.existsFile(resource));
|
||||
} else {
|
||||
checkExists = TPromise.as(false);
|
||||
checkExists = Promise.resolve(false);
|
||||
}
|
||||
|
||||
checkExists.done(exists => {
|
||||
checkExists.then(exists => {
|
||||
if (!exists && !editor.isDisposed()) {
|
||||
editor.dispose();
|
||||
} else if (this.environmentService.verbose) {
|
||||
|
|
|
@ -15,7 +15,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
|
|||
import { toResource, IEditorIdentifier, IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { startsWith, startsWithIgnoreCase, rtrim } from 'vs/base/common/strings';
|
||||
import { rtrim } from 'vs/base/common/strings';
|
||||
import { IEditorGroup } from 'vs/workbench/services/group/common/editorGroupsService';
|
||||
|
||||
export class Model {
|
||||
|
@ -342,9 +342,7 @@ export class ExplorerItem {
|
|||
*/
|
||||
public find(resource: URI): ExplorerItem {
|
||||
// Return if path found
|
||||
if (resource && this.resource.scheme === resource.scheme && this.resource.authority === resource.authority &&
|
||||
(isLinux ? startsWith(resource.path, this.resource.path) : startsWithIgnoreCase(resource.path, this.resource.path))
|
||||
) {
|
||||
if (resource && resources.isEqualOrParent(resource, this.resource)) {
|
||||
return this.findByPath(rtrim(resource.path, paths.sep), this.resource.path.length);
|
||||
}
|
||||
|
||||
|
|
|
@ -544,3 +544,14 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, {
|
|||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
// Go to menu
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'workbench.action.quickOpen',
|
||||
title: nls.localize({ key: 'miGotoFile', comment: ['&& denotes a mnemonic'] }, "Go to &&File...")
|
||||
},
|
||||
order: 1
|
||||
});
|
|
@ -18,7 +18,12 @@ function createStat(path: string, name: string, isFolder: boolean, hasChildren:
|
|||
}
|
||||
|
||||
function toResource(path) {
|
||||
return URI.file(join('C:\\', path));
|
||||
if (isWindows) {
|
||||
return URI.file(join('C:\\', path));
|
||||
} else {
|
||||
return URI.file(join('/home/john', path));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
suite('Files - View Model', () => {
|
||||
|
|
|
@ -71,11 +71,17 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.monaco-tree.focused .selected .outline-element-label, .monaco-tree.focused .selected .outline-element-decoration {
|
||||
.monaco-tree.focused .selected .outline-element-label, .monaco-tree.focused .selected .outline-element-decoration{
|
||||
/* make sure selection color wins when a label is being selected */
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.monaco-tree.focused .selected .outline-element-label .monaco-highlighted-label .highlight,
|
||||
.monaco-tree.focused .selected .monaco-icon-label .monaco-highlighted-label .highlight{
|
||||
/* allows text color to use the default when selected */
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
.monaco-workbench .outline-panel.no-icons .outline-element .outline-element-icon {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
|||
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
|
||||
import { Action, IAction, RadioGroup } from 'vs/base/common/actions';
|
||||
import { firstIndex } from 'vs/base/common/arrays';
|
||||
import { asDisposablePromise, setDisposableTimeout, createCancelablePromise } from 'vs/base/common/async';
|
||||
import { asDisposablePromise, setDisposableTimeout, createCancelablePromise, timeout } from 'vs/base/common/async';
|
||||
import { onUnexpectedError, isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { defaultGenerator } from 'vs/base/common/idGenerator';
|
||||
|
@ -496,7 +496,7 @@ export class OutlinePanel extends ViewletPanel {
|
|||
let oldRatio = oldSize / oldLength;
|
||||
if (newRatio <= oldRatio * 0.5 || newRatio >= oldRatio * 1.5) {
|
||||
if (!await asDisposablePromise(
|
||||
TPromise.timeout(2000).then(_ => true),
|
||||
timeout(2000).then(_ => true),
|
||||
false,
|
||||
this._editorDisposables).promise
|
||||
) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import { localize } from 'vs/nls';
|
|||
import { readdir, del, readFile } from 'vs/base/node/pfs';
|
||||
import { basename } from 'vs/base/common/paths';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
class StartupProfiler implements IWorkbenchContribution {
|
||||
|
||||
|
@ -52,7 +53,7 @@ class StartupProfiler implements IWorkbenchContribution {
|
|||
const removeArgs: string[] = ['--prof-startup'];
|
||||
const markerFile = readFile(profileFilenamePrefix).then(value => removeArgs.push(...value.toString().split('|')))
|
||||
.then(() => del(profileFilenamePrefix))
|
||||
.then(() => TPromise.timeout(1000));
|
||||
.then(() => timeout(1000));
|
||||
|
||||
markerFile.then(() => {
|
||||
return readdir(dir).then(files => files.filter(value => value.indexOf(prefix) === 0));
|
||||
|
|
|
@ -109,14 +109,6 @@
|
|||
background-size: 16px;
|
||||
}
|
||||
|
||||
.vs .settings-editor > .settings-header > .settings-header-controls .settings-header-controls-right .toolbar-toggle-more {
|
||||
background-image: url('ellipsis.svg');
|
||||
}
|
||||
|
||||
.vs-dark .settings-editor > .settings-header > .settings-header-controls .settings-header-controls-right .toolbar-toggle-more {
|
||||
background-image: url('ellipsis-inverse.svg');
|
||||
}
|
||||
|
||||
.settings-editor > .settings-header > .settings-header-controls .settings-tabs-widget > .monaco-action-bar .action-item {
|
||||
padding: 0px; /* padding must be on action-label because it has the bottom-border, because that's where the .checked class is */
|
||||
}
|
||||
|
@ -327,7 +319,8 @@
|
|||
background: url('check.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item-bool .setting-value-checkbox.checked {
|
||||
.vs-dark .settings-editor > .settings-body > .settings-tree-container .setting-item-bool .setting-value-checkbox.checked,
|
||||
.hc-black .settings-editor > .settings-body > .settings-tree-container .setting-item-bool .setting-value-checkbox.checked {
|
||||
background: url('check-inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
|
|
|
@ -302,12 +302,6 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
this.settingsTree.reveal(lastElement, 0.9);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
const controls = this.settingsTree.getHTMLElement().querySelectorAll(SettingsRenderer.CONTROL_SELECTOR);
|
||||
const lastControl = controls && controls[controls.length];
|
||||
if (lastControl) {
|
||||
(<HTMLElement>lastControl).focus();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -336,7 +330,7 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
}
|
||||
|
||||
private createTOC(parent: HTMLElement): void {
|
||||
this.tocTreeModel = new TOCTreeModel();
|
||||
this.tocTreeModel = new TOCTreeModel(this.viewState);
|
||||
this.tocTreeContainer = DOM.append(parent, $('.settings-toc-container'));
|
||||
|
||||
const tocRenderer = this.instantiationService.createInstance(TOCRenderer);
|
||||
|
@ -673,22 +667,54 @@ export class SettingsEditor2 extends BaseEditor {
|
|||
this.searchInProgress = null;
|
||||
});
|
||||
} else {
|
||||
if (this.viewState.tagFilters && this.viewState.tagFilters.size) {
|
||||
this.searchResultModel = this.createFilterModel();
|
||||
} else {
|
||||
this.searchResultModel = null;
|
||||
}
|
||||
|
||||
this.localSearchDelayer.cancel();
|
||||
this.remoteSearchThrottle.cancel();
|
||||
if (this.searchInProgress && this.searchInProgress.cancel) {
|
||||
this.searchInProgress.cancel();
|
||||
}
|
||||
|
||||
this.searchResultModel = null;
|
||||
this.tocTreeModel.currentSearchModel = null;
|
||||
this.viewState.filterToCategory = null;
|
||||
this.tocTreeModel.currentSearchModel = this.searchResultModel;
|
||||
this.tocTree.refresh();
|
||||
this.toggleSearchMode();
|
||||
collapseAll(this.tocTree);
|
||||
return this.settingsTree.setInput(this.settingsTreeModel.root);
|
||||
|
||||
if (this.searchResultModel) {
|
||||
return this.settingsTree.setInput(this.searchResultModel);
|
||||
} else {
|
||||
return this.settingsTree.setInput(this.settingsTreeModel.root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a fake SearchResultModel which can hold a flat list of all settings, to be filtered (@modified etc)
|
||||
*/
|
||||
private createFilterModel(): SearchResultModel {
|
||||
const filterModel = this.instantiationService.createInstance(SearchResultModel, this.viewState);
|
||||
|
||||
const fullResult: ISearchResult = {
|
||||
filterMatches: []
|
||||
};
|
||||
for (let g of this.defaultSettingsEditorModel.settingsGroups.slice(1)) {
|
||||
for (let sect of g.sections) {
|
||||
for (let setting of sect.settings) {
|
||||
fullResult.filterMatches.push({ setting, matches: [], score: 0 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterModel.setResult(0, fullResult);
|
||||
|
||||
return filterModel;
|
||||
}
|
||||
|
||||
private reportFilteringUsed(query: string, results: ISearchResult[]): void {
|
||||
const nlpResult = results[SearchResultIdx.Remote];
|
||||
const nlpMetadata = nlpResult && nlpResult.metadata;
|
||||
|
|
|
@ -45,7 +45,7 @@ export const tocData: ITOCEntry = {
|
|||
},
|
||||
{
|
||||
id: 'editor/format',
|
||||
label: localize('format', "Format"),
|
||||
label: localize('formatting', "Formatting"),
|
||||
settings: ['editor.format*']
|
||||
},
|
||||
{
|
||||
|
|
|
@ -52,6 +52,7 @@ export abstract class SettingsTreeElement {
|
|||
|
||||
export class SettingsTreeGroupElement extends SettingsTreeElement {
|
||||
children: (SettingsTreeGroupElement | SettingsTreeSettingElement)[];
|
||||
count?: number;
|
||||
label: string;
|
||||
level: number;
|
||||
isFirstGroup: boolean;
|
||||
|
@ -91,6 +92,22 @@ export class SettingsTreeSettingElement extends SettingsTreeElement {
|
|||
overriddenScopeList: string[];
|
||||
description: string;
|
||||
valueType: 'enum' | 'string' | 'integer' | 'number' | 'boolean' | 'exclude' | 'complex';
|
||||
|
||||
matchesAllTags(tagFilters?: Set<string>): boolean {
|
||||
if (!tagFilters || !tagFilters.size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.tags) {
|
||||
let hasFilteredTag = true;
|
||||
tagFilters.forEach(tag => {
|
||||
hasFilteredTag = hasFilteredTag && this.tags.has(tag);
|
||||
});
|
||||
return hasFilteredTag;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface ITOCEntry {
|
||||
|
@ -174,7 +191,7 @@ function sanitizeId(id: string): string {
|
|||
return id.replace(/[\.\/]/, '_');
|
||||
}
|
||||
|
||||
function createSettingsTreeSettingElement(setting: ISetting, parent: any, settingsTarget: SettingsTarget, configurationService: IConfigurationService): SettingsTreeSettingElement {
|
||||
function createSettingsTreeSettingElement(setting: ISetting, parent: SearchResultModel | SettingsTreeGroupElement, settingsTarget: SettingsTarget, configurationService: IConfigurationService): SettingsTreeSettingElement {
|
||||
const element = new SettingsTreeSettingElement();
|
||||
element.id = sanitizeId(parent.id + '_' + setting.key);
|
||||
element.parent = parent;
|
||||
|
@ -1287,25 +1304,22 @@ export class SettingsTreeFilter implements IFilter {
|
|||
) { }
|
||||
|
||||
isVisible(tree: ITree, element: SettingsTreeElement): boolean {
|
||||
// Filter during search
|
||||
if (this.viewState.filterToCategory && element instanceof SettingsTreeSettingElement) {
|
||||
if (!this.settingContainedInGroup(element.setting, this.viewState.filterToCategory)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (element instanceof SettingsTreeSettingElement && this.viewState.tagFilters && this.viewState.tagFilters.size) {
|
||||
if (element.tags) {
|
||||
let hasFilteredTag = true;
|
||||
this.viewState.tagFilters.forEach(tag => {
|
||||
hasFilteredTag = hasFilteredTag && element.tags.has(tag);
|
||||
});
|
||||
return hasFilteredTag;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (element instanceof SettingsTreeSettingElement && this.viewState.tagFilters) {
|
||||
return element.matchesAllTags(this.viewState.tagFilters);
|
||||
}
|
||||
|
||||
if (element instanceof SettingsTreeGroupElement && this.viewState.tagFilters && this.viewState.tagFilters.size) {
|
||||
if (element instanceof SettingsTreeGroupElement) {
|
||||
if (typeof element.count === 'number') {
|
||||
return element.count > 0;
|
||||
}
|
||||
|
||||
return element.children.some(child => this.isVisible(tree, child));
|
||||
}
|
||||
|
||||
|
@ -1419,15 +1433,15 @@ export class SearchResultModel {
|
|||
return this.rawSearchResults;
|
||||
}
|
||||
|
||||
setResult(type: SearchResultIdx, result: ISearchResult): void {
|
||||
setResult(order: SearchResultIdx, result: ISearchResult): void {
|
||||
this.cachedUniqueSearchResults = null;
|
||||
this.rawSearchResults = this.rawSearchResults || [];
|
||||
if (!result) {
|
||||
delete this.rawSearchResults[type];
|
||||
delete this.rawSearchResults[order];
|
||||
return;
|
||||
}
|
||||
|
||||
this.rawSearchResults[type] = result;
|
||||
this.rawSearchResults[order] = result;
|
||||
this.updateChildren();
|
||||
}
|
||||
|
||||
|
@ -1482,6 +1496,54 @@ class NonExpandableOrSelectableTree extends Tree {
|
|||
public focusPrevious(count?: number, eventPayload?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public focusParent(eventPayload?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public focusFirstChild(eventPayload?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public focusFirst(eventPayload?: any, from?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public focusNth(index: number, eventPayload?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public focusLast(eventPayload?: any, from?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public focusNextPage(eventPayload?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public focusPreviousPage(eventPayload?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public select(element: any, eventPayload?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public selectRange(fromElement: any, toElement: any, eventPayload?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public selectAll(elements: any[], eventPayload?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public setSelection(elements: any[], eventPayload?: any): void {
|
||||
return;
|
||||
}
|
||||
|
||||
public toggleSelection(element: any, eventPayload?: any): void {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
export class SettingsTree extends NonExpandableOrSelectableTree {
|
||||
|
@ -1556,6 +1618,8 @@ export class SettingsTree extends NonExpandableOrSelectableTree {
|
|||
listFocusForeground: foreground,
|
||||
listHoverForeground: foreground,
|
||||
listHoverBackground: editorBackground,
|
||||
listHoverOutline: editorBackground,
|
||||
listFocusOutline: editorBackground,
|
||||
listInactiveSelectionBackground: editorBackground,
|
||||
listInactiveSelectionForeground: foreground
|
||||
}, colors => {
|
||||
|
|
|
@ -25,6 +25,10 @@ export class TOCTreeModel {
|
|||
private _currentSearchModel: SearchResultModel;
|
||||
private _settingsTreeRoot: SettingsTreeGroupElement;
|
||||
|
||||
constructor(private viewState: ISettingsEditorViewState) {
|
||||
|
||||
}
|
||||
|
||||
public set settingsTreeRoot(value: SettingsTreeGroupElement) {
|
||||
this._settingsTreeRoot = value;
|
||||
this.update();
|
||||
|
@ -44,7 +48,7 @@ export class TOCTreeModel {
|
|||
}
|
||||
|
||||
private updateGroupCount(group: SettingsTreeGroupElement): void {
|
||||
(<any>group).count = this._currentSearchModel ?
|
||||
group.count = this._currentSearchModel ?
|
||||
this.getSearchResultChildrenCount(group) :
|
||||
undefined;
|
||||
|
||||
|
@ -64,7 +68,7 @@ export class TOCTreeModel {
|
|||
private groupContainsSetting(group: SettingsTreeGroupElement, setting: ISetting): boolean {
|
||||
return group.children.some(child => {
|
||||
if (child instanceof SettingsTreeSettingElement) {
|
||||
return child.setting.key === setting.key;
|
||||
return child.setting.key === setting.key && child.matchesAllTags(this.viewState.tagFilters);
|
||||
} else if (child instanceof SettingsTreeGroupElement) {
|
||||
return this.groupContainsSetting(child, setting);
|
||||
} else {
|
||||
|
@ -77,11 +81,6 @@ export class TOCTreeModel {
|
|||
export type TOCTreeElement = SettingsTreeGroupElement | TOCTreeModel;
|
||||
|
||||
export class TOCDataSource implements IDataSource {
|
||||
constructor(
|
||||
@IConfigurationService private configService: IConfigurationService
|
||||
) {
|
||||
}
|
||||
|
||||
getId(tree: ITree, element: SettingsTreeGroupElement): string {
|
||||
return element.id;
|
||||
}
|
||||
|
@ -96,14 +95,6 @@ export class TOCDataSource implements IDataSource {
|
|||
}
|
||||
|
||||
private _getChildren(element: TOCTreeElement): SettingsTreeElement[] {
|
||||
// TODO@roblou hack. Clean up or remove this option
|
||||
if (this.configService.getValue('workbench.settings.settingsSearchTocBehavior') === 'filter') {
|
||||
const children = element.children as SettingsTreeElement[]; // TS????
|
||||
return children.filter(group => {
|
||||
return (<any>group).count !== 0;
|
||||
});
|
||||
}
|
||||
|
||||
return element.children;
|
||||
}
|
||||
|
||||
|
@ -136,7 +127,7 @@ export class TOCRenderer implements IRenderer {
|
|||
}
|
||||
|
||||
renderElement(tree: ITree, element: SettingsTreeGroupElement, templateId: string, template: ITOCEntryTemplate): void {
|
||||
const count = (<any>element).count;
|
||||
const count = element.count;
|
||||
const label = element.label;
|
||||
|
||||
DOM.toggleClass(template.labelElement, 'no-results', count === 0);
|
||||
|
|
|
@ -293,7 +293,7 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup {
|
|||
this.onBeforeRun(this.commandId);
|
||||
|
||||
// Use a timeout to give the quick open widget a chance to close itself first
|
||||
TPromise.timeout(50).done(() => {
|
||||
setTimeout(() => {
|
||||
if (action && (!(action instanceof Action) || action.enabled)) {
|
||||
try {
|
||||
/* __GDPR__
|
||||
|
@ -314,7 +314,7 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup {
|
|||
} else {
|
||||
this.notificationService.info(nls.localize('actionNotEnabled', "Command '{0}' is not enabled in the current context.", this.getLabel()));
|
||||
}
|
||||
}, err => this.onError(err));
|
||||
}, 50);
|
||||
}
|
||||
|
||||
private onError(error?: Error): void {
|
||||
|
|
|
@ -165,3 +165,23 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
|||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
// Go to menu
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'workbench.action.gotoSymbol',
|
||||
title: nls.localize({ key: 'miGotoSymbolInFile', comment: ['&& denotes a mnemonic'] }, "Go to &&Symbol in File...")
|
||||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'workbench.action.gotoLine',
|
||||
title: nls.localize({ key: 'miGotoLine', comment: ['&& denotes a mnemonic'] }, "Go to &&Line...")
|
||||
},
|
||||
order: 7
|
||||
});
|
|
@ -703,11 +703,16 @@ export class DirtyDiffController implements IEditorContribution {
|
|||
return;
|
||||
}
|
||||
|
||||
if (e.target.element.className.indexOf('dirty-diff-glyph') < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = e.target.detail as IMarginData;
|
||||
const gutterOffsetX = data.offsetX - data.glyphMarginWidth - data.lineNumbersWidth - data.glyphMarginLeft;
|
||||
const offsetLeftInGutter = (e.target.element as HTMLElement).offsetLeft;
|
||||
const gutterOffsetX = data.offsetX - offsetLeftInGutter;
|
||||
|
||||
// TODO@joao TODO@alex TODO@martin this is such that we don't collide with folding
|
||||
if (gutterOffsetX > 10) {
|
||||
if (gutterOffsetX < 0 || gutterOffsetX > 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
.monaco-editor .dirty-diff-glyph {
|
||||
margin-left: 5px;
|
||||
cursor: pointer;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.monaco-editor .dirty-diff-deleted:after {
|
||||
|
|
|
@ -642,3 +642,14 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
|
|||
},
|
||||
order: 2
|
||||
});
|
||||
|
||||
// Go to menu
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
|
||||
group: 'z_go_to',
|
||||
command: {
|
||||
id: 'workbench.action.showAllSymbols',
|
||||
title: nls.localize({ key: 'miGotoSymbolInWorkspace', comment: ['&& denotes a mnemonic'] }, "Go to Symbol in &&Workspace...")
|
||||
},
|
||||
order: 3
|
||||
});
|
|
@ -9,7 +9,6 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
|||
import { writeFile, exists } from 'vs/base/node/pfs';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IQuickOpenService, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { join, basename, dirname, extname } from 'path';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
|
@ -18,6 +17,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
|
|||
import URI from 'vs/base/common/uri';
|
||||
import { ISnippetsService } from 'vs/workbench/parts/snippets/electron-browser/snippets.contribution';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { IQuickPickItem, IQuickInputService, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
|
||||
|
||||
const id = 'workbench.action.openSnippets';
|
||||
|
||||
|
@ -27,7 +27,7 @@ namespace ISnippetPick {
|
|||
}
|
||||
}
|
||||
|
||||
interface ISnippetPick extends IPickOpenEntry {
|
||||
interface ISnippetPick extends IQuickPickItem {
|
||||
filepath: string;
|
||||
hint?: true;
|
||||
}
|
||||
|
@ -179,22 +179,23 @@ async function createLanguageSnippetFile(pick: ISnippetPick) {
|
|||
CommandsRegistry.registerCommand(id, async accessor => {
|
||||
|
||||
const snippetService = accessor.get(ISnippetsService);
|
||||
const quickOpenService = accessor.get(IQuickOpenService);
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
const opener = accessor.get(IOpenerService);
|
||||
const windowService = accessor.get(IWindowService);
|
||||
const modeService = accessor.get(IModeService);
|
||||
const envService = accessor.get(IEnvironmentService);
|
||||
|
||||
const { existing, future } = await computePicks(snippetService, envService, modeService);
|
||||
const newGlobalPick = <IPickOpenEntry>{ label: nls.localize('new.global', "New Global Snippets file...") };
|
||||
const picks = await computePicks(snippetService, envService, modeService);
|
||||
const existing: QuickPickInput[] = picks.existing;
|
||||
const newGlobalPick = <IQuickPickItem>{ label: nls.localize('new.global', "New Global Snippets file...") };
|
||||
if (existing.length > 0) {
|
||||
existing[0].separator = { label: nls.localize('group.global', "Existing Snippets") };
|
||||
newGlobalPick.separator = { border: true, label: nls.localize('new.global.sep', "New Snippets") };
|
||||
existing.unshift({ type: 'separator', label: nls.localize('group.global', "Existing Snippets") });
|
||||
existing.push({ type: 'separator', border: true, label: nls.localize('new.global.sep', "New Snippets") });
|
||||
} else {
|
||||
newGlobalPick.separator = { label: nls.localize('new.global.sep', "New Snippets") };
|
||||
existing.push({ type: 'separator', label: nls.localize('new.global.sep', "New Snippets") });
|
||||
}
|
||||
|
||||
const pick = await quickOpenService.pick(<(IPickOpenEntry | ISnippetPick)[]>[].concat(existing, newGlobalPick, future), {
|
||||
const pick = await quickInputService.pick(<(IQuickPickItem | ISnippetPick)[]>[].concat(existing, newGlobalPick, picks.future), {
|
||||
placeHolder: nls.localize('openSnippet.pickLanguage', "Select Snippets File or Create Snippets"),
|
||||
matchOnDescription: true
|
||||
});
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
import * as nls from 'vs/nls';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { registerEditorAction, ServicesAccessor, EditorAction } from 'vs/editor/browser/editorExtensions';
|
||||
import { IQuickOpenService, IPickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { LanguageId } from 'vs/editor/common/modes';
|
||||
import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
|
@ -16,8 +15,9 @@ import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2
|
|||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { Snippet } from 'vs/workbench/parts/snippets/electron-browser/snippetsFile';
|
||||
import { IQuickPickItem, IQuickInputService, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
|
||||
|
||||
interface ISnippetPick extends IPickOpenEntry {
|
||||
interface ISnippetPick extends IQuickPickItem {
|
||||
snippet: Snippet;
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ class InsertSnippetAction extends EditorAction {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
const quickOpenService = accessor.get(IQuickOpenService);
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
const { lineNumber, column } = editor.getPosition();
|
||||
let { snippet, name, langId } = Args.fromUser(arg);
|
||||
|
||||
|
@ -116,7 +116,7 @@ class InsertSnippetAction extends EditorAction {
|
|||
} else {
|
||||
// let user pick a snippet
|
||||
const snippets = (await snippetService.getSnippets(languageId)).sort(Snippet.compare);
|
||||
const picks: ISnippetPick[] = [];
|
||||
const picks: QuickPickInput<ISnippetPick>[] = [];
|
||||
let prevSnippet: Snippet;
|
||||
for (const snippet of snippets) {
|
||||
const pick: ISnippetPick = {
|
||||
|
@ -125,14 +125,14 @@ class InsertSnippetAction extends EditorAction {
|
|||
snippet
|
||||
};
|
||||
if (!snippet.isFromExtension && !prevSnippet) {
|
||||
pick.separator = { label: nls.localize('sep.userSnippet', "User Snippets") };
|
||||
picks.push({ type: 'separator', label: nls.localize('sep.userSnippet', "User Snippets") });
|
||||
} else if (snippet.isFromExtension && (!prevSnippet || !prevSnippet.isFromExtension)) {
|
||||
pick.separator = { label: nls.localize('sep.extSnippet', "Extension Snippets") };
|
||||
picks.push({ type: 'separator', label: nls.localize('sep.extSnippet', "Extension Snippets") });
|
||||
}
|
||||
picks.push(pick);
|
||||
prevSnippet = snippet;
|
||||
}
|
||||
return quickOpenService.pick(picks, { matchOnDetail: true }).then(pick => resolve(pick && pick.snippet), reject);
|
||||
return quickInputService.pick(picks, { matchOnDetail: true }).then(pick => resolve(pick && pick.snippet), reject);
|
||||
}
|
||||
}).then(snippet => {
|
||||
if (snippet) {
|
||||
|
|
|
@ -57,7 +57,6 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
|||
import { IStatusbarItem, IStatusbarRegistry, Extensions as StatusbarExtensions, StatusbarItemDescriptor, StatusbarAlignment } from 'vs/workbench/browser/parts/statusbar/statusbar';
|
||||
import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen';
|
||||
|
||||
import { IQuickOpenService, IPickOpenEntry, IPickOpenAction, IPickOpenItem } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import Constants from 'vs/workbench/parts/markers/electron-browser/constants';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
|
@ -90,7 +89,7 @@ import { QuickOpenActionContributor } from '../browser/quickOpen';
|
|||
|
||||
import { Themable, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput';
|
||||
|
||||
let tasksCategory = nls.localize('tasksCategory', "Tasks");
|
||||
|
||||
|
@ -425,7 +424,7 @@ class TaskMap {
|
|||
}
|
||||
}
|
||||
|
||||
interface TaskQuickPickEntry extends IPickOpenEntry {
|
||||
interface TaskQuickPickEntry extends IQuickPickItem {
|
||||
task: Task;
|
||||
}
|
||||
|
||||
|
@ -475,7 +474,6 @@ class TaskService implements ITaskService {
|
|||
@ILifecycleService lifecycleService: ILifecycleService,
|
||||
@IModelService private modelService: IModelService,
|
||||
@IExtensionService private extensionService: IExtensionService,
|
||||
@IQuickOpenService private quickOpenService: IQuickOpenService,
|
||||
@IQuickInputService private quickInputService: IQuickInputService,
|
||||
@IConfigurationResolverService private configurationResolverService: IConfigurationResolverService,
|
||||
@ITerminalService private terminalService: ITerminalService,
|
||||
|
@ -873,12 +871,12 @@ class TaskService implements ITaskService {
|
|||
}
|
||||
|
||||
private attachProblemMatcher(task: ContributedTask | CustomTask): TPromise<Task> {
|
||||
interface ProblemMatcherPickEntry extends IPickOpenEntry {
|
||||
interface ProblemMatcherPickEntry extends IQuickPickItem {
|
||||
matcher: NamedProblemMatcher;
|
||||
never?: boolean;
|
||||
learnMore?: boolean;
|
||||
}
|
||||
let entries: ProblemMatcherPickEntry[] = [];
|
||||
let entries: QuickPickInput<ProblemMatcherPickEntry>[] = [];
|
||||
for (let key of ProblemMatcherRegistry.keys()) {
|
||||
let matcher = ProblemMatcherRegistry.get(key);
|
||||
if (matcher.deprecated) {
|
||||
|
@ -896,15 +894,14 @@ class TaskService implements ITaskService {
|
|||
}
|
||||
if (entries.length > 0) {
|
||||
entries = entries.sort((a, b) => a.label.localeCompare(b.label));
|
||||
entries[0].separator = { border: true, label: nls.localize('TaskService.associate', 'associate') };
|
||||
entries.unshift({ type: 'separator', border: true, label: nls.localize('TaskService.associate', 'associate') });
|
||||
entries.unshift(
|
||||
{ label: nls.localize('TaskService.attachProblemMatcher.continueWithout', 'Continue without scanning the task output'), matcher: undefined },
|
||||
{ label: nls.localize('TaskService.attachProblemMatcher.never', 'Never scan the task output'), matcher: undefined, never: true },
|
||||
{ label: nls.localize('TaskService.attachProblemMatcher.learnMoreAbout', 'Learn more about scanning the task output'), matcher: undefined, learnMore: true }
|
||||
);
|
||||
return this.quickOpenService.pick(entries, {
|
||||
return this.quickInputService.pick(entries, {
|
||||
placeHolder: nls.localize('selectProblemMatcher', 'Select for which kind of errors and warnings to scan the task output'),
|
||||
autoFocus: { autoFocusFirstEntry: true }
|
||||
}).then((selected) => {
|
||||
if (selected) {
|
||||
if (selected.learnMore) {
|
||||
|
@ -1807,32 +1804,13 @@ class TaskService implements ITaskService {
|
|||
}
|
||||
return { label: task._label, description, task };
|
||||
};
|
||||
let taskService = this;
|
||||
let action = new class extends Action implements IPickOpenAction {
|
||||
constructor() {
|
||||
super('configureAction', 'Configure Task', 'quick-open-task-configure', true);
|
||||
function fillEntries(entries: QuickPickInput<TaskQuickPickEntry>[], tasks: Task[], groupLabel: string, withBorder: boolean = false): void {
|
||||
if (tasks.length) {
|
||||
entries.push({ type: 'separator', label: groupLabel, border: withBorder });
|
||||
}
|
||||
public run(item: IPickOpenItem): TPromise<boolean> {
|
||||
let task: Task = item.getPayload();
|
||||
taskService.quickOpenService.close();
|
||||
if (ContributedTask.is(task)) {
|
||||
taskService.customize(task, undefined, true);
|
||||
} else if (CustomTask.is(task)) {
|
||||
taskService.openConfig(task);
|
||||
}
|
||||
return TPromise.as(false);
|
||||
}
|
||||
};
|
||||
function fillEntries(entries: TaskQuickPickEntry[], tasks: Task[], groupLabel: string, withBorder: boolean = false): void {
|
||||
let first = true;
|
||||
for (let task of tasks) {
|
||||
let entry: TaskQuickPickEntry = TaskQuickPickEntry(task);
|
||||
if (first) {
|
||||
first = false;
|
||||
entry.separator = { label: groupLabel, border: withBorder };
|
||||
}
|
||||
entry.action = action;
|
||||
entry.payload = task;
|
||||
entry.buttons = [{ iconClass: 'quick-open-task-configure', tooltip: nls.localize('configureTask', "Configure Task") }];
|
||||
entries.push(entry);
|
||||
}
|
||||
}
|
||||
|
@ -1896,12 +1874,24 @@ class TaskService implements ITaskService {
|
|||
return tasks.then((tasks) => this.createTaskQuickPickEntries(tasks, group, sort));
|
||||
}
|
||||
};
|
||||
return this.quickOpenService.pick(_createEntries().then((entries) => {
|
||||
return this.quickInputService.pick(_createEntries().then((entries) => {
|
||||
if (entries.length === 0 && defaultEntry) {
|
||||
entries.push(defaultEntry);
|
||||
}
|
||||
return entries;
|
||||
}), { placeHolder, autoFocus: { autoFocusFirstEntry: true }, matchOnDescription: true }).then(entry => entry ? entry.task : undefined);
|
||||
}), {
|
||||
placeHolder,
|
||||
matchOnDescription: true,
|
||||
onDidTriggerItemButton: context => {
|
||||
let task = context.item.task;
|
||||
this.quickInputService.cancel();
|
||||
if (ContributedTask.is(task)) {
|
||||
this.customize(task, undefined, true);
|
||||
} else if (CustomTask.is(task)) {
|
||||
this.openConfig(task);
|
||||
}
|
||||
}
|
||||
}).then(entry => entry ? entry.task : undefined);
|
||||
}
|
||||
|
||||
private showIgnoredFoldersMessage(): TPromise<void> {
|
||||
|
@ -2254,8 +2244,8 @@ class TaskService implements ITaskService {
|
|||
}
|
||||
};
|
||||
|
||||
function isTaskEntry(value: IPickOpenEntry): value is IPickOpenEntry & { task: Task } {
|
||||
let candidate: IPickOpenEntry & { task: Task } = value as any;
|
||||
function isTaskEntry(value: IQuickPickItem): value is IQuickPickItem & { task: Task } {
|
||||
let candidate: IQuickPickItem & { task: Task } = value as any;
|
||||
return candidate && !!candidate.task;
|
||||
}
|
||||
|
||||
|
@ -2267,8 +2257,8 @@ class TaskService implements ITaskService {
|
|||
let openLabel = nls.localize('TaskService.openJsonFile', 'Open tasks.json file');
|
||||
let entries = TPromise.join(stats).then((stats) => {
|
||||
return taskPromise.then((taskMap) => {
|
||||
type EntryType = (IPickOpenEntry & { task: Task; }) | (IPickOpenEntry & { folder: IWorkspaceFolder; });
|
||||
let entries: EntryType[] = [];
|
||||
type EntryType = (IQuickPickItem & { task: Task; }) | (IQuickPickItem & { folder: IWorkspaceFolder; });
|
||||
let entries: QuickPickInput<EntryType>[] = [];
|
||||
if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) {
|
||||
let tasks = taskMap.all();
|
||||
let needsCreateOrOpen: boolean = true;
|
||||
|
@ -2283,7 +2273,10 @@ class TaskService implements ITaskService {
|
|||
}
|
||||
if (needsCreateOrOpen) {
|
||||
let label = stats[0] !== void 0 ? openLabel : createLabel;
|
||||
entries.push({ label, folder: this.contextService.getWorkspace().folders[0], separator: entries.length > 0 ? { border: true } : undefined });
|
||||
if (entries.length) {
|
||||
entries.push({ type: 'separator', border: true });
|
||||
}
|
||||
entries.push({ label, folder: this.contextService.getWorkspace().folders[0] });
|
||||
}
|
||||
} else {
|
||||
let folders = this.contextService.getWorkspace().folders;
|
||||
|
@ -2295,14 +2288,14 @@ class TaskService implements ITaskService {
|
|||
for (let i = 0; i < tasks.length; i++) {
|
||||
let entry: EntryType = { label: tasks[i]._label, task: tasks[i], description: folder.name };
|
||||
if (i === 0) {
|
||||
entry.separator = { label: folder.name, border: index > 0 };
|
||||
entries.push({ type: 'separator', label: folder.name, border: index > 0 });
|
||||
}
|
||||
entries.push(entry);
|
||||
}
|
||||
} else {
|
||||
let label = stats[index] !== void 0 ? openLabel : createLabel;
|
||||
let entry: EntryType = { label, folder: folder };
|
||||
entry.separator = { label: folder.name, border: index > 0 };
|
||||
entries.push({ type: 'separator', label: folder.name, border: index > 0 });
|
||||
entries.push(entry);
|
||||
}
|
||||
index++;
|
||||
|
@ -2312,8 +2305,8 @@ class TaskService implements ITaskService {
|
|||
});
|
||||
});
|
||||
|
||||
this.quickOpenService.pick(entries,
|
||||
{ placeHolder: nls.localize('TaskService.pickTask', 'Select a task to configure'), autoFocus: { autoFocusFirstEntry: true } }).
|
||||
this.quickInputService.pick(entries,
|
||||
{ placeHolder: nls.localize('TaskService.pickTask', 'Select a task to configure') }).
|
||||
then((selection) => {
|
||||
if (!selection) {
|
||||
return;
|
||||
|
|
|
@ -482,7 +482,7 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
label: nls.localize('yes', "Yes"),
|
||||
run: () => {
|
||||
this._configurationService.updateValue('terminal.integrated.rendererType', 'dom', ConfigurationTarget.USER).then(() => {
|
||||
this._notificationService.info(nls.localize('terminal.rendererInAllNewTerminals', "The termnial is now using the fallback renderer."));
|
||||
this._notificationService.info(nls.localize('terminal.rendererInAllNewTerminals', "The terminal is now using the fallback renderer."));
|
||||
});
|
||||
}
|
||||
} as IPromptChoice,
|
||||
|
|
|
@ -13,7 +13,6 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
|||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { IQuickOpenService, IPickOpenEntry, IPickOptions } from 'vs/platform/quickOpen/common/quickOpen';
|
||||
import { ITerminalInstance, ITerminalService, IShellLaunchConfig, ITerminalConfigHelper, NEVER_SUGGEST_SELECT_WINDOWS_SHELL_STORAGE_KEY, TERMINAL_PANEL_ID, ITerminalProcessExtHostProxy } from 'vs/workbench/parts/terminal/common/terminal';
|
||||
import { TerminalService as AbstractTerminalService } from 'vs/workbench/parts/terminal/common/terminalService';
|
||||
import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper';
|
||||
|
@ -29,6 +28,7 @@ import { ipcRenderer as ipc } from 'electron';
|
|||
import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
|
||||
import { TerminalInstance } from 'vs/workbench/parts/terminal/electron-browser/terminalInstance';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IQuickInputService, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput';
|
||||
|
||||
export class TerminalService extends AbstractTerminalService implements ITerminalService {
|
||||
private _configHelper: TerminalConfigHelper;
|
||||
|
@ -47,7 +47,7 @@ export class TerminalService extends AbstractTerminalService implements ITermina
|
|||
@ILifecycleService lifecycleService: ILifecycleService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@IQuickOpenService private readonly _quickOpenService: IQuickOpenService,
|
||||
@IQuickInputService private readonly _quickInputService: IQuickInputService,
|
||||
@INotificationService private readonly _notificationService: INotificationService,
|
||||
@IDialogService private readonly _dialogService: IDialogService,
|
||||
@IExtensionService private readonly _extensionService: IExtensionService
|
||||
|
@ -184,10 +184,10 @@ export class TerminalService extends AbstractTerminalService implements ITermina
|
|||
|
||||
public selectDefaultWindowsShell(): TPromise<string> {
|
||||
return this._detectWindowsShells().then(shells => {
|
||||
const options: IPickOptions = {
|
||||
const options: IPickOptions<IQuickPickItem> = {
|
||||
placeHolder: nls.localize('terminal.integrated.chooseWindowsShell', "Select your preferred terminal shell, you can change this later in your settings")
|
||||
};
|
||||
return this._quickOpenService.pick(shells, options).then(value => {
|
||||
return this._quickInputService.pick(shells, options).then(value => {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ export class TerminalService extends AbstractTerminalService implements ITermina
|
|||
});
|
||||
}
|
||||
|
||||
private _detectWindowsShells(): TPromise<IPickOpenEntry[]> {
|
||||
private _detectWindowsShells(): TPromise<IQuickPickItem[]> {
|
||||
// Determine the correct System32 path. We want to point to Sysnative
|
||||
// when the 32-bit version of VS Code is running on a 64-bit machine.
|
||||
// The reason for this is because PowerShell's important PSReadline
|
||||
|
@ -231,7 +231,7 @@ export class TerminalService extends AbstractTerminalService implements ITermina
|
|||
Object.keys(expectedLocations).forEach(key => promises.push(this._validateShellPaths(key, expectedLocations[key])));
|
||||
return TPromise.join(promises).then(results => {
|
||||
return results.filter(result => !!result).map(result => {
|
||||
return <IPickOpenEntry>{
|
||||
return <IQuickPickItem>{
|
||||
label: result[0],
|
||||
description: result[1]
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } fr
|
|||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { WelcomePageContribution, WelcomePageAction, WelcomeInputFactory } from 'vs/workbench/parts/welcome/page/electron-browser/welcomePage';
|
||||
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
|
@ -41,3 +41,12 @@ Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions)
|
|||
.registerWorkbenchAction(new SyncActionDescriptor(WelcomePageAction, WelcomePageAction.ID, WelcomePageAction.LABEL), 'Help: Welcome', localize('help', "Help"));
|
||||
|
||||
Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories).registerEditorInputFactory(WelcomeInputFactory.ID, WelcomeInputFactory);
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '1_welcome',
|
||||
command: {
|
||||
id: 'workbench.action.showWelcomePage',
|
||||
title: localize({ key: 'miWelcome', comment: ['&& denotes a mnemonic'] }, "&&Welcome")
|
||||
},
|
||||
order: 1
|
||||
});
|
||||
|
|
|
@ -14,7 +14,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
|||
import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { IEditorRegistry, Extensions as EditorExtensions, EditorDescriptor } from 'vs/workbench/browser/editor';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
|
@ -48,3 +48,12 @@ KeybindingsRegistry.registerCommandAndKeybindingRule(WalkThroughArrowDown);
|
|||
KeybindingsRegistry.registerCommandAndKeybindingRule(WalkThroughPageUp);
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule(WalkThroughPageDown);
|
||||
|
||||
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
|
||||
group: '1_welcome',
|
||||
command: {
|
||||
id: 'workbench.action.showInteractivePlayground',
|
||||
title: localize({ key: 'miInteractivePlayground', comment: ['&& denotes a mnemonic'] }, "&&Interactive Playground")
|
||||
},
|
||||
order: 2
|
||||
});
|
|
@ -37,46 +37,44 @@ export class ContextMenuService extends Disposable implements IContextMenuServic
|
|||
|
||||
showContextMenu(delegate: IContextMenuDelegate): void {
|
||||
delegate.getActions().then(actions => {
|
||||
if (!actions.length) {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
if (actions.length) {
|
||||
setTimeout(() => {
|
||||
const onHide = once(() => {
|
||||
if (delegate.onHide) {
|
||||
delegate.onHide(undefined);
|
||||
}
|
||||
|
||||
return TPromise.timeout(0).then(() => { // https://github.com/Microsoft/vscode/issues/3638
|
||||
const onHide = once(() => {
|
||||
if (delegate.onHide) {
|
||||
delegate.onHide(undefined);
|
||||
this._onDidContextMenu.fire();
|
||||
});
|
||||
|
||||
const menu = this.createMenu(delegate, actions, onHide);
|
||||
const anchor = delegate.getAnchor();
|
||||
let x: number, y: number;
|
||||
|
||||
if (dom.isHTMLElement(anchor)) {
|
||||
let elementPosition = dom.getDomNodePagePosition(anchor);
|
||||
|
||||
x = elementPosition.left;
|
||||
y = elementPosition.top + elementPosition.height;
|
||||
} else {
|
||||
const pos = <{ x: number; y: number; }>anchor;
|
||||
x = pos.x + 1; /* prevent first item from being selected automatically under mouse */
|
||||
y = pos.y;
|
||||
}
|
||||
|
||||
this._onDidContextMenu.fire();
|
||||
});
|
||||
let zoom = webFrame.getZoomFactor();
|
||||
x *= zoom;
|
||||
y *= zoom;
|
||||
|
||||
const menu = this.createMenu(delegate, actions, onHide);
|
||||
const anchor = delegate.getAnchor();
|
||||
let x: number, y: number;
|
||||
|
||||
if (dom.isHTMLElement(anchor)) {
|
||||
let elementPosition = dom.getDomNodePagePosition(anchor);
|
||||
|
||||
x = elementPosition.left;
|
||||
y = elementPosition.top + elementPosition.height;
|
||||
} else {
|
||||
const pos = <{ x: number; y: number; }>anchor;
|
||||
x = pos.x + 1; /* prevent first item from being selected automatically under mouse */
|
||||
y = pos.y;
|
||||
}
|
||||
|
||||
let zoom = webFrame.getZoomFactor();
|
||||
x *= zoom;
|
||||
y *= zoom;
|
||||
|
||||
menu.popup({
|
||||
window: remote.getCurrentWindow(),
|
||||
x: Math.floor(x),
|
||||
y: Math.floor(y),
|
||||
positioningItem: delegate.autoSelectFirstItem ? 0 : void 0,
|
||||
callback: () => onHide()
|
||||
});
|
||||
});
|
||||
menu.popup({
|
||||
window: remote.getCurrentWindow(),
|
||||
x: Math.floor(x),
|
||||
y: Math.floor(y),
|
||||
positioningItem: delegate.autoSelectFirstItem ? 0 : void 0,
|
||||
callback: () => onHide()
|
||||
});
|
||||
}, 0); // https://github.com/Microsoft/vscode/issues/3638
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ import { getScopes } from 'vs/platform/configuration/common/configurationRegistr
|
|||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
export class ExtensionHostProcessWorker {
|
||||
|
||||
|
@ -505,7 +506,7 @@ export class ExtensionHostProcessWorker {
|
|||
}
|
||||
});
|
||||
|
||||
event.veto(TPromise.timeout(100 /* wait a bit for IPC to get delivered */).then(() => false));
|
||||
event.veto(timeout(100 /* wait a bit for IPC to get delivered */).then(() => false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import { ResourceGlobMatcher } from 'vs/workbench/electron-browser/resources';
|
|||
import { Schemas } from 'vs/base/common/network';
|
||||
import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
|
||||
/**
|
||||
* Stores the selection & view state of an editor and allows to compare it to other selection states.
|
||||
|
@ -123,6 +124,9 @@ export class HistoryService extends Disposable implements IHistoryService {
|
|||
|
||||
private fileInputFactory: IFileInputFactory;
|
||||
|
||||
private canNavigateBackContextKey: IContextKey<boolean>;
|
||||
private canNavigateForwardContextKey: IContextKey<boolean>;
|
||||
|
||||
constructor(
|
||||
@IEditorService private editorService: EditorServiceImpl,
|
||||
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
|
||||
|
@ -133,12 +137,16 @@ export class HistoryService extends Disposable implements IHistoryService {
|
|||
@IFileService private fileService: IFileService,
|
||||
@IWindowsService private windowService: IWindowsService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IPartService private partService: IPartService
|
||||
@IPartService private partService: IPartService,
|
||||
@IContextKeyService private contextKeyService: IContextKeyService
|
||||
) {
|
||||
super();
|
||||
|
||||
this.activeEditorListeners = [];
|
||||
|
||||
this.canNavigateBackContextKey = (new RawContextKey<boolean>('canNavigateBack', false)).bindTo(this.contextKeyService);
|
||||
this.canNavigateForwardContextKey = (new RawContextKey<boolean>('canNavigateForward', false)).bindTo(this.contextKeyService);
|
||||
|
||||
this.fileInputFactory = Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).getFileInputFactory();
|
||||
|
||||
this.index = -1;
|
||||
|
@ -268,6 +276,8 @@ export class HistoryService extends Disposable implements IHistoryService {
|
|||
private setIndex(value: number): void {
|
||||
this.lastIndex = this.index;
|
||||
this.index = value;
|
||||
|
||||
this.updateContextKeys();
|
||||
}
|
||||
|
||||
private doForwardAcrossEditors(): void {
|
||||
|
@ -338,6 +348,13 @@ export class HistoryService extends Disposable implements IHistoryService {
|
|||
this.stack.splice(0);
|
||||
this.history = [];
|
||||
this.recentlyClosedFiles = [];
|
||||
|
||||
this.updateContextKeys();
|
||||
}
|
||||
|
||||
private updateContextKeys(): void {
|
||||
this.canNavigateBackContextKey.set(this.stack.length > 0 && this.index > 0);
|
||||
this.canNavigateForwardContextKey.set(this.stack.length > 0 && this.index < this.stack.length - 1);
|
||||
}
|
||||
|
||||
private navigate(acrossEditors?: boolean): void {
|
||||
|
@ -569,6 +586,9 @@ export class HistoryService extends Disposable implements IHistoryService {
|
|||
if (stackInput instanceof EditorInput) {
|
||||
once(stackInput.onDispose)(() => this.removeFromStack(input));
|
||||
}
|
||||
|
||||
// Context
|
||||
this.updateContextKeys();
|
||||
}
|
||||
|
||||
private preferResourceInput(input: IEditorInput): IEditorInput | IResourceInput {
|
||||
|
@ -595,6 +615,8 @@ export class HistoryService extends Disposable implements IHistoryService {
|
|||
this.stack = this.stack.filter(e => !this.matches(arg1, e.input));
|
||||
this.index = this.stack.length - 1; // reset index
|
||||
this.lastIndex = -1;
|
||||
|
||||
this.updateContextKeys();
|
||||
}
|
||||
|
||||
private removeFromRecentlyClosedFiles(arg1: IEditorInput | IResourceInput | FileChangesEvent): void {
|
||||
|
@ -659,13 +681,15 @@ export class HistoryService extends Disposable implements IHistoryService {
|
|||
|
||||
if (arg2 instanceof EditorInput) {
|
||||
const inputResource = arg2.getResource();
|
||||
|
||||
let isSupportedFile = true;
|
||||
if (this.partService.isCreated() && !this.fileService.canHandleResource(inputResource)) {
|
||||
isSupportedFile = false; // make sure to only check this when workbench has started (for https://github.com/Microsoft/vscode/issues/48275)
|
||||
if (!inputResource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return inputResource && isSupportedFile && inputResource.toString() === resource.toString();
|
||||
if (this.partService.isCreated() && !this.fileService.canHandleResource(inputResource)) {
|
||||
return false; // make sure to only check this when workbench has started (for https://github.com/Microsoft/vscode/issues/48275)
|
||||
}
|
||||
|
||||
return inputResource.toString() === resource.toString();
|
||||
}
|
||||
|
||||
const resourceInput = arg2 as IResourceInput;
|
||||
|
|
|
@ -21,6 +21,8 @@ import { Engine as TextSearchEngine } from 'vs/workbench/services/search/node/te
|
|||
import { TextSearchWorkerProvider } from 'vs/workbench/services/search/node/textSearchWorkerProvider';
|
||||
import { IFileSearchProgressItem, IRawFileMatch, IRawSearch, IRawSearchService, ISearchEngine, ISerializedFileMatch, ISerializedSearchComplete, ISerializedSearchProgressItem, ITelemetryEvent, ISerializedSearchSuccess } from './search';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { createCancelablePromise, CancelablePromise } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
gracefulFs.gracefulify(fs);
|
||||
|
||||
|
@ -55,12 +57,14 @@ export class SearchService implements IRawSearchService {
|
|||
}
|
||||
|
||||
public textSearch(config: IRawSearch): Event<ISerializedSearchProgressItem | ISerializedSearchComplete> {
|
||||
let promise: TPromise<ISerializedSearchSuccess>;
|
||||
let promise: CancelablePromise<void>;
|
||||
|
||||
const emitter = new Emitter<ISerializedSearchProgressItem | ISerializedSearchComplete>({
|
||||
onFirstListenerDidAdd: () => {
|
||||
promise = (config.useRipgrep ? this.ripgrepTextSearch(config, p => emitter.fire(p)) : this.legacyTextSearch(config, p => emitter.fire(p)))
|
||||
.then(c => emitter.fire(c), err => emitter.fire({ type: 'error', error: { message: err.message, stack: err.stack } }));
|
||||
promise = createCancelablePromise(token => {
|
||||
return (config.useRipgrep ? this.ripgrepTextSearch(config, p => emitter.fire(p), token) : this.legacyTextSearch(config, p => emitter.fire(p), token))
|
||||
.then(c => emitter.fire(c), err => emitter.fire({ type: 'error', error: { message: err.message, stack: err.stack } }));
|
||||
});
|
||||
},
|
||||
onLastListenerRemove: () => {
|
||||
promise.cancel();
|
||||
|
@ -70,11 +74,13 @@ export class SearchService implements IRawSearchService {
|
|||
return emitter.event;
|
||||
}
|
||||
|
||||
private ripgrepTextSearch(config: IRawSearch, progressCallback: IProgressCallback): TPromise<ISerializedSearchSuccess> {
|
||||
private ripgrepTextSearch(config: IRawSearch, progressCallback: IProgressCallback, token: CancellationToken): Promise<ISerializedSearchSuccess> {
|
||||
config.maxFilesize = MAX_FILE_SIZE;
|
||||
let engine = new RipgrepEngine(config);
|
||||
|
||||
return new TPromise<ISerializedSearchSuccess>((c, e) => {
|
||||
token.onCancellationRequested(() => engine.cancel());
|
||||
|
||||
return new Promise<ISerializedSearchSuccess>((c, e) => {
|
||||
// Use BatchedCollector to get new results to the frontend every 2s at least, until 50 results have been returned
|
||||
const collector = new BatchedCollector<ISerializedFileMatch>(SearchService.BATCH_SIZE, progressCallback);
|
||||
engine.search((match) => {
|
||||
|
@ -90,12 +96,10 @@ export class SearchService implements IRawSearchService {
|
|||
c(stats);
|
||||
}
|
||||
});
|
||||
}, () => {
|
||||
engine.cancel();
|
||||
});
|
||||
}
|
||||
|
||||
private legacyTextSearch(config: IRawSearch, progressCallback: IProgressCallback): TPromise<ISerializedSearchComplete> {
|
||||
private legacyTextSearch(config: IRawSearch, progressCallback: IProgressCallback, token: CancellationToken): Promise<ISerializedSearchComplete> {
|
||||
if (!this.textSearchWorkerProvider) {
|
||||
this.textSearchWorkerProvider = new TextSearchWorkerProvider();
|
||||
}
|
||||
|
@ -113,7 +117,7 @@ export class SearchService implements IRawSearchService {
|
|||
}),
|
||||
this.textSearchWorkerProvider);
|
||||
|
||||
return this.doTextSearch(engine, progressCallback, SearchService.BATCH_SIZE);
|
||||
return this.doTextSearch(engine, progressCallback, SearchService.BATCH_SIZE, token);
|
||||
}
|
||||
|
||||
doFileSearch(EngineClass: { new(config: IRawSearch): ISearchEngine<IRawFileMatch>; }, config: IRawSearch, progressCallback: IProgressCallback, batchSize?: number): TPromise<ISerializedSearchSuccess> {
|
||||
|
@ -241,6 +245,7 @@ export class SearchService implements IRawSearchService {
|
|||
const cached = this.getResultsFromCache(cache, config.filePattern, progressCallback);
|
||||
if (cached) {
|
||||
let chained: TPromise<void>;
|
||||
|
||||
return new TPromise<[ISerializedSearchSuccess, IRawFileMatch[]]>((c, e) => {
|
||||
chained = cached.then(([result, results, cacheStats]) => {
|
||||
const cacheLookupResultTime = Date.now();
|
||||
|
@ -361,8 +366,10 @@ export class SearchService implements IRawSearchService {
|
|||
});
|
||||
}
|
||||
|
||||
private doTextSearch(engine: TextSearchEngine, progressCallback: IProgressCallback, batchSize: number): TPromise<ISerializedSearchSuccess> {
|
||||
return new TPromise<ISerializedSearchSuccess>((c, e) => {
|
||||
private doTextSearch(engine: TextSearchEngine, progressCallback: IProgressCallback, batchSize: number, token: CancellationToken): Promise<ISerializedSearchSuccess> {
|
||||
token.onCancellationRequested(() => engine.cancel());
|
||||
|
||||
return new Promise<ISerializedSearchSuccess>((c, e) => {
|
||||
// Use BatchedCollector to get new results to the frontend every 2s at least, until 50 results have been returned
|
||||
const collector = new BatchedCollector<ISerializedFileMatch>(batchSize, progressCallback);
|
||||
engine.search((matches) => {
|
||||
|
@ -379,8 +386,6 @@ export class SearchService implements IRawSearchService {
|
|||
c(stats);
|
||||
}
|
||||
});
|
||||
}, () => {
|
||||
engine.cancel();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
|||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { RunOnceScheduler, timeout } from 'vs/base/common/async';
|
||||
import { ITextBufferFactory } from 'vs/editor/common/model';
|
||||
import { IHashService } from 'vs/workbench/services/hash/common/hashService';
|
||||
import { createTextBufferFactory } from 'vs/editor/common/model/textModel';
|
||||
|
@ -153,13 +153,13 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
}
|
||||
|
||||
if (fileEventImpactsModel && this.inOrphanMode !== newInOrphanModeGuess) {
|
||||
let checkOrphanedPromise: TPromise<boolean>;
|
||||
let checkOrphanedPromise: Thenable<boolean>;
|
||||
if (newInOrphanModeGuess) {
|
||||
// We have received reports of users seeing delete events even though the file still
|
||||
// exists (network shares issue: https://github.com/Microsoft/vscode/issues/13665).
|
||||
// Since we do not want to mark the model as orphaned, we have to check if the
|
||||
// file is really gone and not just a faulty file event.
|
||||
checkOrphanedPromise = TPromise.timeout(100).then(() => {
|
||||
checkOrphanedPromise = timeout(100).then(() => {
|
||||
if (this.disposed) {
|
||||
return true;
|
||||
}
|
||||
|
@ -167,10 +167,10 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil
|
|||
return this.fileService.existsFile(this.resource).then(exists => !exists);
|
||||
});
|
||||
} else {
|
||||
checkOrphanedPromise = TPromise.as(false);
|
||||
checkOrphanedPromise = Promise.resolve(false);
|
||||
}
|
||||
|
||||
checkOrphanedPromise.done(newInOrphanModeValidated => {
|
||||
checkOrphanedPromise.then(newInOrphanModeValidated => {
|
||||
if (this.inOrphanMode !== newInOrphanModeValidated && !this.disposed) {
|
||||
this.setOrphaned(newInOrphanModeValidated);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
|||
import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
import { isThenable } from 'vs/base/common/async';
|
||||
|
||||
export function SingleProxyRPCProtocol(thing: any): IExtHostContext {
|
||||
return {
|
||||
|
@ -106,7 +107,7 @@ export class TestRPCProtocol implements IExtHostContext {
|
|||
let p: Thenable<any>;
|
||||
try {
|
||||
let result = (<Function>instance[path]).apply(instance, wireArgs);
|
||||
p = TPromise.is(result) ? result : TPromise.as(result);
|
||||
p = isThenable(result) ? result : TPromise.as(result);
|
||||
} catch (err) {
|
||||
p = TPromise.wrapError(err);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
"rimraf": "^2.6.1",
|
||||
"strip-json-comments": "^2.0.1",
|
||||
"tmp": "0.0.33",
|
||||
"typescript": "2.5.2",
|
||||
"typescript": "2.9.2",
|
||||
"watch": "^1.0.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1825,9 +1825,9 @@ typedarray@^0.0.6:
|
|||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
|
||||
typescript@2.5.2:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.2.tgz#038a95f7d9bbb420b1bf35ba31d4c5c1dd3ffe34"
|
||||
typescript@2.9.2:
|
||||
version "2.9.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
|
||||
|
||||
uid-number@^0.0.6:
|
||||
version "0.0.6"
|
||||
|
|
|
@ -7933,9 +7933,9 @@ vscode-textmate@^4.0.1:
|
|||
dependencies:
|
||||
oniguruma "^7.0.0"
|
||||
|
||||
vscode-xterm@3.7.0-beta3:
|
||||
version "3.7.0-beta3"
|
||||
resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.7.0-beta3.tgz#2306f9650ee2f55637ba1804d10c5ffb9ef944f6"
|
||||
vscode-xterm@3.7.0-beta4:
|
||||
version "3.7.0-beta4"
|
||||
resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.7.0-beta4.tgz#f980d66f94f09ae80e100715dae60715dcae1ac6"
|
||||
|
||||
vso-node-api@^6.1.2-preview:
|
||||
version "6.1.2-preview"
|
||||
|
|
Loading…
Reference in a new issue