提交 f2e0856e 编写于 作者: B Benjamin Pasero

Merge branch 'master' into ben/theming

......@@ -220,6 +220,8 @@ export class StandardKeyboardEvent implements IKeyboardEvent {
this.metaKey = this.metaKey || this.keyCode === KeyCode.Meta;
this._asKeybinding = this._computeKeybinding();
// console.log(`code: ${e.code}, keyCode: ${e.keyCode}, key: ${e.key}`);
}
public preventDefault(): void {
......
......@@ -97,6 +97,12 @@ class Trait<T> implements ISpliceable<boolean>, IDisposable {
DOM.toggleClass(container, this._trait, this.contains(index));
}
/**
* Sets the indexes which should have this trait.
*
* @param indexes Indexes which should have this trait.
* @return The old indexes which had this trait.
*/
set(indexes: number[]): number[] {
const result = this.indexes;
this.indexes = indexes;
......@@ -279,7 +285,7 @@ class MouseController<T> implements IDisposable {
const newSelection = selection.filter(i => i !== focus);
if (selection.length === newSelection.length) {
this.list.setSelection([...newSelection, focus].sort());
this.list.setSelection([...newSelection, focus]);
} else {
this.list.setSelection(newSelection);
}
......@@ -306,6 +312,35 @@ const DefaultOptions: IListOptions<any> = {
mouseSupport: true
};
/**
* Given two sorted collections of numbers, returns the exclusive
* disjunction between them (XOR).
*/
function exclusiveDisjunction(one: number[], other: number[]): number[] {
const result = [];
let i = 0, j = 0;
while (i < one.length || j < other.length) {
if (i >= one.length) {
result.push(other[j++]);
} else if (j >= other.length) {
result.push(one[i++]);
} else if (one[i] === other[j]) {
i++;
j++;
continue;
} else if (one[i] < other[j]) {
result.push(one[i++]);
} else {
result.push(other[j++]);
}
}
return result;
}
const numericSort = (a: number, b: number) => a - b;
export class List<T> implements ISpliceable<T>, IDisposable {
private static InstanceCount = 0;
......@@ -420,9 +455,12 @@ export class List<T> implements ISpliceable<T>, IDisposable {
}
setSelection(indexes: number[]): void {
indexes = indexes.sort(numericSort);
this.eventBufferer.bufferEvents(() => {
indexes = indexes.concat(this.selection.set(indexes));
indexes.forEach(i => this.view.splice(i, 1, [this.view.element(i)]));
const oldIndexes = this.selection.set(indexes);
const diffIndexes = exclusiveDisjunction(oldIndexes, indexes);
diffIndexes.forEach(i => this.view.splice(i, 1, [this.view.element(i)]));
});
}
......@@ -448,9 +486,12 @@ export class List<T> implements ISpliceable<T>, IDisposable {
}
setFocus(indexes: number[]): void {
indexes = indexes.sort(numericSort);
this.eventBufferer.bufferEvents(() => {
indexes = indexes.concat(this.focus.set(indexes));
indexes.forEach(i => this.view.splice(i, 1, [this.view.element(i)]));
const oldIndexes = this.focus.set(indexes);
const diffIndexes = exclusiveDisjunction(oldIndexes, indexes);
diffIndexes.forEach(i => this.view.splice(i, 1, [this.view.element(i)]));
});
}
......
......@@ -60,14 +60,13 @@ function applyEditorStyles(theme: ITheme, collector: ICssStyleCollector) {
addBackgroundColorRule(theme, '.focused .selected-text', selection, collector);
}
let inactiveSelection = theme.getColor(colorRegistry.editorInactiveSelection, false);
if (inactiveSelection) {
addBackgroundColorRule(theme, '.selected-text', inactiveSelection, collector);
} else if (selection) {
if (theme.isDefault(colorRegistry.editorInactiveSelection) && !theme.isDefault(colorRegistry.editorSelection)) {
addBackgroundColorRule(theme, '.selected-text', selection.transparent(0.5), collector);
} else {
let inactiveSelection = theme.getColor(colorRegistry.editorInactiveSelection);
addBackgroundColorRule(theme, '.selected-text', inactiveSelection, collector);
}
addBackgroundColorRule(theme, '.reference-zone-widget .ref-tree .referenceMatch', theme.getColor(referencesFindMatchHighlight), collector);
addBackgroundColorRule(theme, '.reference-zone-widget .preview .reference-decoration', theme.getColor(referencesReferenceHighlight), collector);
......
......@@ -16,12 +16,12 @@ import { DocumentHighlight, DocumentHighlightKind, DocumentHighlightProviderRegi
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Position } from 'vs/editor/common/core/position';
import * as colorRegistry from 'vs/platform/theme/common/colorRegistry';
import { registerColor, editorSelectionHighlightColor, editorBackground, editorSelection } from 'vs/platform/theme/common/colorRegistry';
import { ITheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { Color } from 'vs/base/common/color';
export const editorWordHighlight = colorRegistry.registerColor('editorWordHighlight', { dark: '#575757B8', light: '#57575740', hc: null }, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable'));
export const editorWordHighlightString = colorRegistry.registerColor('editorWordHighlightStrong', { dark: '#004972B8', light: '#0e639c40', hc: null }, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable'));
export const editorWordHighlight = registerColor('editorWordHighlight', { dark: '#575757B8', light: '#57575740', hc: null }, nls.localize('wordHighlight', 'Background color of a symbol during read-access, like reading a variable'));
export const editorWordHighlightString = registerColor('editorWordHighlightStrong', { dark: '#004972B8', light: '#0e639c40', hc: null }, nls.localize('wordHighlightStrong', 'Background color of a symbol during write-access, like writing to a variable'));
export function getOccurrencesAtPosition(model: editorCommon.IReadOnlyModel, position: Position): TPromise<DocumentHighlight[]> {
......@@ -331,19 +331,14 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
});
function getSelectionHighlightColor(theme: ITheme) {
let selectionHighlight = theme.getColor(colorRegistry.editorSelectionHighlightColor);
if (selectionHighlight) {
return selectionHighlight;
}
let selection = theme.getColor(colorRegistry.editorSelection);
let background = theme.getColor(colorRegistry.editorBackground);
if (selection && background) {
return deriveLessProminentColor(selection, background);
if (theme.isDefault(editorSelectionHighlightColor) && (!theme.isDefault(editorBackground) || !theme.isDefault(editorSelection))) {
let selection = theme.getColor(editorSelection);
let background = theme.getColor(editorBackground);
if (selection && background) {
return deriveLessProminentColor(selection, background);
}
}
return null;
return theme.getColor(editorSelectionHighlightColor);
}
function addBackgroundColorRule(theme: ITheme, selector: string, color: Color, collector: ICssStyleCollector): void {
......
......@@ -130,7 +130,7 @@ export const editorForeground = registerColor('editorForeground', { light: '#333
*/
export const editorSelection = registerColor('editorSelection', { light: '#ADD6FF', dark: '#264F78', hc: '#f3f518' }, nls.localize('editorSelection', 'Color of the editor selection'));
export const editorInactiveSelection = registerColor('editorInactiveSelection', { light: '#E5EBF1', dark: '#3A3D41', hc: null }, nls.localize('editorInactiveSelection', 'Color of the inactive editor selection'));
export const editorSelectionHighlightColor = registerColor('editorSelectionHighlightColor', { light: Color.white, dark: '#1E1E1E', hc: Color.black }, nls.localize('editorsSelectionHighlightColor', 'Background color of regions highlighted while selecting'));
export const editorSelectionHighlightColor = registerColor('editorSelectionHighlightColor', { light: '#add6ff4d', dark: '#add6ff26', hc: null }, nls.localize('editorsSelectionHighlightColor', 'Background color of regions highlighted while selecting'));
/**
* Editor find match colors.
......@@ -152,6 +152,16 @@ export function darken(colorValue: ColorValue, factor: number): ColorFunction {
};
}
export function transparent(colorValue: ColorValue, factor: number): ColorFunction {
return (theme) => {
let color = resolveColorValue(colorValue, theme);
if (color) {
return color.transparent(factor);
}
return null;
};
}
// ----- implementation
/**
......
......@@ -23,11 +23,16 @@ export interface ITheme {
/**
* Resolves the color of the given color identifer. If the theme does not
* sepcify the color, the default color is returned unless <code>useDefault</code> is set to false.
* specify the color, the default color is returned unless <code>useDefault</code> is set to false.
* @param color the id of the color
* @param useDefault specifies if the default color should be used. If not set, the default is used.
*/
getColor(color: ColorIdentifier, useDefault?: boolean): Color;
/**
* Returns wheter the current color matches the default color
*/
isDefault(color: ColorIdentifier): boolean;
}
export interface ICssStyleCollector {
......
......@@ -208,7 +208,7 @@ export class DebugActionsWidget implements IWorkbenchContribution {
const state = this.debugService.state;
const process = this.debugService.getViewModel().focusedProcess;
const attached = process && strings.equalsIgnoreCase(process.configuration.request, 'attach') && !strings.equalsIgnoreCase(process.configuration.type, 'extensionHost');
const attached = process && process.configuration.request && strings.equalsIgnoreCase(process.configuration.request, 'attach') && !strings.equalsIgnoreCase(process.configuration.type, 'extensionHost');
return this.allActions.filter(a => {
if (a.id === ContinueAction.ID) {
......
......@@ -10,7 +10,7 @@ import { Range } from 'vs/editor/common/core/range';
import { EditorContextKeys, ICommonCodeEditor } from 'vs/editor/common/editorCommon';
import { ServicesAccessor, editorAction, EditorAction, CommonEditorRegistry, EditorCommand } from 'vs/editor/common/editorCommonExtensions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IDebugService, CONTEXT_IN_DEBUG_MODE, CONTEXT_NOT_IN_DEBUG_REPL, State, REPL_ID, VIEWLET_ID, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, CONTEXT_BREAKPOINT_WIDGET_VISIBLE } from 'vs/workbench/parts/debug/common/debug';
import { IDebugService, CONTEXT_IN_DEBUG_MODE, CONTEXT_NOT_IN_DEBUG_REPL, CONTEXT_DEBUG_STATE, State, REPL_ID, VIEWLET_ID, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, CONTEXT_BREAKPOINT_WIDGET_VISIBLE } from 'vs/workbench/parts/debug/common/debug';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
......@@ -138,7 +138,7 @@ class RunToCursorAction extends EditorAction {
id: 'editor.debug.action.runToCursor',
label: nls.localize('runToCursor', "Run to Cursor"),
alias: 'Debug: Run to Cursor',
precondition: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_NOT_IN_DEBUG_REPL, EditorContextKeys.Writable),
precondition: ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, CONTEXT_NOT_IN_DEBUG_REPL, EditorContextKeys.Writable, CONTEXT_DEBUG_STATE.isEqualTo('stopped')),
menuOpts: {
group: 'debug',
order: 2
......
......@@ -226,6 +226,15 @@
padding-right: 0.8em;
}
.debug-viewlet .debug-call-stack .stack-frame.label {
text-align: center;
font-style: italic;
}
.debug-viewlet .debug-call-stack .stack-frame.label > .file {
display: none;
}
.debug-viewlet .debug-call-stack .stack-frame > .file {
float: right;
}
......
......@@ -22,6 +22,7 @@ export const VIEWLET_ID = 'workbench.view.debug';
export const REPL_ID = 'workbench.panel.repl';
export const DEBUG_SERVICE_ID = 'debugService';
export const CONTEXT_DEBUG_TYPE = new RawContextKey<string>('debugType', undefined);
export const CONTEXT_DEBUG_STATE = new RawContextKey<string>('debugState', undefined);
export const CONTEXT_IN_DEBUG_MODE = new RawContextKey<boolean>('inDebugMode', false);
export const CONTEXT_NOT_IN_DEBUG_MODE: ContextKeyExpr = CONTEXT_IN_DEBUG_MODE.toNegated();
export const CONTEXT_IN_DEBUG_REPL = new RawContextKey<boolean>('inDebugRepl', false);
......
......@@ -370,7 +370,8 @@ export class StackFrame implements IStackFrame {
}
public openInEditor(editorService: IWorkbenchEditorService, preserveFocus?: boolean, sideBySide?: boolean): TPromise<any> {
return editorService.openEditor({
return this.source.name === UNKNOWN_SOURCE_LABEL ? TPromise.as(null) : editorService.openEditor({
resource: this.source.uri,
description: this.source.origin,
options: {
......@@ -449,11 +450,13 @@ export class Thread implements IThread {
return response.body.stackFrames.map((rsf, level) => {
if (!rsf) {
return new StackFrame(this, 0, new Source({ name: UNKNOWN_SOURCE_LABEL }, true), nls.localize('unknownStack', "Unknown stack location"), null, null);
return new StackFrame(this, 0, new Source({ name: UNKNOWN_SOURCE_LABEL }, rsf.presentationHint), nls.localize('unknownStack', "Unknown stack location"), null, null);
}
let source = rsf.source ? new Source(rsf.source, rsf.source.presentationHint === 'deemphasize') : new Source({ name: UNKNOWN_SOURCE_LABEL }, true);
let source = rsf.source ? new Source(rsf.source, rsf.source.presentationHint) : new Source({ name: UNKNOWN_SOURCE_LABEL }, rsf.presentationHint);
if (this.process.sources.has(source.uri.toString())) {
source = this.process.sources.get(source.uri.toString());
const alreadyCreatedSource = this.process.sources.get(source.uri.toString());
alreadyCreatedSource.presenationHint = source.presenationHint;
source = alreadyCreatedSource;
} else {
this.process.sources.set(source.uri.toString(), source);
}
......@@ -972,7 +975,7 @@ export class Model implements IModel {
public deemphasizeSource(uri: uri): void {
this.processes.forEach(p => {
if (p.sources.has(uri.toString())) {
p.sources.get(uri.toString()).deemphasize = true;
p.sources.get(uri.toString()).presenationHint = 'deemphasize';
}
});
this._onDidChangeCallStack.fire();
......
......@@ -10,7 +10,7 @@ export class Source {
public uri: uri;
constructor(public raw: DebugProtocol.Source, public deemphasize: boolean) {
constructor(public raw: DebugProtocol.Source, public presenationHint: string) {
const path = raw.path || raw.name;
this.uri = raw.sourceReference > 0 ? uri.parse(`${DEBUG_SCHEME}:${path}`) : uri.file(path);
}
......
......@@ -100,15 +100,16 @@ export class DebugEditorContribution implements IDebugEditorContribution {
actions.push(this.instantiationService.createInstance(EnableBreakpointAction, EnableBreakpointAction.ID, EnableBreakpointAction.LABEL));
}
} else if (breakpoints.length > 1) {
actions.push(new Action(
'removeBreakpointsOnLine',
nls.localize('removeBreakpointOnLine', "Remove Breakpoints"),
const sorted = breakpoints.sort((first, second) => first.column - second.column);
actions.push(new ContextSubMenu(nls.localize('removeBreakpoints', "Remove Breakpoints"), sorted.map(bp => new Action(
'removeColumnBreakpoint',
bp.column ? nls.localize('removeBreakpointOnColumn', "Remove Breakpoint on Column {0}", bp.column) : nls.localize('removeLineBreakpoint', "Remove Line Breakpoint"),
null,
true,
() => TPromise.join(breakpoints.map(bp => this.debugService.removeBreakpoints(bp.getId())))
));
() => this.debugService.removeBreakpoints(bp.getId())
))));
actions.push(new ContextSubMenu(nls.localize('editBreakpoints', "Edit Breakpoints"), breakpoints.sort((first, second) => first.column - second.column).map(bp =>
actions.push(new ContextSubMenu(nls.localize('editBreakpoints', "Edit Breakpoints"), sorted.map(bp =>
new Action('editBreakpoint',
bp.column ? nls.localize('editBreakpointOnColumn', "Edit Breakpoint on Column {0}", bp.column) : nls.localize('editLineBrekapoint', "Edit Line Breakpoint"),
null,
......@@ -117,14 +118,14 @@ export class DebugEditorContribution implements IDebugEditorContribution {
)
)));
const disable = breakpoints.some(bp => bp.enabled);
actions.push(new Action(
disable ? 'disableBreakpoints' : 'enableBreakpoints',
disable ? nls.localize('disableBreakpoints', "Disable Breakpoints") : nls.localize('enableBreakpoints', "Enable Breakpoints"),
actions.push(new ContextSubMenu(nls.localize('enableDisableBreakpoints', "Enable/Disable Breakpoints"), sorted.map(bp => new Action(
bp.enabled ? 'disableColumnBreakpoint' : 'enableColumnBreakpoint',
bp.enabled ? (bp.column ? nls.localize('disableColumnBreakpoint', "Disable Breakpoint on Column {0}", bp.column) : nls.localize('disableBreakpointOnLine', "Disable Line Breakpoint"))
: (bp.column ? nls.localize('enableBreakpoints', "Enable Breakpoint on Column {0}", bp.column) : nls.localize('enableBreakpointOnLine', "Enable Line Breakpoint")),
null,
true,
() => TPromise.join(breakpoints.map(bp => this.debugService.enableOrDisableBreakpoints(!disable, bp)))
));
() => this.debugService.enableOrDisableBreakpoints(!bp.enabled, bp)
))));
} else {
actions.push(new Action(
'addBreakpoint',
......@@ -360,7 +361,7 @@ export class DebugEditorContribution implements IDebugEditorContribution {
const sameUri = exceptionSf.source.uri.toString() === model.uri.toString();
if (this.exceptionWidget && !sameUri) {
this.closeExceptionWidget();
} else if (focusedSf.thread.stoppedDetails.reason === 'exception' && sameUri) {
} else if (sameUri && focusedSf.thread.stoppedDetails && focusedSf.thread.stoppedDetails.reason === 'exception') {
this.showExceptionWidget(exceptionSf.lineNumber, exceptionSf.column);
}
}
......
......@@ -76,6 +76,7 @@ export class DebugService implements debug.IDebugService {
private toDisposeOnSessionEnd: Map<string, lifecycle.IDisposable[]>;
private inDebugMode: IContextKey<boolean>;
private debugType: IContextKey<string>;
private debugState: IContextKey<string>;
private breakpointsToSendOnResourceSaved: Set<string>;
constructor(
......@@ -109,6 +110,7 @@ export class DebugService implements debug.IDebugService {
this.configurationManager = this.instantiationService.createInstance(ConfigurationManager);
this.inDebugMode = debug.CONTEXT_IN_DEBUG_MODE.bindTo(contextKeyService);
this.debugType = debug.CONTEXT_DEBUG_TYPE.bindTo(contextKeyService);
this.debugState = debug.CONTEXT_DEBUG_STATE.bindTo(contextKeyService);
this.model = new Model(this.loadBreakpoints(), this.storageService.getBoolean(DEBUG_BREAKPOINTS_ACTIVATED_KEY, StorageScope.WORKSPACE, true), this.loadFunctionBreakpoints(),
this.loadExceptionBreakpoints(), this.loadWatchExpressions());
......@@ -266,7 +268,7 @@ export class DebugService implements debug.IDebugService {
}));
this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidStop(event => {
this.setStateAndEmit(session.getId(), debug.State.Stopped);
this.updateStateAndEmit(session.getId(), debug.State.Stopped);
const threadId = event.body.threadId;
session.threads().then(response => {
......@@ -288,7 +290,7 @@ export class DebugService implements debug.IDebugService {
thread.fetchCallStack().then(callStack => {
if (callStack.length > 0 && !this.viewModel.focusedStackFrame) {
// focus first stack frame from top that has source location if no other stack frame is focussed
const stackFrameToFocus = first(callStack, sf => sf.source && !sf.source.deemphasize, callStack[0]);
const stackFrameToFocus = first(callStack, sf => !!sf.source, callStack[0]);
this.focusStackFrameAndEvaluate(stackFrameToFocus).done(null, errors.onUnexpectedError);
this.windowService.getWindow().focus();
aria.alert(nls.localize('debuggingPaused', "Debugging paused, reason {0}, {1} {2}", event.body.reason, stackFrameToFocus.source ? stackFrameToFocus.source.name : '', stackFrameToFocus.lineNumber));
......@@ -326,7 +328,7 @@ export class DebugService implements debug.IDebugService {
if (this.viewModel.focusedProcess.getId() === session.getId()) {
this.focusStackFrameAndEvaluate(null, this.viewModel.focusedProcess).done(null, errors.onUnexpectedError);
}
this.setStateAndEmit(session.getId(), debug.State.Running);
this.updateStateAndEmit(session.getId(), debug.State.Running);
}));
this.toDisposeOnSessionEnd.get(session.getId()).push(session.onDidOutput(event => {
......@@ -454,13 +456,18 @@ export class DebugService implements debug.IDebugService {
return this._onDidChangeState.event;
}
private setStateAndEmit(sessionId: string, newState: debug.State): void {
if (newState === debug.State.Inactive) {
this.sessionStates.delete(sessionId);
} else {
this.sessionStates.set(sessionId, newState);
private updateStateAndEmit(sessionId?: string, newState?: debug.State): void {
if (sessionId) {
if (newState === debug.State.Inactive) {
this.sessionStates.delete(sessionId);
} else {
this.sessionStates.set(sessionId, newState);
}
}
this._onDidChangeState.fire(this.state);
const state = this.state;
this.debugState.set(debug.State[state].toLowerCase());
this._onDidChangeState.fire(state);
}
public get enabled(): boolean {
......@@ -479,7 +486,7 @@ export class DebugService implements debug.IDebugService {
}
this.viewModel.setFocusedStackFrame(stackFrame, process);
this._onDidChangeState.fire(this.state);
this.updateStateAndEmit();
return this.model.evaluateWatchExpressions(process, stackFrame);
}
......@@ -567,124 +574,124 @@ export class DebugService implements debug.IDebugService {
}
public startDebugging(configName?: string, noDebug = false): TPromise<any> {
return this.textFileService.saveAll().then(() => {
if (this.model.getProcesses().length === 0) {
this.removeReplExpressions();
}
const manager = this.getConfigurationManager();
configName = configName || this.viewModel.selectedConfigurationName;
const config = manager.getConfiguration(configName);
const compound = manager.getCompound(configName);
if (compound) {
if (!compound.configurations) {
return TPromise.wrapError(new Error(nls.localize({ key: 'compoundMustHaveConfigurations', comment: ['compound indicates a "compounds" configuration item', '"configurations" is an attribute and should not be localized'] },
"Compound must have \"configurations\" attribute set in order to start multiple configurations.")));
// make sure to save all files and that the configuration is up to date
return this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration().then(() =>
this.extensionService.onReady().then(() => {
if (this.model.getProcesses().length === 0) {
this.removeReplExpressions();
}
const manager = this.getConfigurationManager();
configName = configName || this.viewModel.selectedConfigurationName;
const config = manager.getConfiguration(configName);
const compound = manager.getCompound(configName);
if (compound) {
if (!compound.configurations) {
return TPromise.wrapError(new Error(nls.localize({ key: 'compoundMustHaveConfigurations', comment: ['compound indicates a "compounds" configuration item', '"configurations" is an attribute and should not be localized'] },
"Compound must have \"configurations\" attribute set in order to start multiple configurations.")));
}
return TPromise.join(compound.configurations.map(name => this.startDebugging(name)));
}
if (configName && !config) {
return TPromise.wrapError(new Error(nls.localize('configMissing', "Configuration '{0}' is missing in 'launch.json'.", configName)));
}
return manager.getStartSessionCommand(config ? config.type : undefined).then(commandAndType => {
if (noDebug && config) {
config.noDebug = true;
return TPromise.join(compound.configurations.map(name => this.startDebugging(name)));
}
if (configName && !config) {
return TPromise.wrapError(new Error(nls.localize('configMissing', "Configuration '{0}' is missing in 'launch.json'.", configName)));
}
if (commandAndType && commandAndType.command) {
const defaultConfig = noDebug ? { noDebug: true } : {};
return this.commandService.executeCommand(commandAndType.command, config || defaultConfig).then((result: StartSessionResult) => {
if (this.contextService.getWorkspace()) {
if (result && result.status === 'initialConfiguration') {
return manager.openConfigFile(false, commandAndType.type);
}
if (result && result.status === 'saveConfiguration') {
return this.fileService.updateContent(manager.configFileUri, result.content).then(() => manager.openConfigFile(false));
return manager.getStartSessionCommand(config ? config.type : undefined).then(commandAndType => {
if (noDebug && config) {
config.noDebug = true;
}
if (commandAndType && commandAndType.command) {
const defaultConfig = noDebug ? { noDebug: true } : {};
return this.commandService.executeCommand(commandAndType.command, config || defaultConfig).then((result: StartSessionResult) => {
if (this.contextService.getWorkspace()) {
if (result && result.status === 'initialConfiguration') {
return manager.openConfigFile(false, commandAndType.type);
}
if (result && result.status === 'saveConfiguration') {
return this.fileService.updateContent(manager.configFileUri, result.content).then(() => manager.openConfigFile(false));
}
}
}
return undefined;
});
}
return undefined;
});
}
if (config) {
return this.createProcess(config);
}
if (this.contextService.getWorkspace() && commandAndType) {
return manager.openConfigFile(false, commandAndType.type);
}
if (config) {
return this.createProcess(config);
}
if (this.contextService.getWorkspace() && commandAndType) {
return manager.openConfigFile(false, commandAndType.type);
}
return undefined;
});
});
return undefined;
});
})
));
}
public createProcess(config: debug.IConfig): TPromise<any> {
return this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration()) // make sure configuration is up to date
.then(() => this.extensionService.onReady()
.then(() => {
return this.configurationManager.resloveConfiguration(config).then(resolvedConfig => {
if (!resolvedConfig) {
// User canceled resolving of interactive variables, silently return
return undefined;
}
if (!this.configurationManager.getAdapter(resolvedConfig.type)) {
const message = resolvedConfig.type ? nls.localize('debugTypeNotSupported', "Configured debug type '{0}' is not supported.", resolvedConfig.type) :
nls.localize('debugTypeMissing', "Missing property 'type' for the chosen launch configuration.");
return TPromise.wrapError(errors.create(message, { actions: [this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL), CloseAction] }));
}
return this.textFileService.saveAll().then(() =>
this.configurationManager.resloveConfiguration(config).then(resolvedConfig => {
if (!resolvedConfig) {
// User canceled resolving of interactive variables, silently return
return undefined;
}
return this.runPreLaunchTask(resolvedConfig.preLaunchTask).then((taskSummary: ITaskSummary) => {
const errorCount = resolvedConfig.preLaunchTask ? this.markerService.getStatistics().errors : 0;
const successExitCode = taskSummary && taskSummary.exitCode === 0;
const failureExitCode = taskSummary && taskSummary.exitCode !== undefined && taskSummary.exitCode !== 0;
if (successExitCode || (errorCount === 0 && !failureExitCode)) {
return this.doCreateProcess(resolvedConfig);
}
if (!this.configurationManager.getAdapter(resolvedConfig.type)) {
const message = resolvedConfig.type ? nls.localize('debugTypeNotSupported', "Configured debug type '{0}' is not supported.", resolvedConfig.type) :
nls.localize('debugTypeMissing', "Missing property 'type' for the chosen launch configuration.");
return TPromise.wrapError(errors.create(message, { actions: [this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL), CloseAction] }));
}
this.messageService.show(severity.Error, {
message: errorCount > 1 ? nls.localize('preLaunchTaskErrors', "Build errors have been detected during preLaunchTask '{0}'.", resolvedConfig.preLaunchTask) :
errorCount === 1 ? nls.localize('preLaunchTaskError', "Build error has been detected during preLaunchTask '{0}'.", resolvedConfig.preLaunchTask) :
nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", resolvedConfig.preLaunchTask, taskSummary.exitCode),
actions: [
new Action('debug.continue', nls.localize('debugAnyway', "Debug Anyway"), null, true, () => {
this.messageService.hideAll();
return this.doCreateProcess(resolvedConfig);
}),
this.instantiationService.createInstance(ToggleMarkersPanelAction, ToggleMarkersPanelAction.ID, ToggleMarkersPanelAction.LABEL),
CloseAction
]
});
return undefined;
}, (err: TaskError) => {
if (err.code !== TaskErrors.NotConfigured) {
throw err;
}
return this.runPreLaunchTask(resolvedConfig.preLaunchTask).then((taskSummary: ITaskSummary) => {
const errorCount = resolvedConfig.preLaunchTask ? this.markerService.getStatistics().errors : 0;
const successExitCode = taskSummary && taskSummary.exitCode === 0;
const failureExitCode = taskSummary && taskSummary.exitCode !== undefined && taskSummary.exitCode !== 0;
if (successExitCode || (errorCount === 0 && !failureExitCode)) {
return this.doCreateProcess(resolvedConfig);
}
this.messageService.show(err.severity, {
message: err.message,
actions: [this.taskService.configureAction(), CloseAction]
});
});
}, err => {
if (!this.contextService.getWorkspace()) {
return this.messageService.show(severity.Error, nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved on disk and that you have a debug extension installed for that file type."));
}
this.messageService.show(severity.Error, {
message: errorCount > 1 ? nls.localize('preLaunchTaskErrors', "Build errors have been detected during preLaunchTask '{0}'.", resolvedConfig.preLaunchTask) :
errorCount === 1 ? nls.localize('preLaunchTaskError', "Build error has been detected during preLaunchTask '{0}'.", resolvedConfig.preLaunchTask) :
nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", resolvedConfig.preLaunchTask, taskSummary.exitCode),
actions: [
new Action('debug.continue', nls.localize('debugAnyway', "Debug Anyway"), null, true, () => {
this.messageService.hideAll();
return this.doCreateProcess(resolvedConfig);
}),
this.instantiationService.createInstance(ToggleMarkersPanelAction, ToggleMarkersPanelAction.ID, ToggleMarkersPanelAction.LABEL),
CloseAction
]
});
return undefined;
}, (err: TaskError) => {
if (err.code !== TaskErrors.NotConfigured) {
throw err;
}
return this.configurationManager.openConfigFile(false).then(openend => {
if (openend) {
this.messageService.show(severity.Info, nls.localize('NewLaunchConfig', "Please set up the launch configuration file for your application. {0}", err.message));
}
});
this.messageService.show(err.severity, {
message: err.message,
actions: [this.taskService.configureAction(), CloseAction]
});
}));
}
});
}, err => {
if (!this.contextService.getWorkspace()) {
return this.messageService.show(severity.Error, nls.localize('noFolderWorkspaceDebugError', "The active file can not be debugged. Make sure it is saved on disk and that you have a debug extension installed for that file type."));
}
return this.configurationManager.openConfigFile(false).then(openend => {
if (openend) {
this.messageService.show(severity.Info, nls.localize('NewLaunchConfig', "Please set up the launch configuration file for your application. {0}", err.message));
}
});
})
);
}
private doCreateProcess(configuration: debug.IConfig): TPromise<any> {
const sessionId = generateUuid();
this.setStateAndEmit(sessionId, debug.State.Initializing);
this.updateStateAndEmit(sessionId, debug.State.Initializing);
return this.telemetryService.getTelemetryInfo().then(info => {
const telemetryInfo: { [key: string]: string } = Object.create(null);
......@@ -767,7 +774,7 @@ export class DebugService implements debug.IDebugService {
if (this.model.getProcesses().length > 1) {
this.viewModel.setMultiProcessView(true);
}
this.setStateAndEmit(session.getId(), debug.State.Running);
this.updateStateAndEmit(session.getId(), debug.State.Running);
return this.telemetryService.publicLog('debugSessionStart', {
type: configuration.type,
......@@ -786,7 +793,7 @@ export class DebugService implements debug.IDebugService {
const errorMessage = error instanceof Error ? error.message : error;
this.telemetryService.publicLog('debugMisconfiguration', { type: configuration ? configuration.type : undefined, error: errorMessage });
this.setStateAndEmit(session.getId(), debug.State.Inactive);
this.updateStateAndEmit(session.getId(), debug.State.Inactive);
if (!session.disconnected) {
session.disconnect().done(null, errors.onUnexpectedError);
}
......@@ -930,7 +937,7 @@ export class DebugService implements debug.IDebugService {
if (focusedProcess && focusedProcess.getId() === session.getId()) {
this.focusStackFrameAndEvaluate(null).done(null, errors.onUnexpectedError);
}
this.setStateAndEmit(session.getId(), debug.State.Inactive);
this.updateStateAndEmit(session.getId(), debug.State.Inactive);
if (this.model.getProcesses().length === 0) {
this.partService.removeClass('debugging');
......
......@@ -524,7 +524,8 @@ export class CallStackRenderer implements IRenderer {
}
private renderStackFrame(stackFrame: debug.IStackFrame, data: IStackFrameTemplateData): void {
stackFrame.source.deemphasize ? dom.addClass(data.stackFrame, 'disabled') : dom.removeClass(data.stackFrame, 'disabled');
stackFrame.source.presenationHint === 'deemphasize' ? dom.addClass(data.stackFrame, 'disabled') : dom.removeClass(data.stackFrame, 'disabled');
stackFrame.source.presenationHint === 'label' ? dom.addClass(data.stackFrame, 'label') : dom.removeClass(data.stackFrame, 'label');
data.file.title = stackFrame.source.raw.path || stackFrame.source.name;
if (stackFrame.source.raw.origin) {
data.file.title += `\n${stackFrame.source.raw.origin}`;
......
......@@ -15,9 +15,9 @@ suite('Debug - Source', () => {
path: '/xx/yy/zz',
sourceReference: 0
};
const source = new Source(rawSource, false);
const source = new Source(rawSource, 'label');
assert.equal(source.deemphasize, false);
assert.equal(source.presenationHint, 'label');
assert.equal(source.name, rawSource.name);
assert.equal(source.inMemory, false);
assert.equal(source.reference, rawSource.sourceReference);
......@@ -29,9 +29,9 @@ suite('Debug - Source', () => {
name: 'internalModule.js',
sourceReference: 11
};
const source = new Source(rawSource, true);
const source = new Source(rawSource, 'deemphasize');
assert.equal(source.deemphasize, true);
assert.equal(source.presenationHint, 'deemphasize');
assert.equal(source.name, rawSource.name);
assert.equal(source.inMemory, true);
assert.equal(source.reference, rawSource.sourceReference);
......
......@@ -410,4 +410,6 @@ export const enum KeyboardEventCode {
MailReply,
MailForward,
MailSend,
MAX_VALUE
}
\ No newline at end of file
......@@ -6,10 +6,12 @@
'use strict';
import { OperatingSystem } from 'vs/base/common/platform';
import { SimpleKeybinding, KeyCode } from 'vs/base/common/keyCodes';
import { SimpleKeybinding, KeyCode, ResolvedKeybinding, Keybinding, KeyCodeUtils } from 'vs/base/common/keyCodes';
import { KeyboardEventCode, KeyboardEventCodeUtils } from 'vs/workbench/services/keybinding/common/keyboardEventCode';
import { PrintableKeypress } from 'vs/platform/keybinding/common/keybindingLabels';
import { CharCode } from 'vs/base/common/charCode';
import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/abstractKeybindingService';
import { IHTMLContentElement } from 'vs/base/common/htmlContent';
import { PrintableKeypress, UILabelProvider, AriaLabelProvider } from 'vs/platform/keybinding/common/keybindingLabels';
export interface IKeyMapping {
value: string;
......@@ -27,10 +29,23 @@ export interface IKeyboardMapping {
[code: string]: IKeyMapping;
}
const LOG = false;
function log(str: string): void {
if (LOG) {
console.info(str);
}
}
function cannotMapSimpleKeybinding(keybinding: SimpleKeybinding, OS: OperatingSystem, reason: string): void {
let usLayout = new USLayoutResolvedKeybinding(keybinding, OS);
log(`No key combination can produce desired simple keybinding: ${usLayout.getUserSettingsLabel()} - ${reason}.`);
}
/**
* -1 if a KeyCode => keyboardEvent.code mapping depends on kb layout.
*/
const IMMUTABLE_KEY_CODE_TO_CODE: KeyboardEventCode[] = [];
const IMMUTABLE_CODE_TO_KEY_CODE: KeyCode[] = [];
/**
* Chars that will be remapped.
......@@ -118,17 +133,107 @@ const enum ModifierState {
ShiftAltGr = 3
}
interface KeyCombo {
code: KeyboardEventCode;
mod: ModifierState;
export class HardwareKeypress {
readonly ctrlKey: boolean;
readonly shiftKey: boolean;
readonly altKey: boolean;
readonly metaKey: boolean;
readonly code: KeyboardEventCode;
constructor(ctrlKey: boolean, shiftKey: boolean, altKey: boolean, metaKey: boolean, code: KeyboardEventCode) {
this.ctrlKey = ctrlKey;
this.shiftKey = shiftKey;
this.altKey = altKey;
this.metaKey = metaKey;
this.code = code;
}
public toPrintableKeypress(key: string): PrintableKeypress {
return new PrintableKeypress(this.ctrlKey, this.shiftKey, this.altKey, this.metaKey, key);
}
}
export class NativeResolvedKeybinding extends ResolvedKeybinding {
private readonly _mapper: KeyboardMapper;
private readonly _OS: OperatingSystem;
private readonly _firstPart: HardwareKeypress;
private readonly _chordPart: HardwareKeypress;
constructor(mapper: KeyboardMapper, OS: OperatingSystem, firstPart: HardwareKeypress, chordPart: HardwareKeypress) {
super();
this._mapper = mapper;
this._OS = OS;
this._firstPart = firstPart;
this._chordPart = chordPart;
}
public getLabel(): string {
let firstPart = this._firstPart.toPrintableKeypress(this._mapper.getUILabelForHardwareCode(this._firstPart.code));
let chordPart = this._chordPart ? this._chordPart.toPrintableKeypress(this._mapper.getUILabelForHardwareCode(this._chordPart.code)) : null;
return UILabelProvider.toLabel2(firstPart, chordPart, this._OS);
}
public getAriaLabel(): string {
let firstPart = this._firstPart.toPrintableKeypress(this._mapper.getAriaLabelForHardwareCode(this._firstPart.code));
let chordPart = this._chordPart ? this._chordPart.toPrintableKeypress(this._mapper.getAriaLabelForHardwareCode(this._chordPart.code)) : null;
return AriaLabelProvider.toLabel2(firstPart, chordPart, this._OS);
}
public getHTMLLabel(): IHTMLContentElement[] {
let firstPart = this._firstPart.toPrintableKeypress(this._mapper.getUILabelForHardwareCode(this._firstPart.code));
let chordPart = this._chordPart ? this._chordPart.toPrintableKeypress(this._mapper.getUILabelForHardwareCode(this._chordPart.code)) : null;
return UILabelProvider.toHTMLLabel2(firstPart, chordPart, this._OS);
}
public getElectronAccelerator(): string {
throw new Error('TODO!');
// const usResolvedKeybinding = new USLayoutResolvedKeybinding(this._actual, OS);
// if (OS === OperatingSystem.Windows) {
// // electron menus always do the correct rendering on Windows
// return usResolvedKeybinding.getElectronAccelerator();
// }
// let usLabel = usResolvedKeybinding.getLabel();
// let label = this.getLabel();
// if (usLabel !== label) {
// // electron menus are incorrect in rendering (linux) and in rendering and interpreting (mac)
// // for non US standard keyboard layouts
// return null;
// }
// return usResolvedKeybinding.getElectronAccelerator();
}
public getUserSettingsLabel(): string {
throw new Error('TODO!');
// return KeybindingIO.writeKeybinding(this._actual, OS);
}
}
interface IHardwareCodeMapping {
value: number;
withShift: number;
withAltGr: number;
withShiftAltGr: number;
valueIsDeadKey: boolean;
withShiftIsDeadKey: boolean;
withAltGrIsDeadKey: boolean;
withShiftAltGrIsDeadKey: boolean;
}
export class KeyboardMapper {
private readonly _OS: OperatingSystem;
private readonly _remapChars: KeyCombo[];
private readonly _remapChars: HardwareKeypress[][];
private readonly _mappings: IHardwareCodeMapping[];
constructor(mapping: IKeyboardMapping, OS: OperatingSystem) {
constructor(mappings: IKeyboardMapping, OS: OperatingSystem) {
this._remapChars = [];
let maxCharCode = REMAP_CHARS.reduce((prev, curr) => Math.max(prev, curr));
......@@ -136,20 +241,37 @@ export class KeyboardMapper {
this._remapChars[i] = null;
}
for (let strCode in mapping) {
if (mapping.hasOwnProperty(strCode)) {
this._mappings = [];
for (let strCode in mappings) {
if (mappings.hasOwnProperty(strCode)) {
const code = KeyboardEventCodeUtils.toEnum(strCode);
if (code === KeyboardEventCode.None) {
console.warn(`Unknown code ${strCode} in mapping.`);
log(`Unknown code ${strCode} in mapping.`);
continue;
}
const results = mapping[strCode];
this._register(code, ModifierState.None, results.value);
this._register(code, ModifierState.Shift, results.withShift);
this._register(code, ModifierState.AltGr, results.withAltGr);
this._register(code, ModifierState.ShiftAltGr, results.withShiftAltGr);
const mapping = mappings[strCode];
const value = KeyboardMapper._getCharCode(mapping.value);
const withShift = KeyboardMapper._getCharCode(mapping.withShift);
const withAltGr = KeyboardMapper._getCharCode(mapping.withAltGr);
const withShiftAltGr = KeyboardMapper._getCharCode(mapping.withShiftAltGr);
this._mappings[code] = {
value: value,
withShift: withShift,
withAltGr: withAltGr,
withShiftAltGr: withShiftAltGr,
valueIsDeadKey: mapping.valueIsDeadKey,
withShiftIsDeadKey: mapping.withShiftIsDeadKey,
withAltGrIsDeadKey: mapping.withAltGrIsDeadKey,
withShiftAltGrIsDeadKey: mapping.withShiftAltGrIsDeadKey,
};
this._register(code, false, false, false, value);
this._register(code, false, true, false, withShift);
this._register(code, true, false, true, withAltGr);
this._register(code, true, true, true, withShiftAltGr);
}
}
......@@ -157,17 +279,56 @@ export class KeyboardMapper {
for (let i = 0; i < REMAP_CHARS.length; i++) {
const charCode = REMAP_CHARS[i];
if (!this._remapChars[charCode]) {
// console.info(`Could not find any key combination producing '${String.fromCharCode(charCode)}'`);
let combos = this._remapChars[charCode];
if (combos === null) {
log(`Could not find any key combination producing '${String.fromCharCode(charCode)}'`);
} else if (combos.length > 1) {
combos.sort((a, b) => {
let aModCnt = (a.ctrlKey ? 1 : 0) + (a.altKey ? 1 : 0) + (a.shiftKey ? 1 : 0) + (a.metaKey ? 1 : 0);
let bModCnt = (b.ctrlKey ? 1 : 0) + (b.altKey ? 1 : 0) + (b.shiftKey ? 1 : 0) + (b.metaKey ? 1 : 0);
if (aModCnt === bModCnt) {
return a.code - b.code;
}
return aModCnt - bModCnt;
});
}
}
}
private _register(code: KeyboardEventCode, mod: ModifierState, char: string): void {
private static _getCharCode(char: string): number {
if (char.length === 0) {
return 0;
}
return this._combiningToRegularCharCode(char.charCodeAt(0));
}
/**
* Attempt to map a combining character to a regular one that renders the same way.
*
* To the brave person following me: Good Luck!
* https://www.compart.com/en/unicode/bidiclass/NSM
*/
private static _combiningToRegularCharCode(charCode: number): number {
switch (charCode) {
case CharCode.U_Combining_Grave_Accent: return CharCode.U_GRAVE_ACCENT;
case CharCode.U_Combining_Acute_Accent: return CharCode.U_ACUTE_ACCENT;
case CharCode.U_Combining_Circumflex_Accent: return CharCode.U_CIRCUMFLEX;
case CharCode.U_Combining_Tilde: return CharCode.U_SMALL_TILDE;
case CharCode.U_Combining_Macron: return CharCode.U_MACRON;
case CharCode.U_Combining_Overline: return CharCode.U_OVERLINE;
case CharCode.U_Combining_Breve: return CharCode.U_BREVE;
case CharCode.U_Combining_Dot_Above: return CharCode.U_DOT_ABOVE;
case CharCode.U_Combining_Diaeresis: return CharCode.U_DIAERESIS;
case CharCode.U_Combining_Ring_Above: return CharCode.U_RING_ABOVE;
case CharCode.U_Combining_Double_Acute_Accent: return CharCode.U_DOUBLE_ACUTE_ACCENT;
}
return charCode;
}
private _register(code: KeyboardEventCode, ctrlKey: boolean, shiftKey: boolean, altKey: boolean, charCode: number): void {
if (charCode === 0) {
return;
}
const charCode = char.charCodeAt(0);
if (REMAP_CHARS.indexOf(charCode) === -1) {
return;
......@@ -175,44 +336,62 @@ export class KeyboardMapper {
if (REMAP_KEYBOARD_EVENT_CODES.indexOf(code) === -1) {
return;
}
if (this._remapChars[charCode]) {
// console.info(`Multiple key combinations can produce '${char}'`);
// already remaped
let entry = new HardwareKeypress(ctrlKey, shiftKey, altKey, false, code);
if (this._remapChars[charCode] === null) {
// no duplicates so far
this._remapChars[charCode] = [entry];
return;
}
this._remapChars[charCode] = {
code: code,
mod: mod
};
const list = this._remapChars[charCode];
// Do not register if it already sits under the same code
for (let i = 0, len = list.length; i < len; i++) {
if (list[i].code === code) {
return;
}
}
list.push(entry);
}
private _mapSimpleKeybinding(ctrlKey: boolean, altKey: boolean, metaKey: boolean, charCode: number): PrintableKeypress {
const keyCombo = this._remapChars[charCode];
if (!keyCombo) {
console.info('Cannot produce desired kb...');
private _doMapSimpleKeybinding(source: SimpleKeybinding, keyCombo: HardwareKeypress, ctrlKey: boolean, altKey: boolean, metaKey: boolean, charCode: number): HardwareKeypress {
if ((keyCombo.ctrlKey && ctrlKey) || (keyCombo.altKey && altKey)) {
cannotMapSimpleKeybinding(source, this._OS, `ctrl or alt modifiers are needed to produce '${String.fromCharCode(charCode)}'`);
return null;
}
// console.log(`_mapSimpleKeybinding ctrlKey: ${ctrlKey}, altKey: ${altKey}, metaKey: ${metaKey}, char: ${String.fromCharCode(charCode)}`);
// console.log(` => ${KeyboardEventCodeUtils.toString(keyCombo.code)}, ${keyCombo.mod}`);
const shiftKey = keyCombo.shiftKey;
if (keyCombo.ctrlKey) {
ctrlKey = true;
}
if (keyCombo.altKey) {
altKey = true;
}
let shiftKey = false;
if (keyCombo.mod === ModifierState.Shift) {
shiftKey = true;
} else if (keyCombo.mod === ModifierState.AltGr) {
console.error('TODO');
console.log(`_mapSimpleKeybinding ctrlKey: ${ctrlKey}, altKey: ${altKey}, metaKey: ${metaKey}, char: ${String.fromCharCode(charCode)}`);
console.log(` => ${KeyboardEventCodeUtils.toString(keyCombo.code)}, ${keyCombo.mod}`);
return null;
} else if (keyCombo.mod === ModifierState.ShiftAltGr) {
console.error('TODO');
return null;
return new HardwareKeypress(ctrlKey, shiftKey, altKey, metaKey, keyCombo.code);
}
private _mapSimpleKeybinding(source: SimpleKeybinding, ctrlKey: boolean, altKey: boolean, metaKey: boolean, charCode: number): HardwareKeypress[] {
const keyCombos = this._remapChars[charCode];
let result: HardwareKeypress[] = [], resultLen = 0;
if (keyCombos !== null) {
for (let i = 0, len = keyCombos.length; i < len; i++) {
const keyCombo = keyCombos[i];
let oneResult = this._doMapSimpleKeybinding(source, keyCombo, ctrlKey, altKey, metaKey, charCode);
if (oneResult !== null) {
result[resultLen++] = oneResult;
}
}
} else {
cannotMapSimpleKeybinding(source, this._OS, `'${String.fromCharCode(charCode)}' cannot be produced`);
}
return new PrintableKeypress(ctrlKey, shiftKey, altKey, metaKey, KeyboardEventCodeUtils.toString(keyCombo.code));
return result;
}
public mapSimpleKeybinding(keybinding: SimpleKeybinding): PrintableKeypress {
public mapSimpleKeybinding(keybinding: SimpleKeybinding): HardwareKeypress[] {
const ctrlCmd = keybinding.hasCtrlCmd();
const winCtrl = keybinding.hasWinCtrl();
......@@ -224,7 +403,7 @@ export class KeyboardMapper {
if (IMMUTABLE_KEY_CODE_TO_CODE[keyCode] !== -1) {
const keyboardEventCode = IMMUTABLE_KEY_CODE_TO_CODE[keyCode];
return new PrintableKeypress(ctrlKey, shiftKey, altKey, metaKey, KeyboardEventCodeUtils.toString(keyboardEventCode));
return [new HardwareKeypress(ctrlKey, shiftKey, altKey, metaKey, keyboardEventCode)];
}
let desiredCharCode = 0;
......@@ -276,24 +455,96 @@ export class KeyboardMapper {
if (desiredCharCode === 0) {
// OEM_8 = 91,
// OEM_102 = 92,
console.info('Cannot produce desired kb...');
cannotMapSimpleKeybinding(keybinding, this._OS, `unknown character`);
return null;
}
return this._mapSimpleKeybinding(ctrlKey, altKey, metaKey, desiredCharCode);
return this._mapSimpleKeybinding(keybinding, ctrlKey, altKey, metaKey, desiredCharCode);
}
public getUILabelForHardwareCode(code: KeyboardEventCode): string {
return this._getLabelForHardwareCode(code, true);
}
public getAriaLabelForHardwareCode(code: KeyboardEventCode): string {
return this._getLabelForHardwareCode(code, false);
}
private _getLabelForHardwareCode(code: KeyboardEventCode, isUI: boolean): string {
if (isUI && this._OS === OperatingSystem.Macintosh) {
switch (code) {
case KeyboardEventCode.ArrowLeft:
return '';
case KeyboardEventCode.ArrowUp:
return '';
case KeyboardEventCode.ArrowRight:
return '';
case KeyboardEventCode.ArrowDown:
return '';
}
}
if (IMMUTABLE_CODE_TO_KEY_CODE[code] !== -1) {
const keyCode = IMMUTABLE_CODE_TO_KEY_CODE[code];
return KeyCodeUtils.toString(keyCode);
}
const mapping = this._mappings[code];
if (!mapping) {
// uh-oh
return 'Unknown';
}
if (mapping.value >= CharCode.a && mapping.value <= CharCode.z) {
return String.fromCharCode(CharCode.A + (mapping.value - CharCode.a));
}
if (mapping.value) {
return String.fromCharCode(mapping.value);
}
throw new Error('TODO!');
}
public resolveKeybinding(keybinding: Keybinding): NativeResolvedKeybinding[] {
let result: NativeResolvedKeybinding[] = [], resultLen = 0;
if (keybinding.isChord()) {
const firstParts = this.mapSimpleKeybinding(keybinding.extractFirstPart());
const chordParts = this.mapSimpleKeybinding(keybinding.extractChordPart());
for (let i = 0, len = firstParts.length; i < len; i++) {
const firstPart = firstParts[i];
for (let j = 0, lenJ = chordParts.length; j < lenJ; j++) {
const chordPart = chordParts[j];
result[resultLen++] = new NativeResolvedKeybinding(this, this._OS, firstPart, chordPart);
}
}
} else {
const firstParts = this.mapSimpleKeybinding(keybinding);
for (let i = 0, len = firstParts.length; i < len; i++) {
const firstPart = firstParts[i];
result[resultLen++] = new NativeResolvedKeybinding(this, this._OS, firstPart, null);
}
}
return result;
}
}
(function () {
let currentLength = 0;
for (let i = 0; i <= KeyCode.MAX_VALUE; i++) {
IMMUTABLE_KEY_CODE_TO_CODE[i] = -1;
}
for (let i = 0; i <= KeyboardEventCode.MAX_VALUE; i++) {
IMMUTABLE_CODE_TO_KEY_CODE[i] = -1;
}
function d(keyCode: KeyCode, code: KeyboardEventCode): void {
if (keyCode > currentLength) {
for (let i = currentLength; i < keyCode; i++) {
IMMUTABLE_KEY_CODE_TO_CODE[i] = -1;
}
}
IMMUTABLE_KEY_CODE_TO_CODE[keyCode] = code;
currentLength = keyCode + 1;
IMMUTABLE_CODE_TO_KEY_CODE[code] = keyCode;
}
// Unknown = 0,
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { IKeyboardMapping } from 'vs/workbench/services/keybinding/common/keyboardMapper';
export const linux_de_ch: IKeyboardMapping = {
Sleep: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
WakeUp: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
KeyA: {
value: 'a',
withShift: 'A',
withAltGr: 'æ',
withShiftAltGr: 'Æ'
},
KeyB: {
value: 'b',
withShift: 'B',
withAltGr: '',
withShiftAltGr: ''
},
KeyC: {
value: 'c',
withShift: 'C',
withAltGr: '¢',
withShiftAltGr: '©'
},
KeyD: {
value: 'd',
withShift: 'D',
withAltGr: 'ð',
withShiftAltGr: 'Ð'
},
KeyE: {
value: 'e',
withShift: 'E',
withAltGr: '',
withShiftAltGr: 'E'
},
KeyF: {
value: 'f',
withShift: 'F',
withAltGr: 'đ',
withShiftAltGr: 'ª'
},
KeyG: {
value: 'g',
withShift: 'G',
withAltGr: 'ŋ',
withShiftAltGr: 'Ŋ'
},
KeyH: {
value: 'h',
withShift: 'H',
withAltGr: 'ħ',
withShiftAltGr: 'Ħ'
},
KeyI: {
value: 'i',
withShift: 'I',
withAltGr: '',
withShiftAltGr: 'ı'
},
KeyJ: {
value: 'j',
withShift: 'J',
withAltGr: '̉',
withShiftAltGr: '̛'
},
KeyK: {
value: 'k',
withShift: 'K',
withAltGr: 'ĸ',
withShiftAltGr: '&'
},
KeyL: {
value: 'l',
withShift: 'L',
withAltGr: 'ł',
withShiftAltGr: 'Ł'
},
KeyM: {
value: 'm',
withShift: 'M',
withAltGr: 'µ',
withShiftAltGr: 'º'
},
KeyN: {
value: 'n',
withShift: 'N',
withAltGr: 'n',
withShiftAltGr: 'N'
},
KeyO: {
value: 'o',
withShift: 'O',
withAltGr: 'œ',
withShiftAltGr: 'Œ'
},
KeyP: {
value: 'p',
withShift: 'P',
withAltGr: 'þ',
withShiftAltGr: 'Þ'
},
KeyQ: {
value: 'q',
withShift: 'Q',
withAltGr: '@',
withShiftAltGr: 'Ω'
},
KeyR: {
value: 'r',
withShift: 'R',
withAltGr: '',
withShiftAltGr: '®'
},
KeyS: {
value: 's',
withShift: 'S',
withAltGr: 'ß',
withShiftAltGr: '§'
},
KeyT: {
value: 't',
withShift: 'T',
withAltGr: 'ŧ',
withShiftAltGr: 'Ŧ'
},
KeyU: {
value: 'u',
withShift: 'U',
withAltGr: '',
withShiftAltGr: ''
},
KeyV: {
value: 'v',
withShift: 'V',
withAltGr: '',
withShiftAltGr: ''
},
KeyW: {
value: 'w',
withShift: 'W',
withAltGr: 'ł',
withShiftAltGr: 'Ł'
},
KeyX: {
value: 'x',
withShift: 'X',
withAltGr: '»',
withShiftAltGr: '>'
},
KeyY: {
value: 'z',
withShift: 'Z',
withAltGr: '',
withShiftAltGr: '¥'
},
KeyZ: {
value: 'y',
withShift: 'Y',
withAltGr: '«',
withShiftAltGr: '<'
},
Digit1: {
value: '1',
withShift: '+',
withAltGr: '|',
withShiftAltGr: '¡'
},
Digit2: {
value: '2',
withShift: '"',
withAltGr: '@',
withShiftAltGr: ''
},
Digit3: {
value: '3',
withShift: '*',
withAltGr: '#',
withShiftAltGr: '£'
},
Digit4: {
value: '4',
withShift: 'ç',
withAltGr: '¼',
withShiftAltGr: '$'
},
Digit5: {
value: '5',
withShift: '%',
withAltGr: '½',
withShiftAltGr: ''
},
Digit6: {
value: '6',
withShift: '&',
withAltGr: '¬',
withShiftAltGr: ''
},
Digit7: {
value: '7',
withShift: '/',
withAltGr: '|',
withShiftAltGr: ''
},
Digit8: {
value: '8',
withShift: '(',
withAltGr: '¢',
withShiftAltGr: ''
},
Digit9: {
value: '9',
withShift: ')',
withAltGr: ']',
withShiftAltGr: '±'
},
Digit0: {
value: '0',
withShift: '=',
withAltGr: '}',
withShiftAltGr: '°'
},
Enter: {
value: '\r',
withShift: '\r',
withAltGr: '\r',
withShiftAltGr: '\r'
},
Escape: {
value: '\u001b',
withShift: '\u001b',
withAltGr: '\u001b',
withShiftAltGr: '\u001b'
},
Backspace: {
value: '\b',
withShift: '\b',
withAltGr: '\b',
withShiftAltGr: '\b'
},
Tab: {
value: '\t',
withShift: '',
withAltGr: '\t',
withShiftAltGr: ''
},
Space: {
value: ' ',
withShift: ' ',
withAltGr: ' ',
withShiftAltGr: ' '
},
Minus: {
value: '\'',
withShift: '?',
withAltGr: '́',
withShiftAltGr: '¿'
},
Equal: {
value: '̂',
withShift: '̀',
withAltGr: '̃',
withShiftAltGr: '̨'
},
BracketLeft: {
value: 'ü',
withShift: 'è',
withAltGr: '[',
withShiftAltGr: '̊'
},
BracketRight: {
value: '̈',
withShift: '!',
withAltGr: ']',
withShiftAltGr: '̄'
},
Backslash: {
value: '$',
withShift: '£',
withAltGr: '}',
withShiftAltGr: '̆'
},
Semicolon: {
value: 'ö',
withShift: 'é',
withAltGr: '́',
withShiftAltGr: '̋'
},
Quote: {
value: 'ä',
withShift: 'à',
withAltGr: '{',
withShiftAltGr: '̌'
},
Backquote: {
value: '§',
withShift: '°',
withAltGr: '¬',
withShiftAltGr: '¬'
},
Comma: {
value: ',',
withShift: ';',
withAltGr: '',
withShiftAltGr: '×'
},
Period: {
value: '.',
withShift: ':',
withAltGr: '·',
withShiftAltGr: '÷'
},
Slash: {
value: '-',
withShift: '_',
withAltGr: '̣',
withShiftAltGr: '̇'
},
CapsLock: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F1: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F2: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F3: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F4: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F5: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F6: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F7: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F8: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F9: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F10: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F11: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F12: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
PrintScreen: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
ScrollLock: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Pause: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Insert: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Home: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
PageUp: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Delete: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
End: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
PageDown: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
ArrowRight: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
ArrowLeft: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
ArrowDown: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
ArrowUp: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
NumLock: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
NumpadDivide: {
value: '/',
withShift: '/',
withAltGr: '/',
withShiftAltGr: '/'
},
NumpadMultiply: {
value: '*',
withShift: '*',
withAltGr: '*',
withShiftAltGr: '*'
},
NumpadSubtract: {
value: '-',
withShift: '-',
withAltGr: '-',
withShiftAltGr: '-'
},
NumpadAdd: {
value: '+',
withShift: '+',
withAltGr: '+',
withShiftAltGr: '+'
},
NumpadEnter: {
value: '\r',
withShift: '\r',
withAltGr: '\r',
withShiftAltGr: '\r'
},
Numpad1: { value: '', withShift: '1', withAltGr: '', withShiftAltGr: '1' },
Numpad2: { value: '', withShift: '2', withAltGr: '', withShiftAltGr: '2' },
Numpad3: { value: '', withShift: '3', withAltGr: '', withShiftAltGr: '3' },
Numpad4: { value: '', withShift: '4', withAltGr: '', withShiftAltGr: '4' },
Numpad5: { value: '', withShift: '5', withAltGr: '', withShiftAltGr: '5' },
Numpad6: { value: '', withShift: '6', withAltGr: '', withShiftAltGr: '6' },
Numpad7: { value: '', withShift: '7', withAltGr: '', withShiftAltGr: '7' },
Numpad8: { value: '', withShift: '8', withAltGr: '', withShiftAltGr: '8' },
Numpad9: { value: '', withShift: '9', withAltGr: '', withShiftAltGr: '9' },
Numpad0: { value: '', withShift: '0', withAltGr: '', withShiftAltGr: '0' },
NumpadDecimal: { value: '', withShift: '.', withAltGr: '', withShiftAltGr: '.' },
IntlBackslash: {
value: '<',
withShift: '>',
withAltGr: '\\',
withShiftAltGr: '¦'
},
ContextMenu: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Power: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
NumpadEqual: {
value: '=',
withShift: '=',
withAltGr: '=',
withShiftAltGr: '='
},
F13: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F14: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F15: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F16: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F17: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F18: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F19: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F20: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F21: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F22: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F23: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
F24: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Open: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Help: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Select: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Again: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Undo: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Cut: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Copy: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Paste: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Find: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
AudioVolumeMute: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
AudioVolumeUp: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
AudioVolumeDown: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
NumpadComma: {
value: '.',
withShift: '.',
withAltGr: '.',
withShiftAltGr: '.'
},
IntlRo: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
KanaMode: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
IntlYen: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Convert: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
NonConvert: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Lang1: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Lang2: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Lang3: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Lang4: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Lang5: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
NumpadParenLeft: {
value: '(',
withShift: '(',
withAltGr: '(',
withShiftAltGr: '('
},
NumpadParenRight: {
value: ')',
withShift: ')',
withAltGr: ')',
withShiftAltGr: ')'
},
ControlLeft: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
ShiftLeft: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
AltLeft: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MetaLeft: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
ControlRight: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
ShiftRight: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
AltRight: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MetaRight: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
BrightnessUp: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
BrightnessDown: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MediaPlay: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MediaRecord: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MediaFastForward: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MediaRewind: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MediaTrackNext: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MediaTrackPrevious: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MediaStop: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
Eject: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MediaPlayPause: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MediaSelect: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
LaunchMail: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
LaunchApp2: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
LaunchApp1: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
SelectTask: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
LaunchScreenSaver: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
BrowserSearch: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
BrowserHome: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
BrowserBack: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
BrowserForward: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
BrowserStop: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
BrowserRefresh: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
BrowserFavorites: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MailReply: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MailForward: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' },
MailSend: { value: '', withShift: '', withAltGr: '', withShiftAltGr: '' }
};
\ No newline at end of file
......@@ -33,21 +33,36 @@ export class ColorThemeData implements IColorTheme {
isLoaded: boolean;
path?: string;
extensionData: ExtensionData;
colorMap?: IColorMap;
colorMap: IColorMap = {};
defaultColorMap: IColorMap = {};
public getColor(colorId: ColorIdentifier, useDefault?: boolean): Color {
if (!this.colorMap) {
return null; // not yet initialized
}
public getColor(colorId: ColorIdentifier, useDefault?: boolean): Color {
let color = this.colorMap[colorId];
if (useDefault !== false && types.isUndefined(color)) {
color = this.getDefault(colorId);
}
return color;
}
private getDefault(colorId: ColorIdentifier): Color {
let color = this.defaultColorMap[colorId];
if (types.isUndefined(color)) {
color = colorRegistry.resolveDefaultColor(colorId, this);
this.colorMap[colorId] = color;
this.defaultColorMap[colorId] = color;
}
return color;
}
public isDefault(colorId: ColorIdentifier): boolean {
let color = this.colorMap[colorId];
if (types.isUndefined(color)) {
return true;
}
let defaultValue = this.getDefault(colorId);
return color === null ? defaultValue === null : color.equals(defaultValue);
}
public ensureLoaded(): TPromise<void> {
if (!this.isLoaded) {
let tokenColors = [];
......@@ -55,6 +70,7 @@ export class ColorThemeData implements IColorTheme {
return _loadThemeDocument(this.getBaseThemeId(), this.path, tokenColors, colorMap).then(_ => {
this.tokenColors = tokenColors;
this.colorMap = colorMap;
this.defaultColorMap = {};
this.isLoaded = true;
});
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册