提交 2276eace 编写于 作者: J Johannes Rieken

Merge branch 'master' into joh/commands

......@@ -32,6 +32,7 @@ var indentationFilter = [
'!extensions/typescript/server/**',
'!test/assert.js',
'!**/package.json',
'!**/npm-shrinkwrap.json',
'!**/octicons/**',
'!**/vs/languages/sass/test/common/example.scss',
'!**/vs/languages/less/common/parser/less.grammar.txt',
......
......@@ -183,8 +183,9 @@ function packageTask(platform, arch, opts) {
var license = gulp.src(['Credits_*', 'LICENSE.txt', 'ThirdPartyNotices.txt'], { base: '.' });
var api = gulp.src('src/vs/vscode.d.ts').pipe(rename('out/vs/vscode.d.ts'));
var depsSrc = _.flatten(Object.keys(packagejson.dependencies)
.map(function (d) { return ['node_modules/' + d + '/**', '!node_modules/' + d + '/**/{test,tests}/**']; }));
var depsSrc = _.flatten(Object.keys(packagejson.dependencies).concat(Object.keys(packagejson.optionalDependencies))
.map(function (d) { return ['node_modules/' + d + '/**', '!node_modules/' + d + '/**/{test,tests}/**']; })
);
var deps = gulp.src(depsSrc, { base: '.', dot: true })
.pipe(util.cleanNodeModule('fsevents', ['binding.gyp', 'fsevents.cc', 'build/**', 'src/**', 'test/**'], true))
......
......@@ -14,5 +14,15 @@
"border: ${width} ${border-style} ${color};$0"
],
"description": "[width] [border-style] [color]"
},
"gradient": {
"prefix": "gradient",
"body": [
"background-image: -moz-linear-gradient(top, ${start-color}, ${end-color});",
"background-image: -webkit-gradient(linear, left top, left bottom, from(${start-color}), to(${end-color}));",
"background-image: -webkit-linear-gradient(top, ${start-color}, ${end-color});",
"background-image: linear-gradient(top, ${start-color}, ${end-color});"
],
"description": "Set the 'background-image' property to a linear gradient"
}
}
\ No newline at end of file
}
......@@ -96,7 +96,7 @@
"patterns": [
{
"name": "comment.block.fsharp",
"begin": "(\\(\\*)",
"begin": "(\\(\\*(?!\\)))",
"end": "(\\*\\))",
"beginCaptures": {
"1": {
......
......@@ -152,7 +152,7 @@ export default class PHPValidationProvider {
let delayer = this.delayers[key];
if (!delayer) {
delayer = new ThrottledDelayer<void>(this.trigger === RunTrigger.onType ? 250 : 0);
this.delayers[key];
this.delayers[key] = delayer;
}
delayer.trigger(() => this.doValidate(textDocument) );
}
......
......@@ -149,7 +149,9 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost {
this.triggerAllDiagnostics();
};
let handleProjectChange = () => {
this.triggerAllDiagnostics();
setTimeout(() => {
this.triggerAllDiagnostics();
}, 1500);
}
let watcher = workspace.createFileSystemWatcher('**/tsconfig.json');
watcher.onDidCreate(handleProjectCreateOrDelete);
......
......@@ -6,13 +6,70 @@
"contributes": {
"languages": [{
"id": "xml",
"extensions": [ ".xml", ".dtd", ".ascx", ".csproj", ".config", ".wxi", ".wxl", ".wxs", ".xaml", ".svg", ".svgz" ],
"extensions": [
".ascx",
".axml",
".bpmn",
".config",
".cpt",
".csl",
".csproj",
".csproj.user",
".dita",
".ditamap",
".dtd",
".dtml",
".fsproj",
".fxml",
".iml",
".isml",
".jmx",
".jsp",
".launch",
".menu",
".mxml",
".nuspec",
".opml",
".owl",
".proj",
".pt",
".pubxml",
".pubxml.user",
".rdf",
".rng",
".rss",
".shproj",
".storyboard",
".svg",
".targets",
".tld",
".vbproj",
".vbproj.user",
".vcxproj",
".vcxproj.filters",
".wsdl",
".wxi",
".wxl",
".wxs",
".xaml",
".xbl",
".xib",
".xlf",
".xliff",
".xml",
".xpdl",
".xsd",
".xul"
],
"firstLine" : "(\\<\\?xml.*)|(\\<svg)|(\\<\\!doctype\\s+svg)",
"aliases": [ "XML", "xml" ],
"configuration": "./xml.configuration.json"
}, {
"id": "xsl",
"extensions": [ ".xsl", ".xslt" ],
"extensions": [
".xsl",
".xslt"
],
"aliases": [ "XSL", "xsl" ],
"configuration": "./xsl.configuration.json"
}],
......@@ -26,4 +83,4 @@
"path": "./syntaxes/XSL.plist"
}]
}
}
\ No newline at end of file
}
......@@ -416,9 +416,9 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
},
"vscode-textmate": {
"version": "1.0.7",
"from": "vscode-textmate@1.0.7",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-1.0.7.tgz",
"version": "1.0.8",
"from": "vscode-textmate@1.0.8",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-1.0.8.tgz",
"dependencies": {
"oniguruma": {
"version": "5.1.1",
......@@ -460,6 +460,22 @@
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz"
}
}
},
"windows-mutex": {
"version": "0.1.3",
"from": "windows-mutex@0.1.3",
"dependencies": {
"bindings": {
"version": "1.2.1",
"from": "bindings@>=1.2.1 <2.0.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz"
},
"nan": {
"version": "2.1.0",
"from": "nan@>=2.1.0 <3.0.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.1.0.tgz"
}
}
}
}
}
......@@ -12,7 +12,7 @@
},
"scripts": {
"test": "node node_modules/mocha/bin/_mocha",
"preinstall": "node build/npm/preinstall.js",
"preinstall": "node build/npm/preinstall.js",
"postinstall": "npm --prefix extensions/csharp-o/ install extensions/csharp-o/ && npm --prefix extensions/vscode-api-tests/ install extensions/vscode-api-tests/"
},
"dependencies": {
......@@ -26,7 +26,7 @@
"iconv-lite": "^0.4.13",
"sax": "^1.1.1",
"semver": "^4.2.0",
"vscode-textmate": "^1.0.7",
"vscode-textmate": "^1.0.8",
"winreg": "0.0.12",
"yauzl": "^2.3.1"
},
......@@ -89,5 +89,8 @@
"ghooks": {
"pre-commit": "node build/gulpfile.hygiene.js"
}
},
"optionalDependencies": {
"windows-mutex": "^0.1.3"
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'windows-mutex' {
export class Mutex {
constructor(name: string);
isActive(): boolean;
release(): void;
}
}
\ No newline at end of file
......@@ -79,7 +79,7 @@ export class ResourceViewer {
let mime: string;
const ext = paths.extname(resource.toString());
if (ext) {
mime = mapExtToMediaMimes[ext];
mime = mapExtToMediaMimes[ext.toLowerCase()];
}
if (!mime) {
......
......@@ -262,7 +262,7 @@ export class DefaultController implements _.IController {
tree.clearHighlight(payload);
} else {
tree.focusPrevious(1, payload);
tree.reveal(tree.getFocus());
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
return true;
}
......@@ -274,7 +274,7 @@ export class DefaultController implements _.IController {
tree.clearHighlight(payload);
} else {
tree.focusPreviousPage(payload);
tree.reveal(tree.getFocus());
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
return true;
}
......@@ -286,7 +286,7 @@ export class DefaultController implements _.IController {
tree.clearHighlight(payload);
} else {
tree.focusNext(1, payload);
tree.reveal(tree.getFocus());
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
return true;
}
......@@ -298,7 +298,7 @@ export class DefaultController implements _.IController {
tree.clearHighlight(payload);
} else {
tree.focusNextPage(payload);
tree.reveal(tree.getFocus());
tree.reveal(tree.getFocus()).done(null, errors.onUnexpectedError);
}
return true;
}
......
......@@ -944,7 +944,7 @@ export class TreeModel extends Events.EventEmitter {
var item = this.getItem(element);
if (item) {
item.reveal(relativeTop);
return item.reveal(relativeTop);
}
});
}
......
......@@ -351,7 +351,7 @@
.monaco-editor.vs .token.entity { color: #A31515; }
.monaco-editor.vs .token.entity.name { color: #800000; }
.monaco-editor.vs .token.entity.name.tag { color: #800000; }
.monaco-editor.vs .token.entity.name.function { color: #444444; }
.monaco-editor.vs .token.entity.name.function { color: #000000; }
.monaco-editor.vs .token.entity.name.class { color: #2B91AF; }
.monaco-editor.vs .token.entity.name.selector { color: #800000; }
.monaco-editor.vs .token.entity.other.selector { color: #800000; }
......@@ -387,9 +387,14 @@
.monaco-editor.vs .token.meta { color: #000000; }
.monaco-editor.vs .token.meta.selector { color: #800000; }
.monaco-editor.vs .token.meta.tag { color: #800000; }
.monaco-editor.vs .token.storage { color: gray };
.monaco-editor.vs .token.storage.content { color: red };
.monaco-editor.vs .token.meta.preprocessor { color: #0000FF; }
.monaco-editor.vs .token.meta.preprocessor.string { color: #A31515; }
.monaco-editor.vs .token.meta.preprocessor.numeric { color: #09885A; }
.monaco-editor.vs .token.meta.object.type { color: #2B91AF; }
.monaco-editor.vs .token.meta.object.type.variable { color: #000000; }
.monaco-editor.vs .token.storage { color: #0000FF; }
.monaco-editor.vs .token.storage.content { color: red; }
.monaco-editor.vs .token.storage.type { color: #0000FF; }
.monaco-editor.vs .token.storage.modifier { color: #0000FF; }
.monaco-editor.vs .token.cast.storage.type,
......@@ -410,7 +415,9 @@
.monaco-editor.vs .token.string.regexp { color: #811f3f; }
/*.monaco-editor.vs .token.string.other*/
.monaco-editor.vs .token.support { color: #800000; }
.monaco-editor.vs .token.support { color: #0000FF; }
.monaco-editor.vs .token.support.function { color: #000000; }
.monaco-editor.vs .token.support.method { color: #000000; }
.monaco-editor.vs .token.support.type { color: red; }
.monaco-editor.vs .token.support.type.json { color: #A31515; }
.monaco-editor.vs .token.support.property-value { color: #0451A5; }
......@@ -515,9 +522,14 @@
.monaco-editor.vs-dark .token.meta { color: #D4D4D4; }
.monaco-editor.vs-dark .token.meta.selector { color: #569CD6; }
.monaco-editor.vs-dark .token.meta.tag { color: #CE9178; }
.monaco-editor.vs-dark .token.storage { color: #569CD6 };
.monaco-editor.vs-dark .token.storage.content { color: #9CDCFE };
.monaco-editor.vs-dark .token.meta.preprocessor { color: #569CD6; }
.monaco-editor.vs-dark .token.meta.preprocessor.string { color: #CE9178; }
.monaco-editor.vs-dark .token.meta.preprocessor.numeric { color: #B5CEA8; }
.monaco-editor.vs-dark .token.meta.object.type { color: #569CD6; }
.monaco-editor.vs-dark .token.meta.object.type.variable { color: #9CDCFE; }
.monaco-editor.vs-dark .token.storage { color: #569CD6; }
.monaco-editor.vs-dark .token.storage.content { color: #9CDCFE; }
.monaco-editor.vs-dark .token.storage.type { color: #569CD6; }
.monaco-editor.vs-dark .token.storage.modifier { color: #569CD6; }
.monaco-editor.vs-dark .token.annotation.storage.type,
......@@ -540,7 +552,9 @@
.monaco-editor.vs-dark .token.string.regexp { color: #D16969; }
/*.monaco-editor.vs-dark .token.string.other*/
.monaco-editor.vs-dark .token.support { color: #A79873; }
.monaco-editor.vs-dark .token.support { color: #569CD6; }
.monaco-editor.vs-dark .token.support.function { color: #D4D4D4; }
.monaco-editor.vs-dark .token.support.method { color: #D4D4D4; }
.monaco-editor.vs-dark .token.support.type { color: #9CDCFE; }
.monaco-editor.vs-dark .token.support.property-value { color: #CE9178; }
/*.monaco-editor.vs-dark .token.support.function
......@@ -635,7 +649,7 @@
/*.monaco-editor.hc-black .token.markup.underline.link*/
.monaco-editor.hc-black .token.markup.bold { font-weight: bold; }
.monaco-editor.hc-black .token.markup.heading { color: #6796e6; }
.monaco-editor.hc-black .token.markup.italic { font-style: italic;}
.monaco-editor.hc-black .token.markup.italic { font-style: italic; }
/*.monaco-editor.hc-black .token.markup.list
.monaco-editor.hc-black .token.markup.list.numbered
.monaco-editor.hc-black .token.markup.list.unnumbered
......@@ -646,9 +660,14 @@
.monaco-editor.hc-black .token.meta { color: #D4D4D4; }
.monaco-editor.hc-black .token.meta.selector { color: #569CD6; }
.monaco-editor.hc-black .token.meta.tag { color: #CE9178; }
.monaco-editor.hc-black .token.storage { color: #569CD6 };
.monaco-editor.hc-black .token.storage.content { color: #9CDCFE };
.monaco-editor.hc-black .token.meta.preprocessor { color: #569CD6; }
.monaco-editor.hc-black .token.meta.preprocessor.string { color: #CE9178; }
.monaco-editor.hc-black .token.meta.preprocessor.numeric { color: #B5CEA8; }
.monaco-editor.hc-black .token.meta.object.type { color: #569CD6; }
.monaco-editor.hc-black .token.meta.object.type.variable { color: #D4D4D4; }
.monaco-editor.hc-black .token.storage { color: #569CD6; }
.monaco-editor.hc-black .token.storage.content { color: #9CDCFE; }
.monaco-editor.hc-black .token.storage.type { color: #569CD6; }
.monaco-editor.hc-black .token.storage.modifier { color: #569CD6; }
.monaco-editor.hc-black .token.annotation.storage.type,
......@@ -671,7 +690,9 @@
.monaco-editor.hc-black .token.string.regexp { color: #D16969; }
/*.monaco-editor.hc-black .token.string.other*/
.monaco-editor.hc-black .token.support { color: #800000; }
.monaco-editor.hc-black .token.support { color: #569CD6; }
.monaco-editor.hc-black .token.support.function { color: #D4D4D4; }
.monaco-editor.hc-black .token.support.method { color: #D4D4D4; }
.monaco-editor.hc-black .token.support.type { color: #9CDCFE; }
.monaco-editor.hc-black .token.support.property-value { color: #CE9178; }
/*.monaco-editor.hc-black .token.support.function
......
......@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
.monaco-editor .defineKeybindingLauncher {
font-family: 'Segoe WPC', 'Segoe UI', "SFUIText-Light", HelveticaNeue-Light, sans-serif, "Droid Sans Fallback";
background: rgba(0,255,0,0.3);
padding: 10px;
border-radius: 5px;
......@@ -11,6 +12,7 @@
}
.monaco-editor .defineKeybindingWidget {
font-family: 'Segoe WPC', 'Segoe UI', "SFUIText-Light", HelveticaNeue-Light, sans-serif, "Droid Sans Fallback";
width: 340px;
height: 60px;
padding: 10px;
......@@ -22,12 +24,9 @@
}
.monaco-editor .defineKeybindingWidget .input {
margin-top:10px;
width: 320px;
display: block;
}
.monaco-editor .defineKeybindingWidget .output {
width: 320px;
text-align: center;
}
......
......@@ -158,7 +158,6 @@ class DefineKeybindingWidget implements EditorBrowser.IContentWidget {
private _messageNode: HTMLElement;
private _inputNode: HTMLInputElement;
private _outputNode: HTMLElement;
private _lastKeybinding: Keybinding;
private _onAccepted: (keybinding:string) => void;
......@@ -182,10 +181,6 @@ class DefineKeybindingWidget implements EditorBrowser.IContentWidget {
this._inputNode.className = 'input';
this._domNode.appendChild(this._inputNode);
this._outputNode = document.createElement('div');
this._outputNode.className = 'output';
this._domNode.appendChild(this._outputNode);
this._toDispose.push(DomUtils.addDisposableListener(this._inputNode, 'keydown', (e) => {
let keyEvent = new StandardKeyboardEvent(e);
keyEvent.preventDefault();
......@@ -207,8 +202,8 @@ class DefineKeybindingWidget implements EditorBrowser.IContentWidget {
this._lastKeybinding = kb;
this._outputNode.innerText = this._lastKeybinding.toUserSettingsLabel().toLowerCase();
this._outputNode.title = 'keyCode: ' + keyEvent.browserEvent.keyCode;
this._inputNode.value = this._lastKeybinding.toUserSettingsLabel().toLowerCase();
this._inputNode.title = 'keyCode: ' + keyEvent.browserEvent.keyCode;
}));
this._toDispose.push(DomUtils.addDisposableListener(this._inputNode, 'blur', (e) => this._stop()));
......@@ -248,8 +243,7 @@ class DefineKeybindingWidget implements EditorBrowser.IContentWidget {
this._editor.getOffsetForColumn(this._position.lineNumber, this._position.column);
this._lastKeybinding = null;
this._outputNode.innerText = '';
this._outputNode.title = '';
this._inputNode.value = '';
this._inputNode.focus();
}
......@@ -285,6 +279,9 @@ export class DefineKeybindingAction extends EditorAction {
const INTERESTING_FILE = /keybindings\.json$/;
function isInterestingEditorModel(editor:EditorCommon.ICommonCodeEditor): boolean {
if (editor.getConfiguration().readOnly) {
return false;
}
let model = editor.getModel();
if (!model) {
return false;
......
......@@ -281,7 +281,7 @@ export class QuickFixSelectionWidget implements EditorBrowser.IContentWidget {
this.updateWidgetHeight();
if (focus) {
this.tree.reveal(focus, (payload && payload.firstSuggestion) ? 0 : null);
return this.tree.reveal(focus, (payload && payload.firstSuggestion) ? 0 : null);
}
}, Errors.onUnexpectedError);
}));
......
......@@ -602,9 +602,12 @@ export class ReferenceWidget extends peekViewWidget.PeekViewWidget {
}, errors.onUnexpectedError);
// show in tree
this.tree.reveal(reference);
this.tree.setSelection([reference]);
this.tree.setFocus(reference);
this.tree.reveal(reference)
.then(() => {
this.tree.setSelection([reference]);
this.tree.setFocus(reference);
})
.done(null, errors.onUnexpectedError);
}
public dispose(): void {
......
......@@ -491,7 +491,7 @@ export class SuggestModel extends EventEmitter {
private onEditorConfigurationChange(): void {
this.autoSuggestDelay = this.editor.getConfiguration().quickSuggestionsDelay;
if (isNaN(this.autoSuggestDelay) || (!this.autoSuggestDelay && this.autoSuggestDelay !== 0) || this.autoSuggestDelay > 2000 || this.autoSuggestDelay < 0) {
if (isNaN(this.autoSuggestDelay) || (!this.autoSuggestDelay && this.autoSuggestDelay !== 0) || this.autoSuggestDelay < 0) {
this.autoSuggestDelay = 10;
}
}
......
......@@ -384,7 +384,7 @@ export class SuggestWidget implements EditorBrowser.IContentWidget {
this.updateWidgetHeight();
if (focus) {
this.tree.reveal(focus, (payload && payload.firstSuggestion) ? 0 : null);
return this.tree.reveal(focus, (payload && payload.firstSuggestion) ? 0 : null);
}
}, Errors.onUnexpectedError);
}));
......
......@@ -67,6 +67,7 @@ export class JSONIntellisense {
var node = doc.getNodeFromOffsetEndInclusive(offset);
var addValue = true;
var currentKey = currentWord;
var currentProperty : Parser.PropertyASTNode = null;
if (node) {
if (node.type === 'string') {
......@@ -76,6 +77,7 @@ export class JSONIntellisense {
result.overwriteBefore = position.column - nodeRange.startColumn;
result.overwriteAfter = nodeRange.endColumn - position.column;
addValue = !(node.parent && ((<Parser.PropertyASTNode> node.parent).value));
currentProperty = node.parent ? <Parser.PropertyASTNode> node.parent : null;
currentKey = modelMirror.getValueInRange({ startColumn: nodeRange.startColumn + 1, startLineNumber: nodeRange.startLineNumber, endColumn: position.column, endLineNumber: position.lineNumber });
if (node.parent) {
node = node.parent.parent;
......@@ -91,10 +93,16 @@ export class JSONIntellisense {
if (node.start === offset) {
return result;
}
// don't suggest properties that are already present
var properties = (<Parser.ObjectASTNode> node).properties;
properties.forEach(p => {
if (!currentProperty || currentProperty !== p) {
proposed[p.key.value] = true;
}
});
if (schema) {
// property proposals with schema
var properties = (<Parser.ObjectASTNode> node).properties;
var isLast = properties.length === 0 || offset >= properties[properties.length - 1].start;
collectionPromises.push(this.getPropertySuggestions(schema, doc, node, currentKey, addValue, isLast, collector));
......
......@@ -351,23 +351,23 @@ export class JSONSchemaService implements IJSONSchemaService {
schemaURL: url
});
}
return this.requestService.makeRequest({ url: url }).then(
request => {
var content = request.responseText;
if (!content) {
var errorMessage = nls.localize('json.schema.nocontent', 'Unable to load schema from \'{0}\': No content.', url) ;
var errorMessage = nls.localize('json.schema.nocontent', 'Unable to load schema from \'{0}\': No content.', toDisplayString(url));
return new UnresolvedSchema(<IJSONSchema> {}, [ errorMessage ]);
}
var schemaContent: IJSONSchema = {};
var jsonErrors = [];
schemaContent = Json.parse(content, errors);
var errors = jsonErrors.length ? [ nls.localize('json.schema.invalidFormat', 'Unable to parse content from \'{0}\': {1}.', url, jsonErrors[0])] : [];
var errors = jsonErrors.length ? [ nls.localize('json.schema.invalidFormat', 'Unable to parse content from \'{0}\': {1}.', toDisplayString(url), jsonErrors[0])] : [];
return new UnresolvedSchema(schemaContent, errors);
},
error => {
var errorMessage = nls.localize('json.schema.unabletoload', 'Unable to load schema from \'{0}\': {1}.', url, error.statusText || error.toString());
var errorMessage = nls.localize('json.schema.unabletoload', 'Unable to load schema from \'{0}\': {1}', toDisplayString(url), error.responseText || error.toString());
return new UnresolvedSchema(<IJSONSchema> {}, [ errorMessage ]);
}
);
......@@ -1562,4 +1562,16 @@ export class JSONSchemaService implements IJSONSchemaService {
});
}
}
function toDisplayString(url:string) {
try {
var uri = URI.parse(url);
if (uri.scheme === 'file') {
return uri.fsPath;
}
} catch (e) {
// ignore
}
return url;
}
\ No newline at end of file
......@@ -179,9 +179,8 @@ suite('JSON - Worker', () => {
assertSuggestion(result, 'name');
}),
testSuggestionsFor('[ { "name": "John", "address": { "street" : "MH Road", "number" : 5 } }, { "name": "Jack", "address": { "street" : "100 Feet Road", /**/ }', '/**/').then((result) => {
assert.strictEqual(result.suggestions.length, 2);
assert.strictEqual(result.suggestions.length, 1);
assertSuggestion(result, 'number');
assertSuggestion(result, 'street');
})
]).done(() => testDone(), (errors:any[]) => {
testDone(errors.reduce((e1, e2) => e1 || e2));
......@@ -216,8 +215,7 @@ suite('JSON - Worker', () => {
assertSuggestion(result, '"xoo"');
}),
testSuggestionsFor('[ { "data": "foo" }, { "data": "bar" }, { "data": "xoo" /**/ } ]', '/**/').then((result) => {
assert.strictEqual(result.suggestions.length, 1);
assertSuggestion(result, 'data');
assert.strictEqual(result.suggestions.length, 0);
})
]).done(() => testDone(), (errors:any[]) => {
testDone(errors.reduce((e1, e2) => e1 || e2));
......@@ -260,8 +258,7 @@ suite('JSON - Worker', () => {
assertSuggestion(result, 'a', 'A');
}),
testSuggestionsFor('{ "a" = 1;/**/}', '/**/', schema).then((result) => {
assert.strictEqual(result.suggestions.length, 3);
assertSuggestion(result, 'a', 'A');
assert.strictEqual(result.suggestions.length, 2);
assertSuggestion(result, 'b', 'B');
assertSuggestion(result, 'c', 'C');
})
......@@ -375,8 +372,7 @@ suite('JSON - Worker', () => {
assertSuggestion(result, 'd', 'D');
}),
testSuggestionsFor('{ "a": "", /**/}', '/**/', schema).then((result) => {
assert.strictEqual(result.suggestions.length, 2);
assertSuggestion(result, 'a', 'A');
assert.strictEqual(result.suggestions.length, 1);
assertSuggestion(result, 'b', 'B');
})
]).done(() => testDone(), (errors:any[]) => {
......@@ -417,8 +413,7 @@ suite('JSON - Worker', () => {
assertSuggestion(result, 'c');
}),
testSuggestionsFor('{ "type": "appartment", /**/}', '/**/', schema).then((result) => {
assert.strictEqual(result.suggestions.length, 2);
assertSuggestion(result, 'type');
assert.strictEqual(result.suggestions.length, 1);
assertSuggestion(result, 'c');
})
]).done(() => testDone(), (errors:any[]) => {
......@@ -480,9 +475,8 @@ suite('JSON - Worker', () => {
assertSuggestion(result, 'd', 'D');
}),
testSuggestionsFor('{ "b1": "", /**/}', '/**/', schema).then((result) => {
assert.strictEqual(result.suggestions.length, 3);
assert.strictEqual(result.suggestions.length, 2);
assertSuggestion(result, 'a', 'A');
assertSuggestion(result, 'b1', 'B1');
assertSuggestion(result, 'b2', 'B2');
})
]).done(() => testDone(), (errors:any[]) => {
......
......@@ -7,6 +7,7 @@
import WinJS = require('vs/base/common/winjs.base');
import Monarch = require('vs/editor/common/modes/monarch/monarch');
import Network = require('vs/base/common/network');
import URI from 'vs/base/common/uri';
import Types = require('vs/editor/common/modes/monarch/monarchTypes');
import Compile = require('vs/editor/common/modes/monarch/monarchCompile');
import EditorCommon = require('vs/editor/common/editorCommon');
......@@ -204,7 +205,6 @@ export const language =
};
export class MarkdownMode extends Monarch.MonarchMode<MarkdownWorker.MarkdownWorker> implements Modes.IEmitOutputSupport {
private baseUrl: string;
public emitOutputSupport: Modes.IEmitOutputSupport;
......@@ -219,9 +219,6 @@ export class MarkdownMode extends Monarch.MonarchMode<MarkdownWorker.MarkdownWor
super(descriptor, Compile.compile(language), instantiationService, threadService, modeService, modelService);
this.emitOutputSupport = this;
const workspace = workspaceContextService && workspaceContextService.getWorkspace();
this.baseUrl = workspace && workspace.resource.toString();
}
public getCommentsConfiguration(): Modes.ICommentsConfiguration {
......@@ -229,8 +226,8 @@ export class MarkdownMode extends Monarch.MonarchMode<MarkdownWorker.MarkdownWor
}
static $getEmitOutput = OneWorkerAttr(MarkdownMode, MarkdownMode.prototype.getEmitOutput);
public getEmitOutput(resource: Network.URL, absoluteWorkerResourcesPath?: string): WinJS.TPromise<Modes.IEmitOutput> { // TODO@Ben technical debt: worker cannot resolve paths absolute
return this._worker((w) => w.getEmitOutput(resource, this.baseUrl, absoluteWorkerResourcesPath));
public getEmitOutput(resource: URI, absoluteWorkerResourcesPath?: string): WinJS.TPromise<Modes.IEmitOutput> { // TODO@Ben technical debt: worker cannot resolve paths absolute
return this._worker((w) => w.getEmitOutput(resource, absoluteWorkerResourcesPath));
}
protected _getWorkerDescriptor(): AsyncDescriptor2<Modes.IMode, Modes.IWorkerParticipant[], MarkdownWorker.MarkdownWorker> {
......
......@@ -7,6 +7,7 @@
import WinJS = require('vs/base/common/winjs.base');
import {AbstractModeWorker} from 'vs/editor/common/modes/abstractModeWorker';
import Network = require('vs/base/common/network');
import URI from 'vs/base/common/uri';
import Types = require('vs/base/common/types');
import EditorCommon = require('vs/editor/common/editorCommon');
import Modes = require('vs/editor/common/modes');
......@@ -101,7 +102,7 @@ export class MarkdownWorker extends AbstractModeWorker {
private modeService: IModeService;
constructor(mode: Modes.IMode, participants: Modes.IWorkerParticipant[], @IResourceService resourceService: IResourceService,
@IMarkerService markerService: IMarkerService, @IModeService modeService:IModeService) {
@IMarkerService markerService: IMarkerService, @IModeService modeService: IModeService) {
super(mode, participants, resourceService, markerService);
this.modeService = modeService;
......@@ -119,15 +120,15 @@ export class MarkdownWorker extends AbstractModeWorker {
return WinJS.TPromise.as(false);
}
public getEmitOutput(resource: Network.URL, baseUrl: string, absoluteWorkersResourcePath: string): WinJS.TPromise<Modes.IEmitOutput> { // TODO@Ben technical debt: worker cannot resolve paths absolute
let model = this.resourceService.get(resource);
public getEmitOutput(resource: URI, absoluteWorkersResourcePath: string): WinJS.TPromise<Modes.IEmitOutput> { // TODO@Ben technical debt: worker cannot resolve paths absolute
let model = this.resourceService.get(Network.URL.fromUri(resource));
let cssLinks: string[] = this.cssLinks || [];
// Custom Renderer to fix href in images
let renderer = new Marked.marked.Renderer();
let $this = this;
renderer.image = function(href: string, title: string, text: string): string {
let out = '<img src="' + $this.fixHref(resource, href, baseUrl) + '" alt="' + text + '"';
let out = '<img src="' + $this.fixHref(resource, href) + '" alt="' + text + '"';
if (title) {
out += ' title="' + title + '"';
}
......@@ -182,10 +183,9 @@ export class MarkdownWorker extends AbstractModeWorker {
'<meta http-equiv="Content-type" content="text/html;charset=UTF-8">',
(cssLinks.length === 0) ? '<link rel="stylesheet" href="' + absoluteWorkersResourcePath + '/markdown.css" type="text/css" media="screen">' : '',
(cssLinks.length === 0) ? '<link rel="stylesheet" href="' + absoluteWorkersResourcePath + '/tokens.css" type="text/css" media="screen">' : '',
'<base href="' + baseUrl + '" />',
(this.theme === Theme.LIGHT) ? MarkdownWorker.LIGHT_SCROLLBAR_CSS : (this.theme === Theme.DARK) ? MarkdownWorker.DARK_SCROLLBAR_CSS : MarkdownWorker.HC_BLACK_SCROLLBAR_CSS,
cssLinks.map((style) => {
return '<link rel="stylesheet" href="' + this.fixHref(resource, style, baseUrl) + '" type="text/css" media="screen">';
return '<link rel="stylesheet" href="' + this.fixHref(resource, style) + '" type="text/css" media="screen">';
}).join('\n'),
'</head>',
isMacintosh ? '<body class="mac">' : '<body>'
......@@ -213,26 +213,16 @@ export class MarkdownWorker extends AbstractModeWorker {
});
}
private fixHref(resource: Network.URL, href: string, baseUrl: string): string {
private fixHref(resource: URI, href: string): string {
if (href) {
let url = new Network.URL(href);
// URL is actually a path
if (!url.getScheme()) {
let path = href;
// the user might have used windows backslash, but we only support slashes in URLs, so fix up
path = Strings.replaceAll(path, '\\', '/');
// Absolute path: resolve against base URL
if (path[0] === '/') {
return Paths.join(baseUrl, path);
}
// Relative path: resolve against resource URL
let resourcePath = resource.getPath();
return Paths.join(Paths.dirname(resourcePath), path);
// Return early if href is already a URL
if (new Network.URL(href).getScheme()) {
return href;
}
// Otherwise convert to a file URI by joining the href with the resource location
return URI.file(Paths.join(Paths.dirname(resource.fsPath), href)).toString();
}
return href;
......
......@@ -9,7 +9,6 @@ import app = require('app');
import fs = require('fs');
import dialog = require('dialog');
import shell = require('shell');
import nls = require('vs/nls');
import {assign} from 'vs/base/common/objects';
import platform = require('vs/base/common/platform');
......@@ -233,6 +232,15 @@ function setupIPC(): TPromise<Server> {
return setup(true);
}
function setupMutex() {
try {
var Mutex = (<any> require.__$__nodeRequire('windows-mutex')).Mutex;
new Mutex('vscode');
} catch (e) {
// noop
}
}
// On some platforms we need to manually read from the global environment variables
// and assign them to the process environment (e.g. when doubleclick app on Mac)
getUserEnvironment()
......@@ -241,6 +249,7 @@ getUserEnvironment()
return timebomb()
.then(setupIPC)
.then(ipcServer => { setupMutex(); return ipcServer; })
.then(ipcServer => main(ipcServer, userEnv));
})
.done(null, quit);
......@@ -266,7 +266,8 @@ export class RemoveBreakpointAction extends AbstractDebugAction {
}
public run(breakpoint: debug.IBreakpoint): Promise {
return this.debugService.toggleBreakpoint(breakpoint.source.uri, breakpoint.lineNumber);
return breakpoint instanceof model.Breakpoint ? this.debugService.toggleBreakpoint(breakpoint.source.uri, breakpoint.lineNumber)
: this.debugService.removeFunctionBreakpoints(breakpoint.getId());
}
}
......@@ -280,7 +281,7 @@ export class RemoveAllBreakpointsAction extends AbstractDebugAction {
}
public run(): Promise {
return this.debugService.clearBreakpoints();
return Promise.join([this.debugService.removeBreakpoints(), this.debugService.removeFunctionBreakpoints()]);
}
protected isEnabled(): boolean {
......@@ -379,6 +380,20 @@ export class ReapplyBreakpointsAction extends AbstractDebugAction {
}
}
export class AddFunctionBreakpointAction extends AbstractDebugAction {
static ID = 'workbench.debug.viewlet.action.addFunctionBreakpointAction';
static LABEL = nls.localize('addFunctionBreakpoint', "Add Function Breakpoint");
constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) {
super(id, label, 'debug-action add-function-breakpoint', debugService, keybindingService);
}
public run(): Promise {
this.debugService.addFunctionBreakpoint();
return Promise.as(null);
}
}
export class ToggleBreakpointAction extends EditorAction {
static ID = 'editor.debug.action.toggleBreakpoint';
......
......@@ -3,10 +3,12 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import nls = require('vs/nls');
import { Promise, TPromise } from 'vs/base/common/winjs.base';
import lifecycle = require('vs/base/common/lifecycle');
import paths = require('vs/base/common/paths');
import async = require('vs/base/common/async');
import errors = require('vs/base/common/errors');
import severity from 'vs/base/common/severity';
import strings = require('vs/base/common/strings');
import { isMacintosh } from 'vs/base/common/platform';
......@@ -65,6 +67,55 @@ export function renderVariable(tree: tree.ITree, variable: model.Variable, data:
}
}
function renderRenameBox(debugService: debug.IDebugService, contextViewService: IContextViewService, tree: tree.ITree, element: any, container: HTMLElement, placeholder: string): void {
let inputBoxContainer = dom.append(container, $('.inputBoxContainer'));
let inputBox = new inputbox.InputBox(inputBoxContainer, contextViewService, {
validationOptions: {
validation: null,
showMessage: false
},
placeholder: placeholder
});
inputBox.value = element.name ? element.name : '';
inputBox.focus();
var disposed = false;
var toDispose: [lifecycle.IDisposable] = [inputBox];
var wrapUp = async.once<any, void>((renamed: boolean) => {
if (!disposed) {
disposed = true;
if (element instanceof model.Expression && renamed && inputBox.value) {
debugService.renameWatchExpression(element.getId(), inputBox.value).done(null, errors.onUnexpectedError);
} else if (element instanceof model.Expression && !element.name) {
debugService.clearWatchExpressions(element.getId());
} else if (element instanceof model.FunctionBreakpoint && renamed && inputBox.value) {
debugService.renameFunctionBreakpoint(element.getId(), inputBox.value).done(null, errors.onUnexpectedError);
} else if (element instanceof model.FunctionBreakpoint && !element.name) {
debugService.removeFunctionBreakpoints(element.getId()).done(null, errors.onUnexpectedError);
}
tree.clearHighlight();
tree.DOMFocus();
// Need to remove the input box since this template will be reused.
container.removeChild(inputBoxContainer);
lifecycle.disposeAll(toDispose);
}
});
toDispose.push(dom.addStandardDisposableListener(inputBox.inputElement, 'keydown', (e: dom.IKeyboardEvent) => {
let isEscape = e.equals(CommonKeybindings.ESCAPE);
let isEnter = e.equals(CommonKeybindings.ENTER);
if (isEscape || isEnter) {
wrapUp(isEnter);
}
}));
toDispose.push(dom.addDisposableListener(inputBox.inputElement, 'blur', () => {
wrapUp(true);
}));
}
export class SimpleActionProvider implements renderer.IActionProvider {
constructor() {
......@@ -543,7 +594,7 @@ export class WatchExpressionsRenderer implements tree.IRenderer {
private renderWatchExpression(tree: tree.ITree, watchExpression: debug.IExpression, data: IWatchExpressionTemplateData): void {
let selectedExpression = this.debugService.getViewModel().getSelectedExpression();
if ((selectedExpression instanceof model.Expression && selectedExpression.getId() === watchExpression.getId()) || (watchExpression instanceof model.Expression && !watchExpression.name)) {
this.renderRenameBox(tree, watchExpression, data);
renderRenameBox(this.debugService, this.contextViewService, tree, watchExpression, data.expression, nls.localize('watchExpressionPlaceholder', "Expression to watch"));
}
data.actionBar.context = watchExpression;
......@@ -557,49 +608,6 @@ export class WatchExpressionsRenderer implements tree.IRenderer {
}
}
private renderRenameBox(tree: tree.ITree, expression: debug.IExpression, data: IWatchExpressionTemplateData): void {
let inputBoxContainer = dom.append(data.expression, $('.inputBoxContainer'));
let inputBox = new inputbox.InputBox(inputBoxContainer, this.contextViewService, {
validationOptions: {
validation: null,
showMessage: false
}
});
inputBox.value = expression.name ? expression.name : '';
inputBox.focus();
var disposed = false;
var toDispose: [lifecycle.IDisposable] = [inputBox];
var wrapUp = async.once<any, void>((renamed: boolean) => {
if (!disposed) {
disposed = true;
if (renamed && inputBox.value) {
this.debugService.renameWatchExpression(expression.getId(), inputBox.value);
} else if (!expression.name) {
this.debugService.clearWatchExpressions(expression.getId());
}
tree.clearHighlight();
tree.DOMFocus();
// Need to remove the input box since this template will be reused.
data.expression.removeChild(inputBoxContainer);
lifecycle.disposeAll(toDispose);
}
});
toDispose.push(dom.addStandardDisposableListener(inputBox.inputElement, 'keydown', (e: dom.IKeyboardEvent) => {
let isEscape = e.equals(CommonKeybindings.ESCAPE);
let isEnter = e.equals(CommonKeybindings.ENTER);
if (isEscape || isEnter) {
wrapUp(isEnter);
}
}));
toDispose.push(dom.addDisposableListener(inputBox.inputElement, 'blur', () => {
wrapUp(true);
}));
}
public disposeTemplate(tree: tree.ITree, templateId: string, templateData: any): void {
// noop
}
......@@ -673,7 +681,7 @@ export class BreakpointsActionProvider extends SimpleActionProvider {
}
public hasSecondaryActions(tree: tree.ITree, element: any): boolean {
return element instanceof model.Breakpoint || element instanceof model.ExceptionBreakpoint;
return element instanceof model.Breakpoint || element instanceof model.ExceptionBreakpoint || element instanceof model.FunctionBreakpoint;
}
public getActions(tree: tree.ITree, element: any): TPromise<actions.IAction[]> {
......@@ -703,6 +711,9 @@ export class BreakpointsActionProvider extends SimpleActionProvider {
actions.push(this.instantiationService.createInstance(debugactions.DisableAllBreakpointsAction, debugactions.DisableAllBreakpointsAction.ID, debugactions.DisableAllBreakpointsAction.LABEL));
actions.push(new actionbar.Separator());
actions.push(this.instantiationService.createInstance(debugactions.AddFunctionBreakpointAction, debugactions.AddFunctionBreakpointAction.ID, debugactions.AddFunctionBreakpointAction.LABEL));
actions.push(new actionbar.Separator());
actions.push(this.instantiationService.createInstance(debugactions.ReapplyBreakpointsAction, debugactions.ReapplyBreakpointsAction.ID, debugactions.ReapplyBreakpointsAction.LABEL));
return Promise.as(actions);
......@@ -723,7 +734,7 @@ export class BreakpointsDataSource implements tree.IDataSource {
var model = <model.Model> element;
var exBreakpoints = <debug.IEnablement[]> model.getExceptionBreakpoints();
return Promise.as(exBreakpoints.concat(model.getBreakpoints()));
return Promise.as(exBreakpoints.concat(model.getFunctionBreakpoints()).concat(model.getBreakpoints()));
}
public getParent(tree: tree.ITree, element: any): Promise {
......@@ -732,6 +743,7 @@ export class BreakpointsDataSource implements tree.IDataSource {
}
interface IExceptionBreakpointTemplateData {
breakpoint: HTMLElement;
name: HTMLElement;
checkbox: HTMLInputElement;
toDisposeBeforeRender: lifecycle.IDisposable[];
......@@ -743,9 +755,14 @@ interface IBreakpointTemplateData extends IExceptionBreakpointTemplateData {
filePath: HTMLElement;
}
interface IFunctionBreakpointTemplateData extends IExceptionBreakpointTemplateData {
actionBar: actionbar.ActionBar;
}
export class BreakpointsRenderer implements tree.IRenderer {
private static EXCEPTION_BREAKPOINT_TEMPLATE_ID = 'exceptionBreakpoint';
private static FUNCTION_BREAKPOINT_TEMPLATE_ID = 'functionBreakpoint';
private static BREAKPOINT_TEMPLATE_ID = 'breakpoint';
constructor(
......@@ -753,7 +770,8 @@ export class BreakpointsRenderer implements tree.IRenderer {
private actionRunner: actions.IActionRunner,
@IMessageService private messageService: IMessageService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@debug.IDebugService private debugService: debug.IDebugService
@debug.IDebugService private debugService: debug.IDebugService,
@IContextViewService private contextViewService: IContextViewService
) {
// noop
}
......@@ -766,6 +784,9 @@ export class BreakpointsRenderer implements tree.IRenderer {
if (element instanceof model.Breakpoint) {
return BreakpointsRenderer.BREAKPOINT_TEMPLATE_ID;
}
if (element instanceof model.FunctionBreakpoint) {
return BreakpointsRenderer.FUNCTION_BREAKPOINT_TEMPLATE_ID;
}
if (element instanceof model.ExceptionBreakpoint) {
return BreakpointsRenderer.EXCEPTION_BREAKPOINT_TEMPLATE_ID;
}
......@@ -775,65 +796,73 @@ export class BreakpointsRenderer implements tree.IRenderer {
public renderTemplate(tree: tree.ITree, templateId: string, container: HTMLElement): any {
var data: IBreakpointTemplateData = Object.create(null);
if (templateId === BreakpointsRenderer.BREAKPOINT_TEMPLATE_ID) {
if (templateId === BreakpointsRenderer.BREAKPOINT_TEMPLATE_ID || templateId === BreakpointsRenderer.FUNCTION_BREAKPOINT_TEMPLATE_ID) {
data.actionBar = new actionbar.ActionBar(container, { actionRunner: this.actionRunner });
data.actionBar.push(this.actionProvider.getBreakpointActions(), { icon: true, label: false });
}
var el = dom.append(container, $('.breakpoint'));
data.breakpoint = dom.append(container, $('.breakpoint'));
data.toDisposeBeforeRender = [];
data.checkbox = <HTMLInputElement> $('input');
data.checkbox.type = 'checkbox';
data.checkbox.className = 'checkbox';
dom.append(el, data.checkbox);
dom.append(data.breakpoint, data.checkbox);
data.name = dom.append(el, $('span.name'));
data.name = dom.append(data.breakpoint, $('span.name'));
if (templateId === BreakpointsRenderer.BREAKPOINT_TEMPLATE_ID) {
data.lineNumber = dom.append(el, $('span.line-number'));
data.filePath = dom.append(el, $('span.file-path'));
data.lineNumber = dom.append(data.breakpoint, $('span.line-number'));
data.filePath = dom.append(data.breakpoint, $('span.file-path'));
}
return data;
}
public renderElement(tree: tree.ITree, element: any, templateId: string, templateData: any): void {
templateData.toDisposeBeforeRender = lifecycle.disposeAll(templateData.toDisposeBeforeRender);
templateData.toDisposeBeforeRender.push(dom.addStandardDisposableListener(templateData.checkbox, 'change', (e) => {
this.debugService.toggleEnablement(element);
}));
if (templateId === BreakpointsRenderer.EXCEPTION_BREAKPOINT_TEMPLATE_ID) {
this.renderExceptionBreakpoint(element, templateData);
} else if (templateId === BreakpointsRenderer.FUNCTION_BREAKPOINT_TEMPLATE_ID) {
this.renderFunctionBreakpoint(tree, element, templateData);
} else {
this.renderBreakpoint(tree, element, templateData);
}
}
private renderExceptionBreakpoint(exceptionBreakpoint: debug.IExceptionBreakpoint, data: IExceptionBreakpointTemplateData): void {
data.toDisposeBeforeRender = lifecycle.disposeAll(data.toDisposeBeforeRender);
var namePascalCase = exceptionBreakpoint.name.charAt(0).toUpperCase() + exceptionBreakpoint.name.slice(1);
data.name.textContent = `${ namePascalCase} exceptions`;
data.checkbox.checked = exceptionBreakpoint.enabled;
}
data.toDisposeBeforeRender.push(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
this.debugService.toggleEnablement(exceptionBreakpoint);
}));
private renderFunctionBreakpoint(tree: tree.ITree, functionBreakpoint: debug.IFunctionBreakpoint, data: IFunctionBreakpointTemplateData): void {
if (!functionBreakpoint.name) {
renderRenameBox(this.debugService, this.contextViewService, tree, functionBreakpoint, data.breakpoint, nls.localize('functionBreakpointPlaceholder', "Function to break on"));
} else {
this.debugService.getModel().areBreakpointsActivated() ? tree.removeTraits('disabled', [functionBreakpoint]) : tree.addTraits('disabled', [functionBreakpoint]);
data.name.textContent = functionBreakpoint.name;
data.checkbox.checked = functionBreakpoint.enabled;
}
data.actionBar.context = functionBreakpoint;
}
private renderBreakpoint(tree: tree.ITree, breakpoint: debug.IBreakpoint, data: IBreakpointTemplateData): void {
this.debugService.getModel().areBreakpointsActivated() ? tree.removeTraits('disabled', [breakpoint]) : tree.addTraits('disabled', [breakpoint]);
data.toDisposeBeforeRender = lifecycle.disposeAll(data.toDisposeBeforeRender);
data.name.textContent = labels.getPathLabel(paths.basename(breakpoint.source.uri.fsPath), this.contextService);
data.lineNumber.textContent = breakpoint.desiredLineNumber !== breakpoint.lineNumber ? breakpoint.desiredLineNumber + ' \u2192 ' + breakpoint.lineNumber : '' + breakpoint.lineNumber;
data.filePath.textContent = labels.getPathLabel(paths.dirname(breakpoint.source.uri.fsPath), this.contextService);
data.checkbox.checked = breakpoint.enabled;
data.actionBar.context = breakpoint;
data.toDisposeBeforeRender.push(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
this.debugService.toggleEnablement(breakpoint);
}));
}
public disposeTemplate(tree: tree.ITree, templateId: string, templateData: any): void {
if (templateId === BreakpointsRenderer.BREAKPOINT_TEMPLATE_ID) {
if (templateId === BreakpointsRenderer.BREAKPOINT_TEMPLATE_ID || templateId === BreakpointsRenderer.FUNCTION_BREAKPOINT_TEMPLATE_ID) {
templateData.actionBar.dispose();
}
}
......@@ -869,10 +898,15 @@ export class BreakpointsController extends BaseDebugController {
}
protected onDelete(tree: tree.ITree, event: keyboard.StandardKeyboardEvent): boolean {
var element = tree.getFocus();
const element = tree.getFocus();
if (element instanceof model.Breakpoint) {
var bp = <model.Breakpoint> element;
this.debugService.toggleBreakpoint(bp.source.uri, bp.lineNumber);
const bp = <model.Breakpoint> element;
this.debugService.toggleBreakpoint(bp.source.uri, bp.lineNumber).done(null, errors.onUnexpectedError);
return true;
} else if (element instanceof model.FunctionBreakpoint) {
const fbp = <model.FunctionBreakpoint> element;
this.debugService.removeFunctionBreakpoints(fbp.getId()).done(null, errors.onUnexpectedError);
return true;
}
......
......@@ -297,7 +297,8 @@ class BreakpointsView extends viewlet.AdaptiveCollapsibleViewletView {
@IInstantiationService private instantiationService: IInstantiationService
) {
super(actionRunner, BreakpointsView.getExpandedBodySize(
debugService.getModel().getBreakpoints().length + debugService.getModel().getExceptionBreakpoints().length), !!settings[BreakpointsView.MEMENTO], 'breakpointsView', messageService, contextMenuService);
debugService.getModel().getBreakpoints().length + debugService.getModel().getFunctionBreakpoints().length + debugService.getModel().getExceptionBreakpoints().length),
!!settings[BreakpointsView.MEMENTO], 'breakpointsView', messageService, contextMenuService);
this.toDispose.push(this.debugService.getModel().addListener2(debug.ModelEvents.BREAKPOINTS_UPDATED,() => this.onBreakpointsChange()));
}
......@@ -327,6 +328,12 @@ class BreakpointsView extends viewlet.AdaptiveCollapsibleViewletView {
if (second instanceof model.ExceptionBreakpoint) {
return 1;
}
if (first instanceof model.FunctionBreakpoint) {
return -1;
}
if(second instanceof model.FunctionBreakpoint) {
return 1;
}
if (first.source.uri.toString() !== second.source.uri.toString()) {
return first.source.uri.toString().localeCompare(second.source.uri.toString());
......@@ -369,6 +376,7 @@ class BreakpointsView extends viewlet.AdaptiveCollapsibleViewletView {
public getActions(): actions.IAction[] {
return [
this.instantiationService.createInstance(dbgactions.AddFunctionBreakpointAction, dbgactions.AddFunctionBreakpointAction.ID, dbgactions.AddFunctionBreakpointAction.LABEL),
this.instantiationService.createInstance(dbgactions.ReapplyBreakpointsAction, dbgactions.ReapplyBreakpointsAction.ID, dbgactions.ReapplyBreakpointsAction.LABEL),
this.instantiationService.createInstance(dbgactions.ToggleBreakpointsActivatedAction, dbgactions.ToggleBreakpointsActivatedAction.ID, dbgactions.ToggleBreakpointsActivatedAction.LABEL),
this.instantiationService.createInstance(dbgactions.RemoveAllBreakpointsAction, dbgactions.RemoveAllBreakpointsAction.ID, dbgactions.RemoveAllBreakpointsAction.LABEL)
......@@ -376,7 +384,9 @@ class BreakpointsView extends viewlet.AdaptiveCollapsibleViewletView {
}
private onBreakpointsChange(): void {
this.expandedBodySize = BreakpointsView.getExpandedBodySize(this.debugService.getModel().getBreakpoints().length + this.debugService.getModel().getExceptionBreakpoints().length);
const model = this.debugService.getModel();
this.expandedBodySize = BreakpointsView.getExpandedBodySize(
model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getFunctionBreakpoints().length);
if (this.tree) {
this.tree.refresh();
......
......@@ -124,6 +124,9 @@
.debug-viewlet .monaco-inputbox {
width: 100%;
line-height: normal;
}
.debug-viewlet .debug-watch .monaco-inputbox {
font-family: Monaco, Menlo, Consolas, "Droid Sans Mono", "Inconsolata", "Courier New", monospace, "Droid Sans Fallback";
}
......@@ -135,7 +138,8 @@
padding: 1px 2px;
}
.debug-viewlet .debug-action.add-watch-expression {
.debug-viewlet .debug-action.add-watch-expression,
.debug-viewlet .debug-action.add-function-breakpoint {
background: url('add.svg') center center no-repeat;
}
......@@ -154,10 +158,6 @@
text-overflow: ellipsis;
}
.debug-viewlet .debug-breakpoints .breakpoint > * {
vertical-align: middle;
}
.debug-viewlet .debug-breakpoints .breakpoint > .file-path {
opacity: 0.7;
font-size: 0.9em;
......
......@@ -74,6 +74,10 @@ export interface IBreakpoint extends IEnablement {
condition: string;
}
export interface IFunctionBreakpoint extends IEnablement {
name: string;
}
export interface IExceptionBreakpoint extends IEnablement {
name: string;
}
......@@ -119,6 +123,7 @@ export interface IModel extends ee.IEventEmitter, ITreeElement {
getThreads(): { [reference: number]: IThread; };
getBreakpoints(): IBreakpoint[];
areBreakpointsActivated(): boolean;
getFunctionBreakpoints(): IFunctionBreakpoint[];
getExceptionBreakpoints(): IExceptionBreakpoint[];
getWatchExpressions(): IExpression[];
getReplElements(): ITreeElement[];
......@@ -214,10 +219,14 @@ export interface IDebugService extends ee.IEventEmitter {
toggleBreakpoint(modelUri: uri, lineNumber: number, condition?: string): Promise;
enableOrDisableAllBreakpoints(enabled: boolean): Promise;
toggleEnablement(element: IEnablement): Promise;
clearBreakpoints(modelUri?: uri): Promise;
removeBreakpoints(modelUri?: uri): Promise;
toggleBreakpointsActivated(): Promise;
sendAllBreakpoints(): Promise;
addFunctionBreakpoint(functionName?: string): Promise;
renameFunctionBreakpoint(id: string, newFunctionName: string): Promise;
removeFunctionBreakpoints(id?: string): Promise;
addReplExpression(name: string): Promise;
clearReplExpressions(): void;
......
......@@ -267,6 +267,19 @@ export class Breakpoint implements debug.IBreakpoint {
}
}
export class FunctionBreakpoint implements debug.IFunctionBreakpoint {
private id: string;
constructor(public name: string, public enabled: boolean) {
this.id = uuid.generateUuid();
}
public getId(): string {
return this.id;
}
}
export class ExceptionBreakpoint implements debug.IExceptionBreakpoint {
private id: string;
......@@ -286,7 +299,7 @@ export class Model extends ee.EventEmitter implements debug.IModel {
private toDispose: lifecycle.IDisposable[];
private replElements: debug.ITreeElement[];
constructor(private breakpoints: debug.IBreakpoint[], private breakpointsActivated: boolean,
constructor(private breakpoints: debug.IBreakpoint[], private breakpointsActivated: boolean, private functionBreakpoints: debug.IFunctionBreakpoint[],
private exceptionBreakpoints: debug.IExceptionBreakpoint[], private watchExpressions: Expression[]) {
super();
......@@ -331,6 +344,10 @@ export class Model extends ee.EventEmitter implements debug.IModel {
return this.breakpoints;
}
public getFunctionBreakpoints(): debug.IFunctionBreakpoint[] {
return this.functionBreakpoints;
}
public getExceptionBreakpoints(): debug.IExceptionBreakpoint[] {
return this.exceptionBreakpoints;
}
......@@ -378,9 +395,8 @@ export class Model extends ee.EventEmitter implements debug.IModel {
bp.lineNumber = bp.desiredLineNumber;
}
});
this.exceptionBreakpoints.forEach(ebp => {
ebp.enabled = enabled;
});
this.exceptionBreakpoints.forEach(ebp => ebp.enabled = enabled);
this.functionBreakpoints.forEach(fbp => fbp.enabled = enabled);
this.emit(debug.ModelEvents.BREAKPOINTS_UPDATED);
}
......@@ -396,18 +412,36 @@ export class Model extends ee.EventEmitter implements debug.IModel {
}
public setBreakpointsForModel(modelUri: uri, data: { lineNumber: number; enabled: boolean; condition?: string; }[]): void {
this.clearBreakpoints(modelUri);
this.removeBreakpoints(modelUri);
for (var i = 0, len = data.length; i < len; i++) {
this.breakpoints.push(new Breakpoint(Source.fromUri(modelUri), data[i].lineNumber, data[i].enabled, data[i].condition));
}
this.emit(debug.ModelEvents.BREAKPOINTS_UPDATED);
}
public clearBreakpoints(modelUri: uri): void {
public removeBreakpoints(modelUri: uri): void {
this.breakpoints = this.breakpoints.filter(bp => modelUri && modelUri.toString() !== bp.source.uri.toString());
this.emit(debug.ModelEvents.BREAKPOINTS_UPDATED);
}
public addFunctionBreakpoint(functionName: string): void {
this.functionBreakpoints.push(new FunctionBreakpoint(functionName, true));
this.emit(debug.ModelEvents.BREAKPOINTS_UPDATED);
}
public renameFunctionBreakpoint(id: string, newFunctionName: string): void {
const fbp = this.functionBreakpoints.filter(bp => bp.getId() === id).pop();
if (fbp) {
fbp.name = newFunctionName;
this.emit(debug.ModelEvents.BREAKPOINTS_UPDATED);
}
}
public removeFunctionBreakpoints(id?: string): void {
this.functionBreakpoints = id ? this.functionBreakpoints.filter(fbp => fbp.getId() != id) : [];
this.emit(debug.ModelEvents.BREAKPOINTS_UPDATED);
}
public getReplElements(): debug.ITreeElement[] {
return this.replElements;
}
......@@ -600,6 +634,7 @@ export class Model extends ee.EventEmitter implements debug.IModel {
this.threads = null;
this.breakpoints = null;
this.exceptionBreakpoints = null;
this.functionBreakpoints = null;
this.watchExpressions = null;
this.replElements = null;
this.toDispose = lifecycle.disposeAll(this.toDispose);
......
......@@ -48,6 +48,7 @@ import { ILogEntry, PLUGIN_LOG_BROADCAST_CHANNEL } from 'vs/workbench/services/t
var DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint';
var DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated';
var DEBUG_FUNCTION_BREAKPOINTS_KEY = 'debug.functionbreakpoint';
var DEBUG_EXCEPTION_BREAKPOINTS_KEY = 'debug.exceptionbreakpoint';
var DEBUG_WATCH_EXPRESSIONS_KEY = 'debug.watchexpressions';
var DEBUG_SELECTED_CONFIG_NAME_KEY = 'debug.selectedconfigname';
......@@ -99,7 +100,7 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
this.configurationManager = this.instantiationService.createInstance(ConfigurationManager, this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE, 'null'));
this.inDebugMode = keybindingService.createKey(debug.CONTEXT_IN_DEBUG_MODE, false);
this.model = new model.Model(this.loadBreakpoints(), this.storageService.getBoolean(DEBUG_BREAKPOINTS_ACTIVATED_KEY, StorageScope.WORKSPACE, true),
this.model = new model.Model(this.loadBreakpoints(), this.storageService.getBoolean(DEBUG_BREAKPOINTS_ACTIVATED_KEY, StorageScope.WORKSPACE, true), this.loadFunctionBreakpoints(),
this.loadExceptionBreakpoints(), this.loadWatchExpressions());
this.viewModel = new viewmodel.ViewModel();
......@@ -313,6 +314,16 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
}
}
private loadFunctionBreakpoints(): debug.IFunctionBreakpoint[] {
try {
return JSON.parse(this.storageService.get(DEBUG_FUNCTION_BREAKPOINTS_KEY, StorageScope.WORKSPACE, '[]')).map((fb: any) => {
return new model.FunctionBreakpoint(fb.name, fb.enabled);
});
} catch (e) {
return [];
}
}
private loadExceptionBreakpoints(): debug.IExceptionBreakpoint[] {
var result: debug.IExceptionBreakpoint[] = null;
try {
......@@ -378,14 +389,16 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
if (element instanceof model.Breakpoint) {
var breakpoint = <model.Breakpoint> element;
return this.sendBreakpoints(breakpoint.source.uri);
} else if (element instanceof model.FunctionBreakpoint) {
// TODO@Isidor send function breakpoints and return
}
return this.sendExceptionBreakpoints();
}
public clearBreakpoints(modelUri: uri = null): Promise {
public removeBreakpoints(modelUri: uri = null): Promise {
var urisToClear = modelUri ? [modelUri] : arrays.distinct(this.model.getBreakpoints(), bp => bp.source.uri.toString()).map(bp => bp.source.uri);
this.model.clearBreakpoints(modelUri);
this.model.removeBreakpoints(modelUri);
return Promise.join(urisToClear.map(uri => this.sendBreakpoints(uri)));
}
......@@ -395,6 +408,24 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
return this.sendAllBreakpoints();
}
public addFunctionBreakpoint(functionName?: string): Promise {
this.model.addFunctionBreakpoint(functionName);
// TODO@Isidor send updated function breakpoints
return Promise.as(true);
}
public renameFunctionBreakpoint(id: string, newFunctionName: string): Promise {
this.model.renameFunctionBreakpoint(id, newFunctionName);
// TODO@Isidor send updated function breakpoints
return Promise.as(true);
}
public removeFunctionBreakpoints(id?: string): Promise {
this.model.removeFunctionBreakpoints(id);
// TODO@Isidor send updated function breakpoints
return Promise.as(true);
}
public addReplExpression(name: string): Promise {
return this.model.addReplExpression(this.session, this.viewModel.getFocusedStackFrame(), name);
}
......@@ -731,7 +762,7 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
var uri = breakpoints[i].source.uri;
var uriStr = uri.toString();
if (!clearedUris[uriStr] && fileChangesEvent.contains(uri, FileChangeType.DELETED)) {
this.clearBreakpoints(uri);
this.removeBreakpoints(uri);
clearedUris[uriStr] = true;
}
}
......@@ -740,6 +771,7 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
private store(): void {
this.storageService.store(DEBUG_BREAKPOINTS_KEY, JSON.stringify(this.model.getBreakpoints()), StorageScope.WORKSPACE);
this.storageService.store(DEBUG_BREAKPOINTS_ACTIVATED_KEY, this.model.areBreakpointsActivated() ? 'true' : 'false', StorageScope.WORKSPACE);
this.storageService.store(DEBUG_FUNCTION_BREAKPOINTS_KEY, JSON.stringify(this.model.getFunctionBreakpoints()), StorageScope.WORKSPACE);
this.storageService.store(DEBUG_EXCEPTION_BREAKPOINTS_KEY, JSON.stringify(this.model.getExceptionBreakpoints()), StorageScope.WORKSPACE);
this.storageService.store(DEBUG_SELECTED_CONFIG_NAME_KEY, this.configurationManager.getConfigurationName(), StorageScope.WORKSPACE);
this.storageService.store(DEBUG_WATCH_EXPRESSIONS_KEY, JSON.stringify(this.model.getWatchExpressions()), StorageScope.WORKSPACE);
......
......@@ -13,7 +13,7 @@ suite('Debug - Model', () => {
var model: debugmodel.Model;
setup(() => {
model = new debugmodel.Model([], true, [], []);
model = new debugmodel.Model([], true, [], [], []);
});
teardown(() => {
......@@ -28,7 +28,7 @@ suite('Debug - Model', () => {
assert.equal(model.areBreakpointsActivated(), true);
assert.equal(model.getBreakpoints().length, 2);
model.clearBreakpoints(modelUri);
model.removeBreakpoints(modelUri);
assert.equal(model.getBreakpoints().length, 0);
});
......@@ -66,7 +66,7 @@ suite('Debug - Model', () => {
model.toggleEnablement(bp);
assert.equal(bp.enabled, true);
model.clearBreakpoints(modelUri1);
model.removeBreakpoints(modelUri1);
assert.equal(model.getBreakpoints().length, 3);
});
......
......@@ -209,6 +209,8 @@ suite('Files - TextFileEditorModel', () => {
});
test("Change after auto save triggered will cause another autosave and twice the events", function(done) {
this.timeout(10000); // TODO@Ben test tends to need longer?
let eventCounter = 0;
let m1 = baseInstantiationService.createInstance(TextFileEditorModel, toResource("/path/index.txt"), "utf8");
......
......@@ -185,7 +185,7 @@ export class ChangesView extends EventEmitter.EventEmitter implements GitView.IV
public focus():void {
var selection = this.tree.getSelection();
if (selection.length > 0) {
this.tree.reveal(selection[0], 0.5);
this.tree.reveal(selection[0], 0.5).done(null, Errors.onUnexpectedError);
}
this.commitInputBox.focus();
......
......@@ -828,7 +828,7 @@ export class Controller extends treedefaults.DefaultController {
}
private canSelect(tree: tree.ITree, ...elements: any[]): boolean {
if (elements.some(e => e instanceof gitmodel.StatusGroup)) {
if (elements.some(e => e instanceof gitmodel.StatusGroup || e instanceof gitmodel.StatusModel)) {
return false;
}
......
......@@ -65,7 +65,7 @@ export class MarkdownEditorModel extends IFrameEditorModel {
let mode = model.getMode();
let absoluteWorkerResourcesPath = require.toUrl('vs/languages/markdown/common'); // TODO@Ben technical debt: worker cannot resolve path absolute
if (mode && !!mode.emitOutputSupport && mode.getId() === MARKDOWN_MODE_ID) {
(<any>mode).emitOutputSupport.getEmitOutput(model.getAssociatedResource(), absoluteWorkerResourcesPath).then((output: IMarkdownWorkerOutput) => {
(<any>mode).emitOutputSupport.getEmitOutput(this.resource, absoluteWorkerResourcesPath).then((output: IMarkdownWorkerOutput) => {
this.setContents(output.head, output.body, output.tail);
c(this);
......
......@@ -57,7 +57,7 @@ suite('FileService', () => {
});
test('createFile', function(done: () => void) {
this.timeout(10000); // test tends to need longer?
this.timeout(10000); // TODO@Ben test tends to need longer?
let contents = 'Hello World';
service.createFile(uri.file(path.join(testDir, 'test.txt')), contents).done(s => {
......
......@@ -46,7 +46,7 @@ export class WorkerRequestService extends BaseRequestService implements IThreadS
public makeRequest(options:http.IXHROptions):TPromise<http.IXHRResponse> {
let url = options.url;
if (!url) {
throw new Error('IRequestService.makeRequest: Url is required');
throw new Error('IRequestService.makeRequest: Url is required.');
}
// Support file:// in worker environment through XHR
......@@ -56,7 +56,7 @@ export class WorkerRequestService extends BaseRequestService implements IThreadS
return xhr; // loading resources locally returns a status of 0 which in WinJS is an error so we need to handle it here
}
return <any>Promise.wrapError(new Error(nls.localize('localFileNotFound', "File not found")));
return <any>Promise.wrapError({ status: 404, responseText: nls.localize('localFileNotFound', "File not found.")});
});
}
......
......@@ -80,7 +80,7 @@ export class RequestService extends BaseRequestService implements IThreadSynchro
public makeRequest(options: http.IXHROptions): TPromise<http.IXHRResponse> {
let url = options.url;
if (!url) {
throw new Error('IRequestService.makeRequest: Url is required');
throw new Error('IRequestService.makeRequest: Url is required.');
}
// Support file:// in native environment through XHR
......@@ -90,7 +90,7 @@ export class RequestService extends BaseRequestService implements IThreadSynchro
return xhr; // loading resources locally returns a status of 0 which in WinJS is an error so we need to handle it here
}
return <any>Promise.wrapError(new Error(nls.localize('localFileNotFound', "File not found")));
return <any>Promise.wrapError({ status: 404, responseText: nls.localize('localFileNotFound', "File not found.")});
});
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册