提交 181bffa0 编写于 作者: J Joao Moreno

Merge branch 'master' of github.com:Microsoft/vscode

{
perform: true,
alwaysRequireAssignee: true,
alwaysRequireAssignee: false,
labelsRequiringAssignee: [ feature-request ],
autoAssignees: {
accessibility: [],
......
......@@ -53,7 +53,7 @@ Type: filesandordirs; Name: {app}\resources\app\node_modules
Type: files; Name: {app}\resources\app\Credits_45.0.2454.85.html
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1
Name: "addcontextmenufiles"; Description: "{cm:AddContextMenuFiles,{#NameShort}}"; GroupDescription: "{cm:Other}"; Flags: unchecked
Name: "addcontextmenufolders"; Description: "{cm:AddContextMenuFolders,{#NameShort}}"; GroupDescription: "{cm:Other}"; Flags: unchecked
......
......@@ -3,12 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Based on @sergeche's work in his emmet plugin */
'use strict';
import { TextDocument, Position, Range, EndOfLine } from 'vscode';
/**
* A stream reader for VSCode's `TextDocument`
* A stream reader for VSCode's `TextDocument`
* Based on @emmetio/stream-reader and @emmetio/atom-plugin
*/
export class DocumentStreamReader {
......
......@@ -3,6 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Based on @sergeche's work in his emmet plugin */
import * as vscode from 'vscode';
import evaluate from '@emmetio/math-expression';
import { DocumentStreamReader } from './bufferStream';
......
......@@ -16,12 +16,17 @@ import { toggleComment } from './toggleComment';
import { fetchEditPoint } from './editPoint';
import { fetchSelectItem } from './selectItem';
import { evaluateMathExpression } from './evaluateMathExpression';
import { LANGUAGE_MODES, getMappedModes } from './util';
import { incrementDecrement } from './incrementDecrement';
import { LANGUAGE_MODES, getMappedModes, getExcludedModes } from './util';
import { updateExtensionsPath } from 'vscode-emmet-helper';
export function activate(context: vscode.ExtensionContext) {
let completionProvider = new DefaultCompletionItemProvider();
let exlcludedLanguages = getExcludedModes();
Object.keys(LANGUAGE_MODES).forEach(language => {
if (exlcludedLanguages.indexOf(language) > -1) {
return;
}
const provider = vscode.languages.registerCompletionItemProvider(language, completionProvider, ...LANGUAGE_MODES[language]);
context.subscriptions.push(provider);
});
......@@ -96,6 +101,32 @@ export function activate(context: vscode.ExtensionContext) {
evaluateMathExpression();
}));
context.subscriptions.push(vscode.commands.registerCommand('emmet.incrementNumberByOneTenth', () => {
incrementDecrement(.1);
}));
context.subscriptions.push(vscode.commands.registerCommand('emmet.incrementNumberByOne', () => {
incrementDecrement(1);
}));
context.subscriptions.push(vscode.commands.registerCommand('emmet.incrementNumberByTen', () => {
incrementDecrement(10);
}));
context.subscriptions.push(vscode.commands.registerCommand('emmet.decrementNumberByOneTenth', () => {
incrementDecrement(-0.1);
}));
context.subscriptions.push(vscode.commands.registerCommand('emmet.decrementNumberByOne', () => {
incrementDecrement(-1);
}));
context.subscriptions.push(vscode.commands.registerCommand('emmet.decrementNumberByTen', () => {
incrementDecrement(-10);
}));
updateExtensionsPath();
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(() => {
updateExtensionsPath();
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Based on @sergeche's work in his emmet plugin */
import * as vscode from 'vscode';
const reNumber = /[0-9]/;
/**
* Incerement number under caret of given editor
* @param {Number} delta
*/
export function incrementDecrement(delta: number) {
let editor = vscode.window.activeTextEditor;
if (!editor) {
vscode.window.showInformationMessage('No editor is active');
return;
}
editor.edit(editBuilder => {
editor.selections.forEach(selection => {
let rangeToReplace: vscode.Range = selection;
if (selection.isEmpty) {
rangeToReplace = locate(editor.document, selection.isReversed ? selection.anchor : selection.active);
}
const text = editor.document.getText(rangeToReplace);
if (isValidNumber(text)) {
editBuilder.replace(rangeToReplace, update(text, delta));
}
});
});
}
/**
* Updates given number with `delta` and returns string formatted according
* to original string format
* @param {String} numString
* @param {Number} delta
* @return {String}
*/
export function update(numString, delta): string {
let m;
let decimals = (m = numString.match(/\.(\d+)$/)) ? m[1].length : 1;
let output = String((parseFloat(numString) + delta).toFixed(decimals)).replace(/\.0+$/, '');
if (m = numString.match(/^\-?(0\d+)/)) {
// padded number: preserve padding
output = output.replace(/^(\-?)(\d+)/, (str, minus, prefix) =>
minus + '0'.repeat(Math.max(0, m[1].length - prefix.length)) + prefix);
}
if (/^\-?\./.test(numString)) {
// omit integer part
output = output.replace(/^(\-?)0+/, '$1');
}
return output;
}
/**
* Locates number from given position in the document
* @param {document} Textdocument
* @param {Point} pos
* @return {Range} Range of number or `undefined` if not found
*/
export function locate(document: vscode.TextDocument, pos: vscode.Position) {
const line = document.lineAt(pos.line).text;
let start = pos.character;
let end = pos.character;
let hadDot = false, hadMinus = false;
let ch;
while (start > 0) {
ch = line[--start];
if (ch === '-') {
hadMinus = true;
break;
} else if (ch === '.' && !hadDot) {
hadDot = true;
} else if (!reNumber.test(ch)) {
start++;
break;
}
}
if (line[end] === '-' && !hadMinus) {
end++;
}
while (end < line.length) {
ch = line[end++];
if (ch === '.' && !hadDot && reNumber.test(line[end])) {
// A dot must be followed by a number. Otherwise stop parsing
hadDot = true;
} else if (!reNumber.test(ch)) {
end--;
break;
}
}
// ensure that found range contains valid number
if (start !== end && isValidNumber(line.slice(start, end))) {
return new vscode.Range(pos.line, start, pos.line, end);
}
}
/**
* Check if given string contains valid number
* @param {String} str
* @return {Boolean}
*/
function isValidNumber(str): boolean {
return str && !isNaN(parseFloat(str));
}
......@@ -58,11 +58,15 @@ export function getMappedModes(): any {
return finalMappedModes;
}
export function getExcludedModes(): string[] {
let excludedConfig = vscode.workspace.getConfiguration('emmet')['excludeLanguages'];
return Array.isArray(excludedConfig) ? excludedConfig : [];
}
/**
* Returns node corresponding to given position in the given root node
* @param root
* @param position
* @param includeNodeBoundary
* @param root
* @param position
* @param includeNodeBoundary
*/
export function getNode(root: Node, position: vscode.Position, includeNodeBoundary: boolean = false) {
let currentNode: Node = root.firstChild;
......@@ -87,7 +91,7 @@ export function getNode(root: Node, position: vscode.Position, includeNodeBounda
/**
* Returns inner range of an html node.
* @param currentNode
* @param currentNode
*/
export function getInnerRange(currentNode: Node): vscode.Range {
if (!currentNode.close) {
......
......@@ -67,6 +67,7 @@ export class View extends ViewEventHandler {
private _scrollbar: EditorScrollbar;
private _context: ViewContext;
private _cursor: Cursor;
// The view lines
private viewLines: ViewLines;
......@@ -103,6 +104,7 @@ export class View extends ViewEventHandler {
) {
super();
this._isDisposed = false;
this._cursor = cursor;
this._renderAnimationFrame = null;
this.outgoingEvents = new ViewOutgoingEvents(model);
......@@ -139,7 +141,7 @@ export class View extends ViewEventHandler {
this.eventDispatcher.emitMany(events);
}));
this._register(cursor.addEventListener((events: viewEvents.ViewEvent[]) => {
this._register(this._cursor.addEventListener((events: viewEvents.ViewEvent[]) => {
this.eventDispatcher.emitMany(events);
}));
}
......@@ -410,7 +412,12 @@ export class View extends ViewEventHandler {
const partialViewportData = this._context.viewLayout.getLinesViewportData();
this._context.model.setViewport(partialViewportData.startLineNumber, partialViewportData.endLineNumber, partialViewportData.centeredLineNumber);
let viewportData = new ViewportData(partialViewportData, this._context.viewLayout.getWhitespaceViewportData(), this._context.model);
let viewportData = new ViewportData(
this._cursor.getViewSelections(),
partialViewportData,
this._context.viewLayout.getWhitespaceViewportData(),
this._context.model
);
if (this.viewLines.shouldRender()) {
this.viewLines.renderText(viewportData);
......
......@@ -40,6 +40,8 @@ const canUseFastRenderedViewLine = (function () {
return true;
})();
const renderInlineSelection = (browser.isEdgeOrIE);
export class DomReadingContext {
private readonly _domNode: HTMLElement;
......@@ -142,6 +144,13 @@ export class ViewLine implements IVisibleLine {
this._isMaybeInvalid = true;
this._options = newOptions;
}
public onSelectionChanged(): boolean {
if (renderInlineSelection) {
this._isMaybeInvalid = true;
return true;
}
return false;
}
public renderLine(lineNumber: number, deltaTop: number, viewportData: ViewportData): string {
if (this._isMaybeInvalid === false) {
......@@ -154,6 +163,26 @@ export class ViewLine implements IVisibleLine {
const lineData = viewportData.getViewLineRenderingData(lineNumber);
const options = this._options;
const actualInlineDecorations = LineDecoration.filter(lineData.inlineDecorations, lineNumber, lineData.minColumn, lineData.maxColumn);
if (renderInlineSelection) {
const selections = viewportData.selections;
for (let i = 0, len = selections.length; i < len; i++) {
const selection = selections[i];
if (selection.endLineNumber < lineNumber || selection.startLineNumber > lineNumber) {
// Selection does not intersect line
continue;
}
let startColumn = (selection.startLineNumber === lineNumber ? selection.startColumn : lineData.minColumn);
let endColumn = (selection.endLineNumber === lineNumber ? selection.endColumn : lineData.maxColumn);
if (startColumn < endColumn) {
actualInlineDecorations.push(new LineDecoration(startColumn, endColumn, 'inline-selected-text', false));
}
}
}
let renderLineInput = new RenderLineInput(
options.useMonospaceOptimizations,
lineData.content,
......
......@@ -157,6 +157,15 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
return true;
}
public onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {
let rendStartLineNumber = this._visibleLines.getStartLineNumber();
let rendEndLineNumber = this._visibleLines.getEndLineNumber();
let r = false;
for (let lineNumber = rendStartLineNumber; lineNumber <= rendEndLineNumber; lineNumber++) {
r = this._visibleLines.getVisibleLine(lineNumber).onSelectionChanged() || r;
}
return r;
}
public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {
if (true/*e.inlineDecorationsChanged*/) {
let rendStartLineNumber = this._visibleLines.getStartLineNumber();
......
......@@ -21,7 +21,6 @@
position: relative;
overflow: visible;
-webkit-text-size-adjust: 100%;
-ms-high-contrast-adjust: none;
-webkit-font-feature-settings: "liga" off, "calt" off;
font-feature-settings: "liga" off, "calt" off;
}
......
......@@ -313,6 +313,10 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
return this._cursors.getSelections();
}
public getViewSelections(): Selection[] {
return this._cursors.getViewSelections();
}
public getPosition(): Position {
return this._cursors.getPrimaryCursor().modelState.position;
}
......
......@@ -6,6 +6,7 @@
import { ViewLineRenderingData, IViewModel, ViewModelDecoration, IViewWhitespaceViewportData } from 'vs/editor/common/viewModel/viewModel';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
export interface IPartialViewLinesViewportData {
/**
......@@ -43,6 +44,8 @@ export interface IPartialViewLinesViewportData {
*/
export class ViewportData {
public readonly selections: Selection[];
/**
* The line number at which to start rendering (inclusive).
*/
......@@ -76,10 +79,12 @@ export class ViewportData {
private readonly _model: IViewModel;
constructor(
selections: Selection[],
partialData: IPartialViewLinesViewportData,
whitespaceViewportData: IViewWhitespaceViewportData[],
model: IViewModel
) {
this.selections = selections;
this.startLineNumber = partialData.startLineNumber | 0;
this.endLineNumber = partialData.endLineNumber | 0;
this.relativeVerticalOffset = partialData.relativeVerticalOffset;
......
......@@ -345,8 +345,6 @@
background-color: rgba(255, 255, 255, 0.1);
}
/* High Contrast Theming */
.monaco-editor.hc-black .find-widget .button:before {
position: relative;
top: 1px;
......@@ -355,4 +353,4 @@
.monaco-editor.hc-black .find-widget .monaco-checkbox .checkbox:checked + .label {
background-color: rgba(255, 255, 255, 0.1);
}
\ No newline at end of file
}
......@@ -26,6 +26,218 @@
margin: 0;
}
/* The hc-black theme is already high contrast optimized */
.monaco-editor.hc-black {
-ms-high-contrast-adjust: none;
}
/* In case the browser goes into high contrast mode and the editor is not configured with the hc-black theme */
@media screen and (-ms-high-contrast:active) {
/* current line highlight */
.monaco-editor.vs .view-overlays .current-line,
.monaco-editor.vs-dark .view-overlays .current-line {
border-color: windowtext !important;
border-left: 0;
border-right: 0;
}
/* view cursors */
.monaco-editor.vs .cursor,
.monaco-editor.vs-dark .cursor {
background-color: windowtext !important;
}
/* dnd target */
.monaco-editor.vs .dnd-target,
.monaco-editor.vs-dark .dnd-target {
border-color: windowtext !important;
}
/* selected text background */
.monaco-editor.vs .selected-text,
.monaco-editor.vs-dark .selected-text {
background-color: highlight !important;
}
/* allow the text to have a transparent background. */
.monaco-editor.vs .view-line,
.monaco-editor.vs-dark .view-line {
-ms-high-contrast-adjust: none;
}
/* text color */
.monaco-editor.vs .view-line span,
.monaco-editor.vs-dark .view-line span {
color: windowtext !important;
}
/* selected text color */
.monaco-editor.vs .view-line span.inline-selected-text,
.monaco-editor.vs-dark .view-line span.inline-selected-text {
color: highlighttext !important;
}
/* allow decorations */
.monaco-editor.vs .view-overlays,
.monaco-editor.vs-dark .view-overlays {
-ms-high-contrast-adjust: none;
}
/* various decorations */
.monaco-editor.vs .selectionHighlight,
.monaco-editor.vs-dark .selectionHighlight,
.monaco-editor.vs .wordHighlight,
.monaco-editor.vs-dark .wordHighlight,
.monaco-editor.vs .wordHighlightStrong,
.monaco-editor.vs-dark .wordHighlightStrong,
.monaco-editor.vs .reference-decoration,
.monaco-editor.vs-dark .reference-decoration {
border: 2px dotted highlight !important;
background: transparent !important;
box-sizing: border-box;
}
.monaco-editor.vs .rangeHighlight,
.monaco-editor.vs-dark .rangeHighlight {
background: transparent !important;
border: 1px dotted activeborder !important;
box-sizing: border-box;
}
.monaco-editor.vs .bracket-match,
.monaco-editor.vs-dark .bracket-match {
border-color: windowtext !important;
background: transparent !important;
}
/* find widget */
.monaco-editor.vs .findMatch,
.monaco-editor.vs-dark .findMatch,
.monaco-editor.vs .currentFindMatch,
.monaco-editor.vs-dark .currentFindMatch {
border: 2px dotted activeborder !important;
background: transparent !important;
box-sizing: border-box;
}
.monaco-editor.vs .find-widget,
.monaco-editor.vs-dark .find-widget {
border: 1px solid windowtext;
}
/* list - used by suggest widget */
.monaco-editor.vs .monaco-list .monaco-list-row,
.monaco-editor.vs-dark .monaco-list .monaco-list-row {
-ms-high-contrast-adjust: none;
color: windowtext !important;
}
.monaco-editor.vs .monaco-list .monaco-list-row.focused,
.monaco-editor.vs-dark .monaco-list .monaco-list-row.focused {
color: highlighttext !important;
background-color: highlight !important;
}
.monaco-editor.vs .monaco-list .monaco-list-row:hover,
.monaco-editor.vs-dark .monaco-list .monaco-list-row:hover {
background: transparent !important;
border: 1px solid highlight;
box-sizing: border-box;
}
/* tree */
.monaco-editor.vs .monaco-tree .monaco-tree-row,
.monaco-editor.vs-dark .monaco-tree .monaco-tree-row {
-ms-high-contrast-adjust: none;
color: windowtext !important;
}
.monaco-editor.vs .monaco-tree .monaco-tree-row.selected,
.monaco-editor.vs-dark .monaco-tree .monaco-tree-row.selected,
.monaco-editor.vs .monaco-tree .monaco-tree-row.focused,
.monaco-editor.vs-dark .monaco-tree .monaco-tree-row.focused {
color: highlighttext !important;
background-color: highlight !important;
}
.monaco-editor.vs .monaco-tree .monaco-tree-row:hover,
.monaco-editor.vs-dark .monaco-tree .monaco-tree-row:hover {
background: transparent !important;
border: 1px solid highlight;
box-sizing: border-box;
}
/* scrollbars */
.monaco-editor.vs .monaco-scrollable-element > .scrollbar,
.monaco-editor.vs-dark .monaco-scrollable-element > .scrollbar {
-ms-high-contrast-adjust: none;
background: background !important;
border: 1px solid windowtext;
box-sizing: border-box;
}
.monaco-editor.vs .monaco-scrollable-element > .scrollbar > .slider,
.monaco-editor.vs-dark .monaco-scrollable-element > .scrollbar > .slider {
background: windowtext !important;
}
.monaco-editor.vs .monaco-scrollable-element > .scrollbar > .slider:hover,
.monaco-editor.vs-dark .monaco-scrollable-element > .scrollbar > .slider:hover {
background: highlight !important;
}
.monaco-editor.vs .monaco-scrollable-element > .scrollbar > .slider.active,
.monaco-editor.vs-dark .monaco-scrollable-element > .scrollbar > .slider.active {
background: highlight !important;
}
/* overview ruler */
.monaco-editor.vs .decorationsOverviewRuler,
.monaco-editor.vs-dark .decorationsOverviewRuler {
opacity: 0;
}
/* minimap */
.monaco-editor.vs .minimap,
.monaco-editor.vs-dark .minimap {
display: none;
}
/* squiggles */
.monaco-editor.vs .redsquiggly,
.monaco-editor.vs-dark .redsquiggly {
background: transparent !important;
border-bottom: 4px double #E47777;
}
.monaco-editor.vs .greensquiggly,
.monaco-editor.vs-dark .greensquiggly {
border-bottom: 4px double #71B771;
}
/* contextmenu */
.monaco-editor.vs .monaco-menu .monaco-action-bar.vertical .action-item .action-label:focus,
.monaco-editor.vs-dark .monaco-menu .monaco-action-bar.vertical .action-item .action-label:focus {
-ms-high-contrast-adjust: none;
color: highlighttext !important;
background-color: highlight !important;
}
.monaco-editor.vs .monaco-menu .monaco-action-bar.vertical .action-item .action-label:hover,
.monaco-editor.vs-dark .monaco-menu .monaco-action-bar.vertical .action-item .action-label:hover {
-ms-high-contrast-adjust: none;
background: transparent !important;
border: 1px solid highlight;
box-sizing: border-box;
}
/* diff editor */
.monaco-diff-editor.vs .diffOverviewRuler,
.monaco-diff-editor.vs-dark .diffOverviewRuler {
display: none;
}
.monaco-editor.vs .line-insert,
.monaco-editor.vs-dark .line-insert,
.monaco-editor.vs .line-delete,
.monaco-editor.vs-dark .line-delete {
background: transparent !important;
border: 1px solid highlight !important;
box-sizing: border-box;
}
.monaco-editor.vs .char-insert,
.monaco-editor.vs-dark .char-insert,
.monaco-editor.vs .char-delete,
.monaco-editor.vs-dark .char-delete {
background: transparent !important;
}
}
/*.monaco-editor.vs [tabindex="0"]:focus {
outline: 1px solid rgba(0, 122, 204, 0.4);
outline-offset: -1px;
......
......@@ -84,6 +84,7 @@ export interface IConfigurationValue<T> {
default: T;
user: T;
workspace: T;
folder: T;
}
export interface IConfigurationKeys {
......@@ -237,18 +238,21 @@ export class Configuration<T> {
}
getValue<C>(section: string = '', overrides: IConfigurationOverrides = {}): C {
const configModel = this.getConfigurationModel(overrides);
const configModel = this.getConsolidateConfigurationModel(overrides);
return section ? configModel.getContentsFor<C>(section) : configModel.contents;
}
lookup<C>(key: string, overrides: IConfigurationOverrides = {}): IConfigurationValue<C> {
// make sure to clone the configuration so that the receiver does not tamper with the values
const workspaceConfiguration = this.getConfigurationModel(overrides);
const consolidateConfigurationModel = this.getConsolidateConfigurationModel(overrides);
const workspaceConfigurationModel = this.getConfigurationModelForResource(this.workspaceUri);
const folderConfigurationModel = this.getConfigurationModelForResource(overrides.resource);
return {
default: objects.clone(getConfigurationValue<C>(overrides.overrideIdentifier ? this._defaults.override(overrides.overrideIdentifier).contents : this._defaults.contents, key)),
user: objects.clone(getConfigurationValue<C>(overrides.overrideIdentifier ? this._user.override(overrides.overrideIdentifier).contents : this._user.contents, key)),
workspace: objects.clone(this.workspaceUri ? getConfigurationValue<C>(overrides.overrideIdentifier ? this.folders.get(this.workspaceUri).override(overrides.overrideIdentifier).contents : this.folders.get(this.workspaceUri).contents, key) : void 0),
value: objects.clone(getConfigurationValue<C>(workspaceConfiguration.contents, key))
workspace: objects.clone(workspaceConfigurationModel ? getConfigurationValue<C>(overrides.overrideIdentifier ? workspaceConfigurationModel.override(overrides.overrideIdentifier).contents : workspaceConfigurationModel.contents, key) : void 0),
folder: objects.clone(folderConfigurationModel ? getConfigurationValue<C>(overrides.overrideIdentifier ? folderConfigurationModel.override(overrides.overrideIdentifier).contents : folderConfigurationModel.contents, key) : void 0),
value: objects.clone(getConfigurationValue<C>(consolidateConfigurationModel.contents, key))
};
}
......@@ -296,12 +300,12 @@ export class Configuration<T> {
return this._workspace ? this._workspace.roots[0] : null;
}
private getConfigurationModel<C>(overrides: IConfigurationOverrides): ConfigurationModel<any> {
let configurationModel = this.getConfigurationForResource(overrides);
private getConsolidateConfigurationModel<C>(overrides: IConfigurationOverrides): ConfigurationModel<any> {
let configurationModel = this.getConsolidatedConfigurationModelForResource(overrides);
return overrides.overrideIdentifier ? configurationModel.override<T>(overrides.overrideIdentifier) : configurationModel;
}
private getConfigurationForResource({ resource }: IConfigurationOverrides): ConfigurationModel<any> {
private getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides): ConfigurationModel<any> {
if (!this._workspace) {
return this._globalConfiguration;
}
......@@ -318,6 +322,18 @@ export class Configuration<T> {
return this._foldersConsolidatedConfigurations.get(root) || this._workspaceConfiguration;
}
private getConfigurationModelForResource(resource: URI): ConfigurationModel<any> {
if (!this._workspace) {
return null;
}
if (!resource) {
return this.folders.get(this.workspaceUri);
}
return this.folders.get(this._workspace.getRoot(resource) || this.workspaceUri);
}
public toData(): IConfigurationData<any> {
return {
defaults: {
......
......@@ -41,7 +41,8 @@ export class TestConfigurationService extends EventEmitter implements IConfigura
value: getConfigurationValue<C>(this.getConfiguration(), key),
default: getConfigurationValue<C>(this.getConfiguration(), key),
user: getConfigurationValue<C>(this.getConfiguration(), key),
workspace: null
workspace: null,
folder: null
};
}
......
......@@ -693,6 +693,7 @@ suite('TelemetryService', () => {
default: getConfigurationValue(this.getConfiguration(), key),
user: getConfigurationValue(this.getConfiguration(), key),
workspace: null,
folder: null
};
},
keys() { return { default: [], user: [], workspace: [] }; },
......
......@@ -55,12 +55,15 @@ export class ExtHostWorkspace extends ExtHostWorkspaceShape {
return undefined;
}
const { roots } = this._workspace;
if (roots.length === 1) {
return roots[0].fsPath;
if (roots.length === 0) {
return undefined;
}
// if (roots.length === 1) {
return roots[0].fsPath;
// }
// return `undefined` when there no or more than 1
// root folder.
return undefined;
// return undefined;
}
getRelativePath(pathOrUri: string | vscode.Uri): string {
......
......@@ -1210,7 +1210,7 @@ export class BreakpointsRenderer implements IRenderer {
private renderBreakpoint(tree: ITree, breakpoint: debug.IBreakpoint, data: IBreakpointTemplateData): void {
this.debugService.getModel().areBreakpointsActivated() ? tree.removeTraits('disabled', [breakpoint]) : tree.addTraits('disabled', [breakpoint]);
data.name.textContent = getPathLabel(paths.basename(breakpoint.uri.fsPath), this.contextService);
data.name.textContent = paths.basename(getPathLabel(breakpoint.uri, this.contextService));
data.lineNumber.textContent = breakpoint.lineNumber.toString();
if (breakpoint.column) {
data.lineNumber.textContent += `:${breakpoint.column}`;
......
......@@ -251,7 +251,13 @@ export abstract class EmmetEditorAction extends EditorAction {
'editor.emmet.action.selectNextItem': 'emmet.selectNextItem',
'editor.emmet.action.splitJoinTag': 'emmet.splitJoinTag',
'editor.emmet.action.toggleComment': 'emmet.toggleComment',
'editor.emmet.action.evaluateMath': 'emmet.evaluateMathExpression'
'editor.emmet.action.evaluateMath': 'emmet.evaluateMathExpression',
'editor.emmet.action.incrementNumberByOneTenth': 'emmet.incrementNumberByOneTenth',
'editor.emmet.action.incrementNumberByOne': 'emmet.incrementNumberByOne',
'editor.emmet.action.incrementNumberByTen': 'emmet.incrementNumberByTen',
'editor.emmet.action.decrementNumberByOneTenth': 'emmet.decrementNumberByOneTenth',
'editor.emmet.action.decrementNumberByOne': 'emmet.decrementNumberByOne',
'editor.emmet.action.decrementNumberByTen': 'emmet.decrementNumberByTen'
};
protected emmetActionName: string;
......
......@@ -27,7 +27,7 @@ import labels = require('vs/base/common/labels');
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IFileService, IFileStat } from 'vs/platform/files/common/files';
import { toResource, IEditorIdentifier, EditorInput } from 'vs/workbench/common/editor';
import { FileStat, NewStatPlaceholder } from 'vs/workbench/parts/files/common/explorerModel';
import { FileStat, Model, NewStatPlaceholder } from 'vs/workbench/parts/files/common/explorerModel';
import { ExplorerView } from 'vs/workbench/parts/files/browser/views/explorerView';
import { ExplorerViewlet } from 'vs/workbench/parts/files/browser/explorerViewlet';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
......@@ -365,13 +365,14 @@ export class BaseNewAction extends BaseFileAction {
return TPromise.wrapError('Invalid viewlet state provided to BaseNewAction.');
}
let folder: FileStat = this.presetFolder;
let folder = this.presetFolder;
if (!folder) {
const focus = <FileStat>this.tree.getFocus();
if (focus) {
folder = focus.isDirectory ? focus : focus.parent;
} else {
folder = this.tree.getInput();
const input: FileStat | Model = this.tree.getInput();
folder = input instanceof Model ? input.roots[0] : input;
}
}
......@@ -795,7 +796,8 @@ export class ImportFileAction extends BaseFileAction {
if (this.element) {
targetElement = this.element;
} else {
targetElement = this.tree.getFocus() || this.tree.getInput();
const input: FileStat | Model = this.tree.getInput();
targetElement = this.tree.getFocus() || (input instanceof Model ? input.roots[0] : input);
}
if (!targetElement.isDirectory) {
......@@ -935,7 +937,11 @@ export class PasteFileAction extends BaseFileAction {
super(PasteFileAction.ID, nls.localize('pasteFile', "Paste"), fileService, messageService, textFileService);
this.tree = tree;
this.element = element || this.tree.getInput();
this.element = element;
if (!this.element) {
const input: FileStat | Model = this.tree.getInput();
this.element = input instanceof Model ? input.roots[0] : input;
}
this._updateEnablement();
}
......@@ -947,7 +953,7 @@ export class PasteFileAction extends BaseFileAction {
}
// Check if file was deleted or moved meanwhile
const root: FileStat = this.tree.getInput();
const root: FileStat = this.element.root;
const exists = root.find(fileToCopy.resource);
if (!exists) {
fileToCopy = null;
......@@ -1041,12 +1047,11 @@ export class DuplicateFileAction extends BaseFileAction {
}
private findTarget(): URI {
const root: FileStat = this.tree.getInput();
let name = this.element.name;
let candidate = URI.file(paths.join(this.target.resource.fsPath, name));
while (true) {
if (!root.find(candidate)) {
if (!this.element.root.find(candidate)) {
break;
}
......@@ -1262,13 +1267,15 @@ export class CompareResourcesAction extends Action {
// Check if file was deleted or moved meanwhile (explorer only)
if (this.tree) {
const root: FileStat = this.tree.getInput();
if (root instanceof FileStat) {
const exists = root.find(globalResourceToCompare);
if (!exists) {
globalResourceToCompare = null;
return false;
}
const input: FileStat | Model = this.tree.getInput();
if (input instanceof Model) {
return false;
}
const exists = input.find(globalResourceToCompare);
if (!exists) {
globalResourceToCompare = null;
return false;
}
}
......
......@@ -433,17 +433,25 @@ export class ExplorerView extends CollapsibleView {
// Add the new file to its parent (Model)
parents.forEach(p => {
const childElement = FileStat.create(addedElement, p.root);
p.removeChild(childElement); // make sure to remove any previous version of the file if any
p.addChild(childElement);
// Refresh the Parent (View)
this.explorerViewer.refresh(p).then(() => {
return this.reveal(childElement, 0.5).then(() => {
// Focus new element
this.explorerViewer.setFocus(childElement);
});
}).done(null, errors.onUnexpectedError);
// We have to check if the parent is resolved #29177
(p.isDirectoryResolved ? TPromise.as(null) : this.fileService.resolveFile(p.resource)).then(stat => {
if (stat) {
const modelStat = FileStat.create(stat, p.root);
FileStat.mergeLocalWithDisk(modelStat, p);
}
const childElement = FileStat.create(addedElement, p.root);
p.removeChild(childElement); // make sure to remove any previous version of the file if any
p.addChild(childElement);
// Refresh the Parent (View)
this.explorerViewer.refresh(p).then(() => {
return this.reveal(childElement, 0.5).then(() => {
// Focus new element
this.explorerViewer.setFocus(childElement);
});
}).done(null, errors.onUnexpectedError);
});
});
}
}
......@@ -721,7 +729,7 @@ export class ExplorerView extends CollapsibleView {
// Load Root Stat with given target path configured
const promise = this.fileService.resolveFiles(targetsToResolve).then(stats => {
// Convert to model
const modelStats = stats.map((stat, index) => FileStat.create(stat, targetsToResolve[index].root.resource, targetsToResolve[index].options.resolveTo));
const modelStats = stats.map((stat, index) => FileStat.create(stat, targetsToResolve[index].root, targetsToResolve[index].options.resolveTo));
// Subsequent refresh: Merge stat into our local model and refresh tree
modelStats.forEach((modelStat, index) => FileStat.mergeLocalWithDisk(modelStat, this.model.roots[index]));
......@@ -808,8 +816,8 @@ export class ExplorerView extends CollapsibleView {
return this.fileService.resolveFile(rootUri, options).then(stat => {
// Convert to model
const modelStat = FileStat.create(stat, rootUri, options.resolveTo);
const root = this.model.roots.filter(r => r.resource.toString() === rootUri.toString()).pop();
const modelStat = FileStat.create(stat, root, options.resolveTo);
// Update Input with disk Stat
FileStat.mergeLocalWithDisk(modelStat, root);
......
......@@ -65,7 +65,7 @@ export class FileDataSource implements IDataSource {
return 'model';
}
return `${stat.root.toString()}:${stat.getId()}`;
return `${stat.root.resource.toString()}:${stat.getId()}`;
}
public hasChildren(tree: ITree, stat: FileStat | Model): boolean {
......@@ -601,8 +601,8 @@ export class FileFilter implements IFilter {
// Hide those that match Hidden Patterns
const siblingsFn = () => siblings && siblings.map(c => c.name);
const expression = this.hiddenExpressionPerRoot.get(stat.root.toString()) || Object.create(null);
if (glob.match(expression, paths.normalize(paths.relative(stat.root.fsPath, stat.resource.fsPath)), siblingsFn)) {
const expression = this.hiddenExpressionPerRoot.get(stat.root.resource.toString()) || Object.create(null);
if (glob.match(expression, paths.normalize(paths.relative(stat.root.resource.fsPath, stat.resource.fsPath)), siblingsFn)) {
return false; // hidden through pattern
}
......
......@@ -25,7 +25,7 @@ export class Model {
private _roots: FileStat[];
constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService) {
const setRoots = () => this._roots = this.contextService.getWorkspace2().roots.map(uri => new FileStat(uri, uri));
const setRoots = () => this._roots = this.contextService.getWorkspace2().roots.map(uri => new FileStat(uri, undefined));
this.contextService.onDidChangeWorkspaceRoots(() => setRoots());
setRoots();
}
......@@ -67,7 +67,7 @@ export class FileStat implements IFileStat {
public isDirectoryResolved: boolean;
constructor(resource: URI, public root: URI, isDirectory?: boolean, hasChildren?: boolean, name: string = paths.basename(resource.fsPath), mtime?: number, etag?: string) {
constructor(resource: URI, public root: FileStat, isDirectory?: boolean, hasChildren?: boolean, name: string = paths.basename(resource.fsPath), mtime?: number, etag?: string) {
this.resource = resource;
this.name = name;
this.isDirectory = !!isDirectory;
......@@ -79,6 +79,9 @@ export class FileStat implements IFileStat {
if (this.isDirectory) {
this.children = [];
}
if (!this.root) {
this.root = this;
}
this.isDirectoryResolved = false;
}
......@@ -88,10 +91,10 @@ export class FileStat implements IFileStat {
}
public get isRoot(): boolean {
return this.resource.toString() === this.root.toString();
return this.resource.toString() === this.root.resource.toString();
}
public static create(raw: IFileStat, root: URI, resolveTo?: URI[]): FileStat {
public static create(raw: IFileStat, root: FileStat, resolveTo?: URI[]): FileStat {
const stat = new FileStat(raw.resource, root, raw.isDirectory, raw.hasChildren, raw.name, raw.mtime, raw.etag);
// Recursively add children if present
......@@ -316,8 +319,8 @@ export class NewStatPlaceholder extends FileStat {
private id: number;
private directoryPlaceholder: boolean;
constructor(isDirectory: boolean) {
super(URI.file(''), URI.file(''));
constructor(isDirectory: boolean, root: FileStat) {
super(URI.file(''), root);
this.id = NewStatPlaceholder.ID++;
this.isDirectoryResolved = isDirectory;
......@@ -367,7 +370,7 @@ export class NewStatPlaceholder extends FileStat {
}
public static addNewStatPlaceholder(parent: FileStat, isDirectory: boolean): NewStatPlaceholder {
const child = new NewStatPlaceholder(isDirectory);
const child = new NewStatPlaceholder(isDirectory, parent.root);
// Inherit some parent properties to child
child.parent = parent;
......
......@@ -13,8 +13,8 @@ import { join } from 'vs/base/common/paths';
import { validateFileName } from 'vs/workbench/parts/files/browser/fileActions';
import { FileStat } from 'vs/workbench/parts/files/common/explorerModel';
function createStat(path, name, isFolder, hasChildren, size, mtime) {
return new FileStat(toResource(path), toResource(path), isFolder, hasChildren, name, mtime);
function createStat(path: string, name: string, isFolder: boolean, hasChildren: boolean, size: number, mtime: number): FileStat {
return new FileStat(toResource(path), undefined, isFolder, hasChildren, name, mtime);
}
function toResource(path) {
......@@ -246,20 +246,20 @@ suite('Files - View Model', () => {
test('Merge Local with Disk', function () {
const d = new Date().toUTCString();
const merge1 = new FileStat(URI.file(join('C:\\', '/path/to')), URI.file(join('C:\\', '/path')), true, false, 'to', Date.now(), d);
const merge2 = new FileStat(URI.file(join('C:\\', '/path/to')), URI.file(join('C:\\', '/path')), true, false, 'to', Date.now(), new Date(0).toUTCString());
const merge1 = new FileStat(URI.file(join('C:\\', '/path/to')), undefined, true, false, 'to', Date.now(), d);
const merge2 = new FileStat(URI.file(join('C:\\', '/path/to')), undefined, true, false, 'to', Date.now(), new Date(0).toUTCString());
// Merge Properties
FileStat.mergeLocalWithDisk(merge2, merge1);
assert.strictEqual(merge1.mtime, merge2.mtime);
// Merge Child when isDirectoryResolved=false is a no-op
merge2.addChild(new FileStat(URI.file(join('C:\\', '/path/to/foo.html')), URI.file(join('C:\\', '/path')), true, false, 'foo.html', Date.now(), d));
merge2.addChild(new FileStat(URI.file(join('C:\\', '/path/to/foo.html')), undefined, true, false, 'foo.html', Date.now(), d));
FileStat.mergeLocalWithDisk(merge2, merge1);
assert.strictEqual(merge1.children.length, 0);
// Merge Child with isDirectoryResolved=true
const child = new FileStat(URI.file(join('C:\\', '/path/to/foo.html')), URI.file(join('C:\\', '/path')), true, false, 'foo.html', Date.now(), d);
const child = new FileStat(URI.file(join('C:\\', '/path/to/foo.html')), undefined, true, false, 'foo.html', Date.now(), d);
merge2.removeChild(child);
merge2.addChild(child);
merge2.isDirectoryResolved = true;
......
......@@ -102,7 +102,7 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend
public updatePreference(key: string, value: any, source: ISetting): void {
this.telemetryService.publicLog('defaultSettingsActions.copySetting', { userConfigurationKeys: [key] });
const overrideIdentifier = source.overrideOf ? overrideIdentifierFromKey(source.overrideOf.key) : null;
this.configurationEditingService.writeConfiguration(this.preferencesModel.configurationTarget, { key, value, overrideIdentifier }, { donotSave: this.textFileService.isDirty(this.preferencesModel.uri), donotNotifyError: true })
this.configurationEditingService.writeConfiguration(this.preferencesModel.configurationTarget, { key, value }, { donotSave: this.textFileService.isDirty(this.preferencesModel.uri), donotNotifyError: true, scopes: { overrideIdentifier } })
.then(() => this.onSettingUpdated(source), error => {
this.messageService.show(Severity.Error, this.toErrorMessage(error, this.preferencesModel.configurationTarget));
});
......
......@@ -18,7 +18,7 @@ class MockConfigurationService implements IConfigurationService {
public serviceId = IConfigurationService;
public constructor(private configuration: any = {}) { }
public reloadConfiguration<T>(section?: string): TPromise<T> { return TPromise.as(this.getConfiguration()); }
public lookup<T>(key: string, overrides?: IConfigurationOverrides): IConfigurationValue<T> { return { value: getConfigurationValue<T>(this.getConfiguration(), key), default: getConfigurationValue<T>(this.getConfiguration(), key), user: getConfigurationValue<T>(this.getConfiguration(), key), workspace: void 0 }; }
public lookup<T>(key: string, overrides?: IConfigurationOverrides): IConfigurationValue<T> { return { value: getConfigurationValue<T>(this.getConfiguration(), key), default: getConfigurationValue<T>(this.getConfiguration(), key), user: getConfigurationValue<T>(this.getConfiguration(), key), workspace: void 0, folder: void 0 }; }
public keys() { return { default: [], user: [], workspace: [] }; }
public values() { return {}; }
public getConfiguration(): any { return this.configuration; }
......
......@@ -6,6 +6,7 @@
import { TPromise } from 'vs/base/common/winjs.base';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
export const IConfigurationEditingService = createDecorator<IConfigurationEditingService>('configurationEditingService');
......@@ -58,7 +59,6 @@ export enum ConfigurationTarget {
export interface IConfigurationValue {
key: string;
value: any;
overrideIdentifier?: string;
}
export interface IConfigurationEditingOptions {
......@@ -70,6 +70,10 @@ export interface IConfigurationEditingOptions {
* If `true`, do not notifies the error to user by showing the message box. Default is `false`.
*/
donotNotifyError?: boolean;
/**
* Scope of configuration to be written into.
*/
scopes?: IConfigurationOverrides;
}
export interface IConfigurationEditingService {
......
......@@ -7,6 +7,7 @@
import nls = require('vs/nls');
import { TPromise } from 'vs/base/common/winjs.base';
import * as paths from 'vs/base/common/paths';
import URI from 'vs/base/common/uri';
import * as json from 'vs/base/common/json';
import * as encoding from 'vs/base/node/encoding';
......@@ -22,7 +23,7 @@ import { Selection } from 'vs/editor/common/core/selection';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IConfigurationService, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
import { keyFromOverrideIdentifier } from 'vs/platform/configuration/common/model';
import { WORKSPACE_CONFIG_DEFAULT_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration';
import { IFileService } from 'vs/platform/files/common/files';
......@@ -35,6 +36,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands';
interface IConfigurationEditOperation extends IConfigurationValue {
resource: URI;
isWorkspaceStandalone?: boolean;
overrideIdentifier?: string;
}
interface IValidationResult {
......@@ -70,12 +72,12 @@ export class ConfigurationEditingService implements IConfigurationEditingService
return this.queue.queue(() => this.doWriteConfiguration(target, value, options) // queue up writes to prevent race conditions
.then(() => null,
error => {
return options.donotNotifyError ? TPromise.wrapError(error) : this.onError(error, target, value);
return options.donotNotifyError ? TPromise.wrapError(error) : this.onError(error, target, value, options.scopes);
}));
}
private doWriteConfiguration(target: ConfigurationTarget, value: IConfigurationValue, options: ConfigurationEditingOptions): TPromise<void> {
const operation = this.getConfigurationEditOperation(target, value);
const operation = this.getConfigurationEditOperation(target, value, options.scopes || {});
const checkDirtyConfiguration = !(options.force || options.donotSave);
const saveConfiguration = options.force || !options.donotSave;
......@@ -106,13 +108,13 @@ export class ConfigurationEditingService implements IConfigurationEditingService
return false;
}
private onError(error: IConfigurationEditingError, target: ConfigurationTarget, value: IConfigurationValue): TPromise<IConfigurationEditingError> {
private onError(error: IConfigurationEditingError, target: ConfigurationTarget, value: IConfigurationValue, scopes: IConfigurationOverrides): TPromise<IConfigurationEditingError> {
switch (error.code) {
case ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION:
this.onInvalidConfigurationError(error, target);
break;
case ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY:
this.onConfigurationFileDirtyError(error, target, value);
this.onConfigurationFileDirtyError(error, target, value, scopes);
break;
default:
this.messageService.show(Severity.Error, error.message);
......@@ -130,12 +132,12 @@ export class ConfigurationEditingService implements IConfigurationEditingService
});
}
private onConfigurationFileDirtyError(error: IConfigurationEditingError, target: ConfigurationTarget, value: IConfigurationValue): void {
private onConfigurationFileDirtyError(error: IConfigurationEditingError, target: ConfigurationTarget, value: IConfigurationValue, scopes: IConfigurationOverrides): void {
this.choiceService.choose(Severity.Error, error.message, [nls.localize('saveAndRetry', "Save Settings and Retry"), nls.localize('open', "Open Settings"), nls.localize('close', "Close")], 2)
.then(option => {
switch (option) {
case 0:
this.writeConfiguration(target, value, <ConfigurationEditingOptions>{ force: true });
this.writeConfiguration(target, value, <ConfigurationEditingOptions>{ force: true, scopes });
break;
case 1:
this.openSettings(target);
......@@ -257,7 +259,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService
});
}
private getConfigurationEditOperation(target: ConfigurationTarget, config: IConfigurationValue): IConfigurationEditOperation {
private getConfigurationEditOperation(target: ConfigurationTarget, config: IConfigurationValue, overrides: IConfigurationOverrides): IConfigurationEditOperation {
// Check for standalone workspace configurations
if (config.key) {
......@@ -280,9 +282,27 @@ export class ConfigurationEditingService implements IConfigurationEditingService
}
if (target === ConfigurationTarget.USER) {
return { key: config.key, value: config.value, overrideIdentifier: config.overrideIdentifier, resource: URI.file(this.environmentService.appSettingsPath) };
return { key: config.key, value: config.value, overrideIdentifier: overrides.overrideIdentifier, resource: URI.file(this.environmentService.appSettingsPath) };
}
return { key: config.key, value: config.value, overrideIdentifier: config.overrideIdentifier, resource: this.contextService.toResource(WORKSPACE_CONFIG_DEFAULT_PATH) };
return { key: config.key, value: config.value, overrideIdentifier: overrides.overrideIdentifier, resource: this.getConfigurationFileResource(overrides.resource) };
}
private getConfigurationFileResource(resource: URI): URI {
const workspace = this.contextService.getWorkspace2();
if (workspace) {
if (resource) {
const root = this.contextService.getRoot(resource);
if (root) {
return this.toResource(WORKSPACE_CONFIG_DEFAULT_PATH, root);
}
}
return this.toResource(WORKSPACE_CONFIG_DEFAULT_PATH, workspace.roots[0]);
}
return null;
}
private toResource(relativePath: string, root: URI): URI {
return URI.file(paths.join(root.fsPath, relativePath));
}
}
......@@ -340,7 +340,7 @@ class MockConfigurationService implements IConfigurationService {
public serviceId = IConfigurationService;
public constructor(private configuration: any = {}) { }
public reloadConfiguration<T>(section?: string): TPromise<T> { return TPromise.as(this.getConfiguration()); }
public lookup<T>(key: string, overrides?: IConfigurationOverrides): IConfigurationValue<T> { return { value: getConfigurationValue<T>(this.getConfiguration(), key), default: getConfigurationValue<T>(this.getConfiguration(), key), user: getConfigurationValue<T>(this.getConfiguration(), key), workspace: void 0 }; }
public lookup<T>(key: string, overrides?: IConfigurationOverrides): IConfigurationValue<T> { return { value: getConfigurationValue<T>(this.getConfiguration(), key), default: getConfigurationValue<T>(this.getConfiguration(), key), user: getConfigurationValue<T>(this.getConfiguration(), key), workspace: void 0, folder: void 0 }; }
public keys() { return { default: [], user: [], workspace: [] }; }
public values() { return {}; }
public getConfiguration(): any { return this.configuration; }
......
......@@ -59,8 +59,8 @@ suite('ExtHostWorkspace', function () {
ws = new ExtHostWorkspace(new TestThreadService(), undefined);
assert.equal(ws.getPath(), undefined);
ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', roots: [URI.file('Folder'), URI.file('Another/Folder')] });
assert.equal(ws.getPath(), undefined);
// ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', roots: [URI.file('Folder'), URI.file('Another/Folder')] });
// assert.equal(ws.getPath(), undefined);
ws = new ExtHostWorkspace(new TestThreadService(), { id: 'foo', name: 'Test', roots: [URI.file('/Folder')] });
assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册