提交 489876ea 编写于 作者: P Peng Lyu

Merge remote-tracking branch 'upstream/master' into rebornix/buffer-pt

......@@ -110,8 +110,7 @@ function buildDebPackage(arch) {
return shell.task([
'chmod 755 ' + product.applicationName + '-' + debArch + '/DEBIAN/postinst ' + product.applicationName + '-' + debArch + '/DEBIAN/prerm ' + product.applicationName + '-' + debArch + '/DEBIAN/postrm',
'mkdir -p deb',
'fakeroot dpkg-deb -b ' + product.applicationName + '-' + debArch + ' deb',
'dpkg-scanpackages deb /dev/null > Packages'
'fakeroot dpkg-deb -b ' + product.applicationName + '-' + debArch + ' deb'
], { cwd: '.build/linux/deb/' + debArch });
}
......
......@@ -332,6 +332,12 @@ declare module 'vscode-xterm' {
*/
deregisterLinkMatcher(matcherId: number): void;
/**
* Enters screen reader navigation mode. This will only work when
* the screenReaderMode option is true.
*/
enterNavigationMode(): void;
/**
* Gets whether the terminal has an active selection.
*/
......
......@@ -255,7 +255,7 @@ export class ThrottledDelayer<T> extends Delayer<TPromise<T>> {
this.throttler = new Throttler();
}
trigger(promiseFactory: ITask<TPromise<T>>, delay?: number): Promise {
trigger(promiseFactory: ITask<TPromise<T>>, delay?: number): TPromise {
return super.trigger(() => this.throttler.queue(promiseFactory), delay);
}
}
......
......@@ -15,7 +15,7 @@ import { Range } from 'vs/editor/common/core/range';
import { IPosition } from 'vs/editor/common/core/position';
import { groupBy } from 'vs/base/common/arrays';
import { dispose } from 'vs/base/common/lifecycle';
import { SelectionBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, ClipboardBasedVariableResolver } from './snippetVariables';
import { SelectionBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, ClipboardBasedVariableResolver, TimeBasedVariableResolver } from './snippetVariables';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
......@@ -318,7 +318,8 @@ export class SnippetSession {
.resolveVariables(new CompositeSnippetVariableResolver([
modelBasedVariableResolver,
new ClipboardBasedVariableResolver(clipboardService, idx, indexedSelections.length),
new SelectionBasedVariableResolver(model, selection)
new SelectionBasedVariableResolver(model, selection),
new TimeBasedVariableResolver
]));
const offset = model.getOffsetAt(start) + delta;
......
......@@ -9,10 +9,17 @@ import { basename, dirname } from 'vs/base/common/paths';
import { ITextModel } from 'vs/editor/common/model';
import { Selection } from 'vs/editor/common/core/selection';
import { VariableResolver, Variable, Text } from 'vs/editor/contrib/snippet/snippetParser';
import { getLeadingWhitespace, commonPrefixLength, isFalsyOrWhitespace } from 'vs/base/common/strings';
import { getLeadingWhitespace, commonPrefixLength, isFalsyOrWhitespace, pad } from 'vs/base/common/strings';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
export const KnownSnippetVariableNames = Object.freeze({
'CURRENT_YEAR': true,
'CURRENT_YEAR_SHORT': true,
'CURRENT_MONTH': true,
'CURRENT_DATE': true,
'CURRENT_HOUR': true,
'CURRENT_MINUTE': true,
'CURRENT_SECOND': true,
'SELECTION': true,
'CLIPBOARD': true,
'TM_SELECTED_TEXT': true,
......@@ -170,3 +177,28 @@ export class ClipboardBasedVariableResolver implements VariableResolver {
}
}
}
export class TimeBasedVariableResolver implements VariableResolver {
resolve(variable: Variable): string {
const { name } = variable;
if (name === 'CURRENT_YEAR') {
return String(new Date().getFullYear());
} else if (name === 'CURRENT_YEAR_SHORT') {
return String(new Date().getFullYear()).slice(-2);
} else if (name === 'CURRENT_MONTH') {
return pad((new Date().getMonth().valueOf() + 1), 2);
} else if (name === 'CURRENT_DATE') {
return pad(new Date().getDate().valueOf(), 2);
} else if (name === 'CURRENT_HOUR') {
return pad(new Date().getHours().valueOf(), 2);
} else if (name === 'CURRENT_MINUTE') {
return pad(new Date().getMinutes().valueOf(), 2);
} else if (name === 'CURRENT_SECOND') {
return pad(new Date().getSeconds().valueOf(), 2);
}
return undefined;
}
}
......@@ -8,7 +8,7 @@ import * as assert from 'assert';
import { isWindows } from 'vs/base/common/platform';
import URI from 'vs/base/common/uri';
import { Selection } from 'vs/editor/common/core/selection';
import { SelectionBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, ClipboardBasedVariableResolver } from 'vs/editor/contrib/snippet/snippetVariables';
import { SelectionBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, ClipboardBasedVariableResolver, TimeBasedVariableResolver } from 'vs/editor/contrib/snippet/snippetVariables';
import { SnippetParser, Variable, VariableResolver } from 'vs/editor/contrib/snippet/snippetParser';
import { TextModel } from 'vs/editor/common/model/textModel';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
......@@ -261,4 +261,25 @@ suite('Snippet Variables Resolver', function () {
resolver = new ClipboardBasedVariableResolver(clipboardService, 0, 2);
assertVariableResolve(resolver, 'CLIPBOARD', 'line1');
});
function assertVariableResolve3(resolver: VariableResolver, varName: string) {
const snippet = new SnippetParser().parse(`$${varName}`);
const variable = <Variable>snippet.children[0];
assert.equal(variable.resolve(resolver), true, `${varName} failed to resolve`);
}
test('Add time variables for snippets #41631', function () {
const resolver = new TimeBasedVariableResolver;
assertVariableResolve3(resolver, 'CURRENT_YEAR');
assertVariableResolve3(resolver, 'CURRENT_YEAR_SHORT');
assertVariableResolve3(resolver, 'CURRENT_MONTH');
assertVariableResolve3(resolver, 'CURRENT_DATE');
assertVariableResolve3(resolver, 'CURRENT_HOUR');
assertVariableResolve3(resolver, 'CURRENT_MINUTE');
assertVariableResolve3(resolver, 'CURRENT_SECOND');
});
});
......@@ -57,6 +57,7 @@ import { MessageController } from 'vs/editor/contrib/message/messageController';
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IHashService } from 'vs/workbench/services/hash/common/hashService';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { IStringDictionary } from 'vs/base/common/collections';
export class PreferencesEditorInput extends SideBySideEditorInput {
public static ID: string = 'workbench.editorinputs.preferencesEditorInput';
......@@ -110,9 +111,8 @@ export class PreferencesEditor extends BaseEditor {
private preferencesRenderers: PreferencesRenderersController;
private delayedFilterLogging: Delayer<void>;
private remoteSearchThrottle: ThrottledDelayer<void>;
private remoteSearchThrottle: ThrottledDelayer<IFilterOrSearchResult>;
private latestEmptyFilters: string[] = [];
private lastFocusedWidget: SearchWidget | SideBySidePreferencesWidget = null;
constructor(
......@@ -237,16 +237,28 @@ export class PreferencesEditor extends BaseEditor {
}
private onInputChanged(): void {
this.triggerThrottledSearch();
this.localFilterPreferences();
const query = this.searchWidget.getValue().trim();
this.delayedFilterLogging.cancel();
TPromise.join([
this.preferencesRenderers.localFilterPreferences(query),
this.triggerThrottledSearch(query)
]).then(results => {
if (results) {
const [localResult, remoteResult] = results;
this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(
query,
remoteResult ? remoteResult.defaultSettingsGroupCounts : localResult.defaultSettingsGroupCounts,
remoteResult && remoteResult.metadata));
}
});
}
private triggerThrottledSearch(): void {
if (this.searchWidget.getValue()) {
this.remoteSearchThrottle.trigger(() => this.remoteSearchPreferences());
private triggerThrottledSearch(query: string): TPromise<IFilterOrSearchResult> {
if (query) {
return this.remoteSearchThrottle.trigger(() => this.preferencesRenderers.localFilterPreferences(query));
} else {
// When clearing the input, update immediately to clear it
this.remoteSearchPreferences();
return this.preferencesRenderers.remoteSearchPreferences(query);
}
}
......@@ -267,31 +279,6 @@ export class PreferencesEditor extends BaseEditor {
});
}
private remoteSearchPreferences(): TPromise<void> {
const query = this.searchWidget.getValue().trim();
return this.preferencesRenderers.remoteSearchPreferences(query).then(result => {
this.onSearchResult(query, result);
}, onUnexpectedError);
}
private localFilterPreferences(): TPromise<void> {
const query = this.searchWidget.getValue().trim();
return this.preferencesRenderers.localFilterPreferences(query).then(result => {
this.onSearchResult(query, result);
}, onUnexpectedError);
}
private onSearchResult(filter: string, result: { count: number, metadata: IFilterMetadata }): void {
if (result) {
this.showSearchResultsMessage(result.count);
if (result.count === 0) {
this.latestEmptyFilters.push(filter);
}
this.delayedFilterLogging.trigger(() => this.reportFilteringUsed(filter, result.metadata));
}
}
private showSearchResultsMessage(count: number): void {
if (this.searchWidget.getValue()) {
if (count === 0) {
......@@ -306,38 +293,28 @@ export class PreferencesEditor extends BaseEditor {
}
}
private reportFilteringUsed(filter: string, metadata?: IFilterMetadata): void {
private reportFilteringUsed(filter: string, counts: IStringDictionary<number>, metadata?: IFilterMetadata): void {
if (filter) {
let data = {
filter,
emptyFilters: this.getLatestEmptyFiltersForTelemetry(),
fuzzy: !!metadata,
duration: metadata ? metadata.duration : undefined,
context: metadata ? metadata.context : undefined
context: metadata ? metadata.context : undefined,
counts
};
this.latestEmptyFilters = [];
/* __GDPR__
"defaultSettings.filter" : {
"filter": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"emptyFilters" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"fuzzy" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"duration" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"context" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
"context" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"counts" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
this.telemetryService.publicLog('defaultSettings.filter', data);
}
}
/**
* Put a rough limit on the size of the telemetry data, since otherwise it could be an unbounded large amount
* of data. 8192 is the max size of a property value. This is rough since that probably includes ""s, etc.
*/
private getLatestEmptyFiltersForTelemetry(): string[] {
let cumulativeSize = 0;
return this.latestEmptyFilters.filter(filterText => (cumulativeSize += filterText.length) <= 8192);
}
}
class SettingsNavigator implements INavigator<ISetting> {
......@@ -374,7 +351,7 @@ class SettingsNavigator implements INavigator<ISetting> {
}
interface IFilterOrSearchResult {
count: number;
defaultSettingsGroupCounts: IStringDictionary<number>;
metadata: IFilterMetadata;
}
......@@ -387,7 +364,7 @@ class PreferencesRenderersController extends Disposable {
private _editablePreferencesRendererDisposables: IDisposable[] = [];
private _settingsNavigator: SettingsNavigator;
private _filtersInProgress: TPromise<any>[];
private _filtersInProgress: TPromise<IFilterResult>[];
private _currentLocalSearchProvider: ISearchProvider;
private _currentRemoteSearchProvider: ISearchProvider;
......@@ -466,8 +443,19 @@ class PreferencesRenderersController extends Disposable {
this._filtersInProgress = null;
const [defaultFilterResult, editableFilterResult] = results;
const count = this.consolidateAndUpdate(defaultFilterResult, editableFilterResult);
return { count, metadata: defaultFilterResult && defaultFilterResult.metadata };
this.consolidateAndUpdate(defaultFilterResult, editableFilterResult);
const result = <IFilterOrSearchResult>{
metadata: defaultFilterResult && defaultFilterResult.metadata,
defaultSettingsGroupCounts: defaultFilterResult && this._countById(defaultFilterResult.filteredGroups)
};
return result;
}, err => {
if (isPromiseCanceledError(err)) {
return null;
} else {
onUnexpectedError(err);
}
});
}
......@@ -488,7 +476,7 @@ class PreferencesRenderersController extends Disposable {
return searchP
.then<ISearchResult>(null, err => {
if (isPromiseCanceledError(err)) {
return null;
return TPromise.wrapError(err);
} else {
/* __GDPR__
"defaultSettings.searchError" : {
......@@ -521,15 +509,14 @@ class PreferencesRenderersController extends Disposable {
return TPromise.wrap(null);
}
private consolidateAndUpdate(defaultFilterResult: IFilterResult, editableFilterResult: IFilterResult): number {
private consolidateAndUpdate(defaultFilterResult: IFilterResult, editableFilterResult: IFilterResult): void {
const defaultPreferencesFilteredGroups = defaultFilterResult ? defaultFilterResult.filteredGroups : this._getAllPreferences(this._defaultPreferencesRenderer);
const editablePreferencesFilteredGroups = editableFilterResult ? editableFilterResult.filteredGroups : this._getAllPreferences(this._editablePreferencesRenderer);
const consolidatedSettings = this._consolidateSettings(editablePreferencesFilteredGroups, defaultPreferencesFilteredGroups);
this._settingsNavigator = new SettingsNavigator(this._lastQuery ? consolidatedSettings : []);
const count = consolidatedSettings.length;
this._onDidFilterResultsCountChange.fire(count);
return count;
const totalCount = consolidatedSettings.length;
this._onDidFilterResultsCountChange.fire(totalCount);
}
private _getAllPreferences(preferencesRenderer: IPreferencesRenderer<ISetting>): ISettingsGroup[] {
......@@ -571,6 +558,21 @@ class PreferencesRenderersController extends Disposable {
return settings;
}
private _countById(settingsGroups: ISettingsGroup[]): IStringDictionary<number> {
const result = {};
for (const group of settingsGroups) {
let i = 0;
for (const section of group.sections) {
i += section.settings.length;
}
result[group.id] = i;
}
return result;
}
public dispose(): void {
dispose(this._defaultPreferencesRendererDisposables);
dispose(this._editablePreferencesRendererDisposables);
......
......@@ -388,4 +388,9 @@ export interface ITerminalInstance {
* Sets the title of the terminal instance.
*/
setTitle(title: string, eventFromProcess: boolean): void;
/**
* Enter screen reader navigation mode.
*/
enterNavigationMode(): void;
}
......@@ -127,7 +127,7 @@
cursor: text;
}
.xterm .accessibility {
.xterm .xterm-accessibility {
position: absolute;
left: 0;
top: 0;
......@@ -136,10 +136,14 @@
z-index: 100;
}
.xterm .accessibility-tree {
.xterm .xterm-accessibility-tree {
color: transparent;
}
.xterm .xterm-accessibility-tree:focus [id^="xterm-active-item-"] {
outline: 1px solid #F80;
}
.xterm .live-region {
position: absolute;
left: -9999px;
......
......@@ -18,7 +18,7 @@ import { TERMINAL_DEFAULT_SHELL_UNIX_LIKE, TERMINAL_DEFAULT_SHELL_WINDOWS } from
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, CreateNewInActiveWorkspaceTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, SelectAllTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction, ShowPreviousFindTermTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, TERMINAL_PICKER_PREFIX } from 'vs/workbench/parts/terminal/electron-browser/terminalActions';
import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, CreateNewInActiveWorkspaceTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, SelectAllTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction, ShowPreviousFindTermTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, TERMINAL_PICKER_PREFIX, EnterNavigationModeTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions';
import { Registry } from 'vs/platform/registry/common/platform';
import { ShowAllCommandsAction } from 'vs/workbench/parts/quickopen/browser/commandsHandler';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
......@@ -204,6 +204,7 @@ configurationRegistry.registerConfiguration({
FocusActiveTerminalAction.ID,
FocusPreviousTerminalAction.ID,
FocusNextTerminalAction.ID,
EnterNavigationModeTerminalAction.ID,
'workbench.action.tasks.build',
'workbench.action.tasks.restartTask',
'workbench.action.tasks.runTask',
......@@ -386,6 +387,9 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DeleteWordRightT
primary: KeyMod.CtrlCmd | KeyCode.Delete,
mac: { primary: KeyMod.Alt | KeyCode.Delete }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Delete Word Right', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(EnterNavigationModeTerminalAction, EnterNavigationModeTerminalAction.ID, EnterNavigationModeTerminalAction.LABEL, {
primary: KeyMod.CtrlCmd | KeyCode.KEY_N
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Enter Navigation Mode', category);
terminalCommands.setup();
......
......@@ -196,6 +196,27 @@ export class DeleteWordRightTerminalAction extends Action {
}
}
export class EnterNavigationModeTerminalAction extends Action {
public static readonly ID = 'workbench.action.terminal.enterLineNavigationMode';
public static readonly LABEL = nls.localize('workbench.action.terminal.enterLineNavigationMode', "Enter Line Navigation Mode");
constructor(
id: string, label: string,
@ITerminalService private terminalService: ITerminalService
) {
super(id, label);
}
public run(event?: any): TPromise<any> {
let terminalInstance = this.terminalService.getActiveInstance();
if (terminalInstance) {
terminalInstance.enterNavigationMode();
}
return TPromise.as(void 0);
}
}
export class CreateNewTerminalAction extends Action {
public static readonly ID = 'workbench.action.terminal.new';
......
......@@ -1123,6 +1123,15 @@ export class TerminalInstance implements ITerminalInstance {
private _updateTheme(theme?: ITheme): void {
this._xterm.setOption('theme', this._getXtermTheme(theme));
}
public enterNavigationMode(): void {
// Perform this asynchronously as entering navigation mode will override
// the key event handlers which seemed to mess with the keybindings
// system
setTimeout(() => {
this._xterm.enterNavigationMode();
}, 100);
}
}
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
......
......@@ -5808,9 +5808,9 @@ vscode-textmate@^3.2.0:
fast-plist "^0.1.2"
oniguruma "^6.0.1"
vscode-xterm@3.1.0-beta2:
version "3.1.0-beta2"
resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.1.0-beta2.tgz#74adae19283738fab15f0ef145797f2eff5cc608"
vscode-xterm@3.1.0-beta3:
version "3.1.0-beta3"
resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.1.0-beta3.tgz#03ac017cb828ea51873c65b6c06ed045efa981ec"
vso-node-api@^6.1.2-preview:
version "6.1.2-preview"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册