Merge branch 'master' into ben/electron

This commit is contained in:
Benjamin Pasero 2016-01-05 19:05:15 +01:00
commit 1c4656f045
48 changed files with 1031 additions and 842 deletions

View file

@ -12,5 +12,6 @@
".build/**": true,
"out*/**": true,
"extensions/**/out/**": true
}
},
"filePicker.alternateFileNameMatching": true
}

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>fileTypes</key>
@ -462,7 +462,11 @@
</dict>
<dict>
<key>include</key>
<string>#mixins</string>
<string>#mixin_definition</string>
</dict>
<dict>
<key>include</key>
<string>#mixin_call</string>
</dict>
<dict>
<key>include</key>
@ -592,26 +596,6 @@
<key>name</key>
<string>meta.first-class.jade</string>
</dict>
<key>brackets_js</key>
<dict>
<key>begin</key>
<string>\[</string>
<key>end</key>
<string>\]</string>
<key>name</key>
<string>js.value.attribute.tag.jade</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#brackets_js</string>
</dict>
<dict>
<key>include</key>
<string>source.js</string>
</dict>
</array>
</dict>
<key>case_conds</key>
<dict>
<key>begin</key>
@ -712,7 +696,7 @@
</dict>
<dict>
<key>include</key>
<string>#mixins</string>
<string>#mixin_call</string>
</dict>
<dict>
<key>include</key>
@ -946,7 +930,7 @@
</dict>
<dict>
<key>include</key>
<string>#mixins</string>
<string>#mixin_call</string>
</dict>
<dict>
<key>begin</key>
@ -1081,60 +1065,155 @@
</dict>
</array>
</dict>
<key>mixins</key>
<key>js_braces</key>
<dict>
<key>begin</key>
<string>(((mixin\s+)|\+)([\w-]+))\s*</string>
<string>\{</string>
<key>end</key>
<string>\}</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#js_braces</string>
</dict>
<dict>
<key>include</key>
<string>source.js</string>
</dict>
</array>
</dict>
<key>js_brackets</key>
<dict>
<key>begin</key>
<string>\[</string>
<key>end</key>
<string>\]</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#js_brackets</string>
</dict>
<dict>
<key>include</key>
<string>source.js</string>
</dict>
</array>
</dict>
<key>js_parens</key>
<dict>
<key>begin</key>
<string>\(</string>
<key>end</key>
<string>\)</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#js_parens</string>
</dict>
<dict>
<key>include</key>
<string>source.js</string>
</dict>
</array>
</dict>
<key>mixin_call</key>
<dict>
<key>begin</key>
<string>((?:mixin\s+)|\+)([\w-]+)</string>
<key>beginCaptures</key>
<dict>
<key>2</key>
<key>1</key>
<dict>
<key>name</key>
<string>storage.type.function.jade</string>
</dict>
<key>4</key>
<key>2</key>
<dict>
<key>name</key>
<string>entity.name.function.jade</string>
<string>meta.tag.other entity.name.function.jade</string>
</dict>
</dict>
<key>comment</key>
<string>Mixin declaration and use, including the new '+' syntax.</string>
<key>end</key>
<string>(?=\])|$</string>
<key>name</key>
<string>source.meta.function</string>
<string>(?!\()|$</string>
<key>patterns</key>
<array>
<dict>
<key>begin</key>
<string></string>
<string>(?&lt;!\))\(</string>
<key>end</key>
<string>(?=\])|$</string>
<string>\)</string>
<key>name</key>
<string>args.mixin.jade</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#tag_attribute_value_paren</string>
<string>#js_parens</string>
</dict>
<dict>
<key>include</key>
<string>#tag_attribute_value_brackets</string>
<string>#string</string>
</dict>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>meta.tag.other entity.other.attribute-name.tag.jade</string>
</dict>
</dict>
<key>match</key>
<string>([^\s(),=/]+)\s*=\s*</string>
</dict>
<dict>
<key>include</key>
<string>#tag_attribute_value_braces</string>
</dict>
<dict>
<key>include</key>
<string>#complete_tag</string>
<string>source.js</string>
</dict>
</array>
</dict>
<dict>
<key>include</key>
<string>#tag_attributes</string>
</dict>
</array>
</dict>
<key>mixin_definition</key>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>storage.type.function.jade</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>meta.tag.other entity.name.function.jade</string>
</dict>
<key>3</key>
<dict>
<key>name</key>
<string>punctuation.definition.parameters.begin.js</string>
</dict>
<key>4</key>
<dict>
<key>name</key>
<string>variable.parameter.function.js</string>
</dict>
<key>5</key>
<dict>
<key>name</key>
<string>punctuation.definition.parameters.begin.js</string>
</dict>
</dict>
<key>match</key>
<string>(mixin\s+)([\w-]+)(?:(\()((?:[a-zA-Z_]\w*(?:,\s*)?)*)(\)))?$</string>
</dict>
<key>printed_expression</key>
<dict>
<key>begin</key>
@ -1155,7 +1234,7 @@
<array>
<dict>
<key>include</key>
<string>#brackets_js</string>
<string>#js_brackets</string>
</dict>
<dict>
<key>include</key>
@ -1189,106 +1268,43 @@
</dict>
</array>
</dict>
<key>tag_attribute_value_braces</key>
<key>tag_attribute_name</key>
<dict>
<key>begin</key>
<string>\{</string>
<key>end</key>
<string>\}</string>
<key>name</key>
<string>js.value.attribute.tag.jade</string>
<key>patterns</key>
<array>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>include</key>
<string>#tag_attribute_value_paren</string>
<key>name</key>
<string>entity.other.attribute-name.tag.jade</string>
</dict>
<dict>
<key>include</key>
<string>#tag_attribute_value_brackets</string>
</dict>
<dict>
<key>include</key>
<string>#tag_attribute_value_braces</string>
</dict>
<dict>
<key>include</key>
<string>#string</string>
</dict>
<dict>
<key>include</key>
<string>source.js</string>
</dict>
</array>
</dict>
<key>match</key>
<string>([^\s(),=/!]+)\s*</string>
</dict>
<key>tag_attribute_value_brackets</key>
<key>tag_attribute_name_paren</key>
<dict>
<key>begin</key>
<string>\[</string>
<key>end</key>
<string>\]</string>
<key>name</key>
<string>js.value.attribute.tag.jade</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#tag_attribute_value_paren</string>
</dict>
<dict>
<key>include</key>
<string>#tag_attribute_value_brackets</string>
</dict>
<dict>
<key>include</key>
<string>#tag_attribute_value_braces</string>
</dict>
<dict>
<key>include</key>
<string>#string</string>
</dict>
<dict>
<key>include</key>
<string>source.js</string>
</dict>
</array>
</dict>
<key>tag_attribute_value_paren</key>
<dict>
<key>begin</key>
<string>\(</string>
<string>\(\s*</string>
<key>end</key>
<string>\)</string>
<key>name</key>
<string>js.value.attribute.tag.jade</string>
<string>entity.other.attribute-name.tag.jade</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#tag_attribute_value_paren</string>
<string>#tag_attribute_name_paren</string>
</dict>
<dict>
<key>include</key>
<string>#tag_attribute_value_brackets</string>
</dict>
<dict>
<key>include</key>
<string>#tag_attribute_value_braces</string>
</dict>
<dict>
<key>include</key>
<string>#string</string>
</dict>
<dict>
<key>include</key>
<string>source.js</string>
<string>#tag_attribute_name</string>
</dict>
</array>
</dict>
<key>tag_attributes</key>
<dict>
<key>begin</key>
<string>(\()</string>
<string>(\(\s*)</string>
<key>captures</key>
<dict>
<key>1</key>
@ -1304,53 +1320,75 @@
<key>patterns</key>
<array>
<dict>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>entity.other.attribute-name.tag.jade</string>
</dict>
</dict>
<key>include</key>
<string>#tag_attribute_name_paren</string>
</dict>
<dict>
<key>include</key>
<string>#tag_attribute_name</string>
</dict>
<dict>
<key>match</key>
<string>([^\s(),=/]+)\s*((?=\))|,|\s+|$)(?!\!?\=)</string>
<string>!</string>
<key>name</key>
<string>invalid.illegal.tag.jade</string>
</dict>
<dict>
<key>begin</key>
<string>([^\s(),=/]*[^\s(),=!/])\s*(!?\=)</string>
<key>beginCaptures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>entity.other.attribute-name.tag.jade</string>
</dict>
<key>2</key>
<dict>
<key>name</key>
<string>punctuation.separator.key-value.jade</string>
</dict>
</dict>
<string>=\s*</string>
<key>end</key>
<string>(,|$|(?=\)|((?&lt;![+/*|&amp;=:^~!?&lt;&gt;%-])\s+[^+/*|&amp;=:^~!?&lt;&gt;%-])))</string>
<string>$|(?=,|(?:\s+[^!%&amp;*-+~|&lt;&gt;:?/])|\))</string>
<key>name</key>
<string>attribute_value</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#tag_attribute_value_paren</string>
<string>#string</string>
</dict>
<dict>
<key>include</key>
<string>#tag_attribute_value_brackets</string>
<string>#js_parens</string>
</dict>
<dict>
<key>include</key>
<string>#tag_attribute_value_braces</string>
<string>#js_brackets</string>
</dict>
<dict>
<key>include</key>
<string>#js_braces</string>
</dict>
<dict>
<key>include</key>
<string>source.js</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>(?&lt;=[%&amp;*-+~|&lt;&gt;:?/])\s+</string>
<key>end</key>
<string>$|(?=,|(?:\s+[^!%&amp;*-+~|&lt;&gt;:?/])|\))</string>
<key>name</key>
<string>attribute_value2</string>
<key>patterns</key>
<array>
<dict>
<key>include</key>
<string>#string</string>
</dict>
<dict>
<key>include</key>
<string>#js_parens</string>
</dict>
<dict>
<key>include</key>
<string>#js_brackets</string>
</dict>
<dict>
<key>include</key>
<string>#js_braces</string>
</dict>
<dict>
<key>include</key>
<string>source.js</string>
@ -1496,7 +1534,7 @@
<array>
<dict>
<key>include</key>
<string>#brackets_js</string>
<string>#js_brackets</string>
</dict>
<dict>
<key>include</key>

View file

@ -64,7 +64,7 @@
"jsonValidation": [
{
"fileMatch": "package.json",
"url": "http://json.schemastore.org/project"
"url": "http://json.schemastore.org/package"
},
{
"fileMatch": "bower.json",

View file

@ -1,6 +1,6 @@
{
"account": "monacobuild",
"container": "debuggers",
"zip": "f1ea61a/node-debug.zip",
"zip": "d98733b/node-debug.zip",
"output": ""
}

6
npm-shrinkwrap.json generated
View file

@ -416,9 +416,9 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
},
"vscode-debugprotocol": {
"version": "1.0.1",
"from": "vscode-debugprotocol@>=1.0.1",
"resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.0.1.tgz"
"version": "1.1.1",
"from": "vscode-debugprotocol@>=1.1.1",
"resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.1.1.tgz"
},
"vscode-textmate": {
"version": "1.0.9",

View file

@ -1,6 +1,6 @@
{
"name": "Code",
"version": "0.10.5",
"version": "0.10.6",
"electronVersion": "0.35.5",
"author": {
"name": "Microsoft Corporation"
@ -26,7 +26,7 @@
"iconv-lite": "^0.4.13",
"sax": "^1.1.1",
"semver": "^4.2.0",
"vscode-debugprotocol": "^1.0.0",
"vscode-debugprotocol": "^1.1.1",
"vscode-textmate": "^1.0.9",
"native-keymap": "^0.1.2",
"winreg": "0.0.12",

View file

@ -277,7 +277,7 @@ export function isEqualOrParent(path: string, candidate: string): boolean {
// Reference: https://en.wikipedia.org/wiki/Filename
const INVALID_FILE_CHARS = isWindows ? /[\\/:\*\?"<>\|]/g : /[\\/]/g;
const WINDOWS_FORBIDDEN_NAMES = /con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9]/i;
const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i;
export function isValidBasename(name: string): boolean {
if (!name || name.length === 0 || /^\s+$/.test(name)) {
return false; // require a name that is not just whitespace

View file

@ -333,7 +333,7 @@ let showReferencesCommand: ICommandHandler = (accessor, args:[URI, EditorCommon.
let controller = FindReferencesController.getController(control);
let range = Position.asEmptyRange(args[1]);
return TPromise.as(controller.processRequest(Range.lift(range), TPromise.as(args[2])));
return TPromise.as(controller.processRequest(Range.lift(range), TPromise.as(args[2]))).then(() => true);
});
};

View file

@ -523,10 +523,6 @@ export class SuggestWidget implements EditorBrowser.IContentWidget, IDisposable
this.suggestionSupportsAutoAccept.set(!(<CompletionItem>focus).suggestion.noAutoAccept);
}
if (focus === this.oldFocus) {
return;
}
const elementsToRefresh: any[] = [];
if (this.oldFocus) {

View file

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------------------------
* Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). This document includes material copied
* Copyright © 2015 W3C® (MIT, ERCIM, Keio, Beihang). This software or document includes includes material copied
* from or derived from HTML 5.1 W3C Working Draft (http://www.w3.org/TR/2015/WD-html51-20151008/.)"
*--------------------------------------------------------------------------------------------*/

View file

@ -280,7 +280,10 @@ export class JSONSchemaService implements IJSONSchemaService {
this.contributionAssociations[pattern] = associations;
var fpa = this.getOrAddFilePatternAssociation(pattern);
associations.forEach(schemaId => fpa.addSchema(schemaId));
associations.forEach(schemaId => {
var id = this.normalizeId(schemaId);
fpa.addSchema(id)
});
}
}
}
@ -327,7 +330,10 @@ export class JSONSchemaService implements IJSONSchemaService {
for (var pattern in this.contributionAssociations) {
var fpa = this.getOrAddFilePatternAssociation(pattern);
this.contributionAssociations[pattern].forEach(schemaId => fpa.addSchema(schemaId));
this.contributionAssociations[pattern].forEach(schemaId => {
var id = this.normalizeId(schemaId);
fpa.addSchema(id);
});
}
}

View file

@ -172,7 +172,7 @@
// Return true if the given text is composed entirely of whitespace.
this.is_whitespace = function(text) {
for (var n = 0; n < text.length; text++) {
for (var n = 0; n < text.length; n++) {
if (!this.Utils.in_array(text.charAt(n), this.Utils.whitespace)) {
return false;
}
@ -467,7 +467,7 @@
} else if (tag_check === 'script' &&
(tag_complete.search('type') === -1 ||
(tag_complete.search('type') > -1 &&
tag_complete.search(/\b(text|application)\/(x-)?(javascript|ecmascript|jscript|livescript)/) > -1))) {
tag_complete.search(/\b(text|application)\/(x-)?(javascript|ecmascript|jscript|livescript|(ld\+)?json)/) > -1))) {
if (!peek) {
this.record_tag(tag_check);
this.tag_type = 'SCRIPT';
@ -525,7 +525,7 @@
matched = false;
this.pos = start_pos;
input_char = this.input.charAt(this.pos);
var input_char = this.input.charAt(this.pos);
this.pos++;
while (this.pos <= this.input.length) {
@ -570,15 +570,34 @@
return comment;
};
this.get_unformatted = function(delimiter, orig_tag) { //function to return unformatted content in its entirety
function tokenMatcher(delimiter) {
var token = '';
var add = function (str) {
var newToken = token + str.toLowerCase();
token = newToken.length <= delimiter.length ? newToken : newToken.substr(newToken.length - delimiter.length, delimiter.length);
};
var doesNotMatch = function () {
return token.indexOf(delimiter) === -1;
};
return {
add: add,
doesNotMatch: doesNotMatch
};
}
this.get_unformatted = function(delimiter, orig_tag) { //function to return unformatted content in its entirety
if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) !== -1) {
return '';
}
var input_char = '';
var content = '';
var min_index = 0;
var space = true;
var delimiterMatcher = tokenMatcher(delimiter);
do {
if (this.pos >= this.input.length) {
@ -606,16 +625,17 @@
}
}
content += input_char;
delimiterMatcher.add(input_char);
this.line_char_count++;
space = true;
if (indent_handlebars && input_char === '{' && content.length && content.charAt(content.length - 2) === '{') {
// Handlebars expressions in strings should also be unformatted.
content += this.get_unformatted('}}');
// These expressions are opaque. Ignore delimiters found in them.
min_index = content.length;
// Don't consider when stopping for delimiters.
}
} while (content.toLowerCase().indexOf(delimiter, min_index) === -1);
} while (delimiterMatcher.doesNotMatch());
return content;
};
@ -832,6 +852,21 @@
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_TAG_HANDLEBARS_ELSE':
// Don't add a newline if opening {{#if}} tag is on the current line
var foundIfOnCurrentLine = false;
for (var lastCheckedOutput=multi_parser.output.length-1; lastCheckedOutput>=0; lastCheckedOutput--) {
if (multi_parser.output[lastCheckedOutput] === '\n') {
break;
} else {
if (multi_parser.output[lastCheckedOutput].match(/{{#if/)) {
foundIfOnCurrentLine = true;
break;
}
}
}
if (!foundIfOnCurrentLine) {
multi_parser.print_newline(false, multi_parser.output);
}
multi_parser.print_token(multi_parser.token_text);
if (multi_parser.indent_content) {
multi_parser.indent();

View file

@ -298,6 +298,17 @@ jsonContributionRegistry.registerSchema('http://json-schema.org/draft-04/schema#
],
'description': nls.localize('schema.json.type', 'Either a string of one of the basic schema types (number, integer, null, array, object, boolean, string) or an array of strings specifying a subset of those types.')
},
'format': {
'anyOf': [
{
'type': 'string',
'description': nls.localize('schema.json.format', 'Describes the format expected for the value.'),
'enum': [ 'date-time', 'uri', 'email', 'hostname', 'ipv4', 'ipv6', 'regex']
},{
'type': 'string'
}
]
},
'allOf': {
'allOf': [
{ '$ref': '#/definitions/schemaArray' }

2
src/vs/vscode.d.ts vendored
View file

@ -3319,7 +3319,6 @@ declare namespace vscode {
*
* ```javascript
* export function activate(context: vscode.ExtensionContext) {
*
* let api = {
* sum(a, b) {
* return a + b;
@ -3328,7 +3327,6 @@ declare namespace vscode {
* return a * b;
* }
* };
*
* // 'export' public api-surface
* return api;
* }

View file

@ -23,7 +23,6 @@ import {ExtHostLanguages} from 'vs/workbench/api/common/extHostLanguages';
import {ExtHostLanguageFeatures} from 'vs/workbench/api/common/extHostLanguageFeatures';
import {registerApiCommands} from 'vs/workbench/api/common/extHostApiCommands';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import 'vs/workbench/api/common/extHostTypes.marshalling';
import Modes = require('vs/editor/common/modes');
import {IModeService} from 'vs/editor/common/services/modeService';
import {ICommentsSupportContribution, ITokenTypeClassificationSupportContribution} from 'vs/editor/common/modes/supports';
@ -133,12 +132,36 @@ export class ExtHostAPIImplementation {
});
const pluginHostCommands = this._threadService.getRemotable(ExtHostCommands);
const pluginHostEditors = this._threadService.getRemotable(ExtHostEditors);
const pluginHostMessageService = new ExtHostMessageService(this._threadService, this.commands);
const pluginHostQuickOpen = new ExtHostQuickOpen(this._threadService);
const pluginHostStatusBar = new ExtHostStatusBar(this._threadService);
const extHostOutputService = new ExtHostOutputService(this._threadService);
// commands namespace
this.commands = {
registerCommand<T>(id: string, command: <T>(...args: any[]) => T | Thenable<T>, thisArgs?: any): vscode.Disposable {
return pluginHostCommands.registerCommand(id, command, thisArgs);
},
registerTextEditorCommand(commandId: string, callback: (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit) => void, thisArg?: any): vscode.Disposable {
return pluginHostCommands.registerTextEditorCommand(commandId, callback, thisArg);
registerTextEditorCommand(id: string, callback: (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit) => void, thisArg?: any): vscode.Disposable {
let actualCallback: typeof callback = thisArg ? callback.bind(thisArg) : callback;
return pluginHostCommands.registerCommand(id, () => {
let activeTextEditor = pluginHostEditors.getActiveTextEditor();
if (!activeTextEditor) {
console.warn('Cannot execute ' + id + ' because there is no active text editor.');
return;
}
activeTextEditor.edit((edit: vscode.TextEditorEdit) => {
actualCallback(activeTextEditor, edit);
}).then((result) => {
if (!result) {
console.warn('Edits from command ' + id + ' were not applied.');
}
}, (err) => {
console.warn('An error occured while running command ' + id, err);
});
});
},
executeCommand<T>(id: string, ...args: any[]): Thenable<T> {
return pluginHostCommands.executeCommand(id, args);
@ -148,11 +171,6 @@ export class ExtHostAPIImplementation {
}
};
const pluginHostEditors = this._threadService.getRemotable(ExtHostEditors);
const pluginHostMessageService = new ExtHostMessageService(this._threadService, this.commands);
const pluginHostQuickOpen = new ExtHostQuickOpen(this._threadService);
const pluginHostStatusBar = new ExtHostStatusBar(this._threadService);
const extHostOutputService = new ExtHostOutputService(this._threadService);
this.window = {
get activeTextEditor() {
return pluginHostEditors.getActiveTextEditor();

View file

@ -175,7 +175,7 @@ class ExtHostApiCommands {
};
return this._commands.executeCommand<modes.IReference[]>('_executeDefinitionProvider', args).then(value => {
if (Array.isArray(value)) {
return value.map(typeConverters.toLocation);
return value.map(typeConverters.location.to);
}
});
}
@ -211,7 +211,7 @@ class ExtHostApiCommands {
};
return this._commands.executeCommand<modes.IReference[]>('_executeDocumentHighlights', args).then(value => {
if (Array.isArray(value)) {
return value.map(typeConverters.toLocation);
return value.map(typeConverters.location.to);
}
});
}

View file

@ -10,7 +10,9 @@ import {KeybindingsRegistry} from 'vs/platform/keybinding/common/keybindingsRegi
import {IKeybindingService, ICommandHandlerDescription} from 'vs/platform/keybinding/common/keybindingService';
import {TPromise} from 'vs/base/common/winjs.base';
import {ExtHostEditors} from 'vs/workbench/api/common/extHostEditors';
import * as vscode from 'vscode';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters';
import {cloneAndChange} from 'vs/base/common/objects';
interface CommandHandler {
callback: Function;
@ -30,7 +32,7 @@ export class ExtHostCommands {
this._proxy = threadService.getRemotable(MainThreadCommands);
}
registerCommand(id: string, callback: <T>(...args: any[]) => T | Thenable<T>, thisArg?: any, description?: ICommandHandlerDescription): vscode.Disposable {
registerCommand(id: string, callback: <T>(...args: any[]) => T | Thenable<T>, thisArg?: any, description?: ICommandHandlerDescription): extHostTypes.Disposable {
if (!id.trim().length) {
throw new Error('invalid id');
@ -43,32 +45,7 @@ export class ExtHostCommands {
this._commands[id] = { callback, thisArg, description };
this._proxy.$registerCommand(id);
return {
dispose: () => {
delete this._commands[id];
}
};
}
registerTextEditorCommand(id: string, callback: (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit) => void, thisArg?: any): vscode.Disposable {
let actualCallback: (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit) => void = thisArg ? callback.bind(thisArg) : callback;
return this.registerCommand(id, () => {
let activeTextEditor = this._pluginHostEditors.getActiveTextEditor();
if (!activeTextEditor) {
console.warn('Cannot execute ' + id + ' because there is no active text editor.');
return;
}
activeTextEditor.edit((edit: vscode.TextEditorEdit) => {
actualCallback(activeTextEditor, edit);
}).then((result) => {
if (!result) {
console.warn('Edits from command ' + id + ' were not applied.');
}
}, (err) => {
console.warn('An error occured while running command ' + id, err);
});
});
return new extHostTypes.Disposable(() => delete this._commands[id]);
}
executeCommand<T>(id: string, ...args: any[]): Thenable<T> {
@ -79,13 +56,22 @@ export class ExtHostCommands {
return this.$executeContributedCommand(id, ...args);
} else {
// // check that we can get all parameters over to
// // the other side
// for (let i = 0; i < args.length; i++) {
// if (args[i] !== null && typeof args[i] === 'object' && !canSerialize(args[i])) {
// throw new Error('illegal argument - can not serialize argument number: ' + i)
// }
// }
// automagically convert some argument types
args = cloneAndChange(args, function(value) {
if (value instanceof extHostTypes.Position) {
return extHostTypeConverter.fromPosition(value);
}
if (value instanceof extHostTypes.Range) {
return extHostTypeConverter.fromRange(value);
}
if (value instanceof extHostTypes.Location) {
return extHostTypeConverter.location.from(value);
}
if (!Array.isArray(value)) {
return value;
}
});
return this._proxy.$executeCommand(id, args);
}
@ -95,7 +81,7 @@ export class ExtHostCommands {
$executeContributedCommand<T>(id: string, ...args: any[]): Thenable<T> {
let command = this._commands[id];
if (!command) {
return Promise.reject<T>(id);
return Promise.reject<T>(`Contributed command '${id}' does not exist.`);
}
try {
let {callback, thisArg, description} = command;
@ -156,7 +142,7 @@ export class MainThreadCommands {
KeybindingsRegistry.registerCommandDesc({
id,
handler: (serviceAccessor, ...args: any[]) => {
return this._proxy.$executeContributedCommand(id, ...args); //TODO@Joh - we cannot serialize the args
return this._proxy.$executeContributedCommand(id, ...args);
},
weight: undefined,
context: undefined,
@ -177,19 +163,6 @@ export class MainThreadCommands {
$getCommands(): Thenable<string[]> {
return TPromise.as(Object.keys(KeybindingsRegistry.getCommands()));
}
$getCommandHandlerDescriptions(): TPromise<{ [id: string]: string | ICommandHandlerDescription }> {
return this._proxy.$getContributedCommandHandlerDescriptions().then(result => {
const commands = KeybindingsRegistry.getCommands();
for (let id in commands) {
let {description} = commands[id];
if (description) {
result[id] = description;
}
}
return result;
});
}
}
@ -198,7 +171,18 @@ export class MainThreadCommands {
KeybindingsRegistry.registerCommandDesc({
id: '_generateCommandsDocumentation',
handler: function(accessor) {
return accessor.get(IThreadService).getRemotable(MainThreadCommands).$getCommandHandlerDescriptions().then(result => {
return accessor.get(IThreadService).getRemotable(ExtHostCommands).$getContributedCommandHandlerDescriptions().then(result => {
// add local commands
const commands = KeybindingsRegistry.getCommands();
for (let id in commands) {
let {description} = commands[id];
if (description) {
result[id] = description;
}
}
// print all as markdown
const all: string[] = [];
for (let id in result) {
all.push('`' + id + '` - ' + _generateMarkdown(result[id]));
@ -228,4 +212,4 @@ function _generateMarkdown(description: string | ICommandHandlerDescription): st
parts.push('\n\n');
return parts.join('');
}
}
}

View file

@ -7,7 +7,7 @@
import URI from 'vs/base/common/uri';
import {DefaultFilter} from 'vs/editor/common/modes/modesFilters';
import {TPromise} from 'vs/base/common/winjs.base';
import {IDisposable} from 'vs/base/common/lifecycle';
import {IDisposable, disposeAll} from 'vs/base/common/lifecycle';
import {Remotable, IThreadService} from 'vs/platform/thread/common/thread';
import {Range as EditorRange} from 'vs/editor/common/core/range';
import * as vscode from 'vscode';
@ -33,7 +33,7 @@ import {ParameterHintsRegistry} from 'vs/editor/contrib/parameterHints/common/pa
import {SuggestRegistry} from 'vs/editor/contrib/suggest/common/suggest';
function isThenable<T>(obj: any): obj is Thenable<T> {
return obj && typeof obj['then'] === 'function';
return obj && typeof (<Thenable<any>>obj).then === 'function';
}
function asWinJsPromise<T>(callback: (token: vscode.CancellationToken) => T | Thenable<T>): TPromise<T> {
@ -72,72 +72,112 @@ class OutlineAdapter implements IOutlineSupport {
}
}
interface CachedCodeLens {
symbols: modes.ICodeLensSymbol[];
lenses: vscode.CodeLens[];
disposables: IDisposable[];
};
class CodeLensAdapter implements modes.ICodeLensSupport {
private _documents: ExtHostModelService;
private _commands: ExtHostCommands;
private _provider: vscode.CodeLensProvider;
private _cache: { [uri: string]: vscode.CodeLens[] } = Object.create(null);
private _cache: { [uri: string]: { version: number; data: TPromise<CachedCodeLens>; } } = Object.create(null);
constructor(documents: ExtHostModelService, provider: vscode.CodeLensProvider) {
constructor(documents: ExtHostModelService, commands: ExtHostCommands, provider: vscode.CodeLensProvider) {
this._documents = documents;
this._commands = commands;
this._provider = provider;
}
findCodeLensSymbols(resource: URI): TPromise<modes.ICodeLensSymbol[]> {
let doc = this._documents.getDocument(resource);
let key = resource.toString();
const doc = this._documents.getDocument(resource);
const version = doc.version;
const key = resource.toString();
delete this._cache[key];
// from cache
let entry = this._cache[key];
if (entry && entry.version === version) {
return entry.data.then(cached => cached.symbols);
}
return asWinJsPromise(token => this._provider.provideCodeLenses(doc, token)).then(value => {
if (!Array.isArray(value)) {
const newCodeLensData = asWinJsPromise(token => this._provider.provideCodeLenses(doc, token)).then(lenses => {
if (!Array.isArray(lenses)) {
return;
}
this._cache[key] = value;
const data: CachedCodeLens = {
lenses,
symbols: [],
disposables: [],
}
return value.map((lens, i) => {
return <modes.ICodeLensSymbol>{
lenses.forEach((lens, i) => {
data.symbols.push(<modes.ICodeLensSymbol>{
id: String(i),
range: TypeConverters.fromRange(lens.range),
command: TypeConverters.Command.from(lens.command)
};
command: TypeConverters.Command.from(lens.command, { commands: this._commands, disposables: data.disposables })
});
});
return data;
});
this._cache[key] = {
version,
data: newCodeLensData
};
return newCodeLensData.then(newCached => {
if (entry) {
// only now dispose old commands et al
entry.data.then(oldCached => disposeAll(oldCached.disposables));
}
return newCached && newCached.symbols;
});
}
resolveCodeLensSymbol(resource: URI, symbol: modes.ICodeLensSymbol): TPromise<modes.ICodeLensSymbol> {
let lenses = this._cache[resource.toString()];
if (!lenses) {
const entry = this._cache[resource.toString()];
if (!entry) {
return;
}
let lens = lenses[Number(symbol.id)];
if (!lens) {
return;
}
return entry.data.then(cachedData => {
let resolve: TPromise<vscode.CodeLens>;
if (typeof this._provider.resolveCodeLens !== 'function' || lens.isResolved) {
resolve = TPromise.as(lens);
} else {
resolve = asWinJsPromise(token => this._provider.resolveCodeLens(lens, token));
}
return resolve.then(newLens => {
lens = newLens || lens;
let command = lens.command;
if (!command) {
command = {
title: '<<MISSING COMMAND>>',
command: 'missing',
};
if (!cachedData) {
return;
}
symbol.command = TypeConverters.Command.from(command);
return symbol;
let lens = cachedData.lenses[Number(symbol.id)];
if (!lens) {
return;
}
let resolve: TPromise<vscode.CodeLens>;
if (typeof this._provider.resolveCodeLens !== 'function' || lens.isResolved) {
resolve = TPromise.as(lens);
} else {
resolve = asWinJsPromise(token => this._provider.resolveCodeLens(lens, token));
}
return resolve.then(newLens => {
lens = newLens || lens;
let command = lens.command;
if (!command) {
command = {
title: '<<MISSING COMMAND>>',
command: 'missing',
};
}
symbol.command = TypeConverters.Command.from(command, { commands: this._commands, disposables: cachedData.disposables });
return symbol;
});
});
}
}
@ -279,30 +319,35 @@ class QuickFixAdapter implements modes.IQuickFixSupport {
private _commands: ExtHostCommands;
private _provider: vscode.CodeActionProvider;
private _cachedCommands: IDisposable[] = [];
constructor(documents: ExtHostModelService, commands: ExtHostCommands, provider: vscode.CodeActionProvider) {
this._documents = documents;
this._commands = commands;
this._provider = provider;
}
getQuickFixes(resource: URI, range: IRange, marker?: IMarker[]): TPromise<modes.IQuickFix[]> {
getQuickFixes(resource: URI, range: IRange, markers?: IMarker[]): TPromise<modes.IQuickFix[]> {
const doc = this._documents.getDocument(resource);
const ran = TypeConverters.toRange(range);
const diagnostics = marker.map(marker => {
const diagnostics = markers.map(marker => {
const diag = new Diagnostic(TypeConverters.toRange(marker), marker.message);
diag.code = marker.code;
diag.severity = TypeConverters.toDiagnosticSeverty(marker.severity);
return diag;
});
this._cachedCommands = disposeAll(this._cachedCommands);
const ctx = { commands: this._commands, disposables: this._cachedCommands };
return asWinJsPromise(token => this._provider.provideCodeActions(doc, ran, { diagnostics: <any>diagnostics }, token)).then(commands => {
if (!Array.isArray(commands)) {
return;
}
return commands.map((command, i) => {
return <modes.IQuickFix> {
command: TypeConverters.Command.from(command),
command: TypeConverters.Command.from(command, ctx),
score: i
};
});
@ -310,8 +355,8 @@ class QuickFixAdapter implements modes.IQuickFixSupport {
}
runQuickFixAction(resource: URI, range: IRange, quickFix: modes.IQuickFix): any {
let {command} = quickFix;
return this._commands.executeCommand(command.id, ...command.arguments);
let command = TypeConverters.Command.to(quickFix.command);
return this._commands.executeCommand(command.command, ...command.arguments);
}
}
@ -644,7 +689,7 @@ export class ExtHostLanguageFeatures {
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
const handle = this._nextHandle();
this._adapter[handle] = new CodeLensAdapter(this._documents, provider);
this._adapter[handle] = new CodeLensAdapter(this._documents, this._commands, provider);
this._proxy.$registerCodeLensSupport(handle, selector);
return this._createDisposable(handle);
}

View file

@ -4,7 +4,10 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {ExtHostCommands} from 'vs/workbench/api/common/extHostCommands';
import Severity from 'vs/base/common/severity';
import {isFalsyOrEmpty} from 'vs/base/common/arrays';
import {IDisposable} from 'vs/base/common/lifecycle';
import * as modes from 'vs/editor/common/modes';
import * as types from './extHostTypes';
import {Position as EditorPosition} from 'vs/platform/editor/common/editor';
@ -295,11 +298,18 @@ export function toSymbolInformation(bearing: ITypeBearing): types.SymbolInformat
}
export function toLocation(reference: modes.IReference): types.Location {
return new types.Location(reference.resource, toRange(reference.range));
export const location = {
from(value: types.Location): modes.IReference {
return {
range: fromRange(value.range),
resource: value.uri
}
},
to(value: modes.IReference): types.Location {
return new types.Location(value.resource, toRange(value.range));
}
}
export function fromHover(hover: vscode.Hover): modes.IComputeExtraInfoResult {
return <modes.IComputeExtraInfoResult>{
range: fromRange(hover.range),
@ -419,24 +429,47 @@ export namespace SignatureHelp {
}
}
export const Command = {
from(command: vscode.Command): modes.ICommand {
if (command) {
return <modes.ICommand>{
id: command.command,
title: command.title,
arguments: command.arguments
};
}
},
to(command: modes.ICommand): vscode.Command {
if (command) {
return <vscode.Command>{
command: command.id,
title: command.title,
arguments: command.arguments
};
export namespace Command {
const _cache: { [id: string]: vscode.Command } = Object.create(null);
let _idPool = 1;
export function from(command: vscode.Command, context: { commands: ExtHostCommands; disposables: IDisposable[]; }): modes.ICommand {
if (!command) {
return;
}
const result = <modes.ICommand>{
id: command.command,
title: command.title
};
if (!isFalsyOrEmpty(command.arguments)) {
// keep command around
const id = `${command.command}-no-args-wrapper-${_idPool++}`;
result.id = id;
_cache[id] = command;
const disposable1 = context.commands.registerCommand(id, () => context.commands.executeCommand(command.command, ..._cache[id].arguments));
const disposable2 = { dispose() { delete _cache[id] } };
context.disposables.push(disposable1, disposable2);
}
return result;
}
};
export function to(command: modes.ICommand): vscode.Command {
let result = _cache[command.id];
if (!result) {
result = {
command: command.id,
title: command.title
}
}
return result;
}
}

View file

@ -1,65 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {registerMarshallingContribution, IMarshallingContribution} from 'vs/base/common/marshalling';
import * as types from './extHostTypes';
import {fromPosition, fromRange} from './extHostTypeConverters';
import {IReference} from 'vs/editor/common/modes';
abstract class OneWayMarshalling<T> implements IMarshallingContribution {
canDeserialize() {
return false;
}
deserialize() {
throw Error();
}
abstract canSerialize(obj: any): boolean;
abstract serialize(obj: T, serialize: (obj: any) => any): any;
}
class RangeMarshalling extends OneWayMarshalling<types.Range> {
canSerialize(obj: any): boolean {
return obj instanceof types.Range;
}
serialize(obj: types.Range, serialize: (obj: any) => any): any {
return fromRange(obj);
}
}
class PositionMarshalling extends OneWayMarshalling<types.Position> {
canSerialize(obj: any): boolean {
return obj instanceof types.Position;
}
serialize(obj: types.Position, serialize: (obj: any) => any): any {
return fromPosition(obj);
}
}
class LocationMarshalling extends OneWayMarshalling<types.Location> {
canSerialize(obj: any): boolean {
return obj instanceof types.Location;
}
serialize(obj: types.Location, serialize: (obj: any) => any): any {
return <IReference>{
resource: serialize(obj.uri),
range: serialize(obj.range)
};
}
}
registerMarshallingContribution(new RangeMarshalling());
registerMarshallingContribution(new PositionMarshalling());
registerMarshallingContribution(new LocationMarshalling());

View file

@ -22,7 +22,7 @@ function getAgent(rawRequestURL: string, proxyURL: string, strictSSL: boolean =
}
return new HttpsProxyAgent({
host: proxyEndpoint.host,
host: proxyEndpoint.hostname,
port: Number(proxyEndpoint.port),
rejectUnauthorized: strictSSL
});

View file

@ -40,8 +40,8 @@ export class BreakpointWidget extends ZoneWidget {
});
dom.addClass(this.inputBox.inputElement, platform.isWindows ? 'windows' : platform.isMacintosh ? 'mac' : 'linux');
this.inputBox.value = (breakpoint && breakpoint.condition) ? breakpoint.condition : '';
// TODO@Isidor check with Alex why does the editor steal focus
setTimeout(() => this.inputBox.focus(), 150);
// Due to an electron bug we have to do the timeout, otherwise we do not get focus
setTimeout(() => this.inputBox.focus(), 0);
let disposed = false;
const toDispose: [lifecycle.IDisposable] = [this.inputBox, this];

View file

@ -13,7 +13,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
import keyboard = require('vs/base/browser/keyboardEvent');
import editorbrowser = require('vs/editor/browser/editorBrowser');
import editorcommon = require('vs/editor/common/editorCommon');
import { DebugHoverWidget } from 'vs/workbench/parts/debug/browser/debugHoverWidget';
import { DebugHoverWidget } from 'vs/workbench/parts/debug/browser/debugHover';
import debugactions = require('vs/workbench/parts/debug/electron-browser/debugActions');
import debug = require('vs/workbench/parts/debug/common/debug');
import { IWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService';
@ -37,7 +37,7 @@ export class DebugEditorContribution implements editorcommon.IEditorContribution
) {
this.breakpointHintDecoration = [];
this.toDispose = [];
this.hoverWidget = new DebugHoverWidget(this.editor, this.debugService);
this.hoverWidget = new DebugHoverWidget(this.editor, this.debugService, this.instantiationService);
this.registerListeners();
}
@ -148,7 +148,7 @@ export class DebugEditorContribution implements editorcommon.IEditorContribution
// hover business
private onEditorMouseDown(mouseEvent: editorbrowser.IMouseEvent): void {
if (mouseEvent.target.type === editorcommon.MouseTargetType.CONTENT_WIDGET && mouseEvent.target.detail === DebugHoverWidget.ID) {
if (mouseEvent.target.type === editorcommon.MouseTargetType.OVERLAY_WIDGET && mouseEvent.target.detail === DebugHoverWidget.ID) {
return;
}
@ -163,8 +163,8 @@ export class DebugEditorContribution implements editorcommon.IEditorContribution
const targetType = mouseEvent.target.type;
const stopKey = env.isMacintosh ? 'metaKey' : 'ctrlKey';
if (targetType === editorcommon.MouseTargetType.CONTENT_WIDGET && mouseEvent.target.detail === DebugHoverWidget.ID && !(<any>mouseEvent.event)[stopKey]) {
// mouse moved on top of content hover widget
if (targetType === editorcommon.MouseTargetType.OVERLAY_WIDGET && mouseEvent.target.detail === DebugHoverWidget.ID && !(<any>mouseEvent.event)[stopKey]) {
// mouse moved on top of debug hover widget
return;
}

View file

@ -144,7 +144,7 @@ export class DebugEditorModelManager implements IWorkbenchContribution {
range: createRange(sf.lineNumber, sf.column, sf.lineNumber, sf.column + 1)
});
if (thread.exception) {
if (thread.stoppedReason === 'exception') {
result.push({
options: DebugEditorModelManager.TOP_STACK_FRAME_EXCEPTION_DECORATION,
range: wholeLineRange

View file

@ -3,16 +3,22 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import htmlcontentrenderer = require('vs/base/browser/htmlContentRenderer');
import errors = require('vs/base/common/errors');
import dom = require('vs/base/browser/dom');
import { ITree } from 'vs/base/parts/tree/common/tree';
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
import { DefaultController, ICancelableEvent } from 'vs/base/parts/tree/browser/treeDefaults';
import editorbrowser = require('vs/editor/browser/editorBrowser');
import editorcommon = require('vs/editor/common/editorCommon');
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import debug = require('vs/workbench/parts/debug/common/debug');
import { tokenizeToHtmlContent } from 'vs/editor/common/modes/textToHtmlTokenizer';
import viewer = require('vs/workbench/parts/debug/browser/debugViewer');
const $ = dom.emmet;
const stringRegex = /^(['"]).*\1$/;
const debugTreeOptions = {
indentPixels: 8,
twistiePixels: 20
};
export class DebugHoverWidget implements editorbrowser.IContentWidget {
@ -22,12 +28,23 @@ export class DebugHoverWidget implements editorbrowser.IContentWidget {
private domNode: HTMLElement;
private isVisible: boolean;
private tree: ITree;
private showAtPosition: editorcommon.IPosition;
private lastHoveringOver: string;
private highlightDecorations: string[];
private treeContainer: HTMLElement;
private valueContainer: HTMLElement;
constructor(private editor: editorbrowser.ICodeEditor, private debugService: debug.IDebugService) {
constructor(private editor: editorbrowser.ICodeEditor, private debugService: debug.IDebugService, private instantiationService: IInstantiationService) {
this.domNode = $('.debug-hover-widget monaco-editor-background');
this.treeContainer = dom.append(this.domNode, $('.debug-hover-tree'));
this.tree = new Tree(this.treeContainer, {
dataSource: new viewer.VariablesDataSource(this.debugService),
renderer: this.instantiationService.createInstance(viewer.VariablesRenderer),
controller: new DebugHoverController()
}, debugTreeOptions);
this.valueContainer = dom.append(this.domNode, $('.debug-hover-value'));
this.isVisible = false;
this.showAtPosition = null;
this.lastHoveringOver = null;
@ -95,8 +112,6 @@ export class DebugHoverWidget implements editorbrowser.IContentWidget {
return;
}
const variable = variables[0];
// show it
this.highlightDecorations = this.editor.deltaDecorations(this.highlightDecorations, [{
range: {
@ -110,54 +125,21 @@ export class DebugHoverWidget implements editorbrowser.IContentWidget {
}
}]);
this.lastHoveringOver = hoveringOver;
if (variable.reference > 0 && variable.value.indexOf('function') === -1) {
let objectToString = '{\n';
variable.getChildren(this.debugService).then(children => {
if (!children) {
this.hide();
return;
}
for (let i = 0; i < children.length; i++) {
const nameAndValue = ` ${ children[i].name }: ${ children[i].value }`;
objectToString += nameAndValue.substr(0, 80);
// add a quote to the end of the string if cropped
if (nameAndValue.length > 80 && stringRegex.test(children[i].value)) {
objectToString += children[i].value[0];
}
if (i < children.length - 1) {
objectToString += ',\n';
}
}
objectToString += '\n}';
return objectToString;
}).done(value => this.doShow(pos, value), () => this.hide());
} else {
this.doShow(pos, variable.value);
}
this.doShow(pos, variables[0]);
}
private doShow(position: editorcommon.IEditorPosition, value: string): void {
const model = this.editor.getModel();
if (!value || !model) {
return;
private doShow(position: editorcommon.IEditorPosition, expression: debug.IExpression): void {
if (expression.reference > 0) {
this.valueContainer.hidden = true;
this.treeContainer.hidden = false;
this.tree.setInput(expression).done(null, errors.onUnexpectedError);
this.tree.layout(this.treeContainer.clientHeight);
} else {
this.treeContainer.hidden = true;
this.valueContainer.hidden = false;
viewer.renderExpressionValue(expression, false, this.valueContainer);
}
let crlfCount = 0;
for (let i = 0; i < value.length; i++) {
if (value[i] === '\n') {
crlfCount++;
}
if (crlfCount > 12) {
value = value.substr(0, i + 1) + ' ...\n}';
break;
}
}
this.domNode.innerHTML = '';
this.domNode.appendChild(htmlcontentrenderer.renderHtml(tokenizeToHtmlContent(value, model.getMode())));
this.showAtPosition = position;
this.isVisible = true;
this.editor.layoutContentWidget(this);
@ -184,3 +166,16 @@ export class DebugHoverWidget implements editorbrowser.IContentWidget {
} : null;
}
}
class DebugHoverController extends DefaultController {
/* protected */ public onLeftClick(tree: ITree, element: any, eventish: ICancelableEvent, origin: string = 'mouse'): boolean {
if (element.reference > 0) {
super.onLeftClick(tree, element, eventish, origin);
tree.clearFocus();
tree.deselect(element);
}
return true;
}
}

View file

@ -35,7 +35,7 @@ const $ = dom.emmet;
const booleanRegex = /^true|false$/i;
const stringRegex = /^(['"]).*\1$/;
export function renderExpressionValue(tree: tree.ITree, arg2: debug.IExpression|string, debugInactive: boolean, container: HTMLElement): void {
export function renderExpressionValue(arg2: debug.IExpression|string, debugInactive: boolean, container: HTMLElement): void {
let value = typeof arg2 === 'string' ? arg2 : arg2.value;
// remove stale classes
@ -62,7 +62,7 @@ export function renderVariable(tree: tree.ITree, variable: model.Variable, data:
}
if (variable.value) {
renderExpressionValue(tree, variable, debugInactive, data.value);
renderExpressionValue(variable, debugInactive, data.value);
if (variable.valueChanged && showChanged) {
// value changed color has priority over other colors.
data.value.className = 'value changed';
@ -190,11 +190,9 @@ export class CallStackDataSource implements tree.IDataSource {
const threads = (<model.Model> element).getThreads();
const threadsArray: debug.IThread[] = [];
for (let reference in threads) {
if (threads.hasOwnProperty(reference)) {
threadsArray.push(threads[reference]);
}
}
Object.keys(threads).forEach(threadId => {
threadsArray.push(threads[threadId]);
});
if (threadsArray.length === 1) {
return Promise.as(threadsArray[0].callStack);
@ -589,7 +587,7 @@ export class WatchExpressionsRenderer implements tree.IRenderer {
private renderExpression(tree: tree.ITree, expression: debug.IExpression, data: IVariableTemplateData): void {
data.name.textContent = `${expression.name}:`;
if (expression.value) {
renderExpressionValue(tree, expression, this.debugService.getState() === debug.State.Inactive, data.value);
renderExpressionValue(expression, this.debugService.getState() === debug.State.Inactive, data.value);
}
}

View file

@ -246,10 +246,11 @@ class CallStackView extends viewlet.CollapsibleViewletView {
this.toDispose.push(debugModel.addListener2(debug.ModelEvents.CALLSTACK_UPDATED, () => {
this.tree.refresh().done(null, errors.onUnexpectedError);
}));
this.toDispose.push(this.debugService.addListener2(debug.ServiceEvents.STATE_CHANGED, (reason: string) => {
if (this.debugService.getState() === debug.State.Stopped && reason !== 'step') {
this.messageBox.textContent = nls.localize('debugStopped', "Paused on {0}.", reason);
reason === 'exception' ? this.messageBox.classList.add('exception') : this.messageBox.classList.remove('exception');
this.toDispose.push(this.debugService.getViewModel().addListener2(debug.ViewModelEvents.FOCUSED_STACK_FRAME_UPDATED, () => {
const focussedThread = this.debugService.getModel().getThreads()[this.debugService.getViewModel().getFocusedThreadId()];
if (focussedThread && focussedThread.stoppedReason && focussedThread.stoppedReason !== 'step') {
this.messageBox.textContent = nls.localize('debugStopped', "Paused on {0}.", focussedThread.stoppedReason);
focussedThread.stoppedReason === 'exception' ? this.messageBox.classList.add('exception') : this.messageBox.classList.remove('exception');
this.messageBox.hidden = false;
return;

View file

@ -138,44 +138,6 @@
background-repeat: no-repeat;
}
/* Hover */
.monaco-editor .debug-hover-widget {
padding: 0 3px 0 3px;
border: 1px solid #CCC;
position: absolute;
margin-top: -1px;
cursor: default;
z-index: 50;
-webkit-animation-duration: 0.15s;
-webkit-animation-name: fadeIn;
-moz-animation-duration: 0.15s;
-moz-animation-name: fadeIn;
-ms-animation-duration: 0.15s;
-ms-animation-name: fadeIn;
animation-duration: 0.15s;
animation-name: fadeIn;
white-space: pre;
min-width: 50px;
-webkit-user-select: text;
-ms-user-select: text;
-khtml-user-select: text;
-moz-user-select: text;
-o-user-select: text;
overflow: hidden;
}
.monaco-editor .debug-hover-widget pre {
margin-top: 0;
margin-bottom: 0;
}
.monaco-editor .debugHoverHighlight {
background-color: rgba(173, 214, 255, 0.15);
}
/* Expressions */
.monaco-workbench .monaco-tree-row .expression {
@ -352,14 +314,6 @@
box-shadow: 0 2px 8px #000;
}
.monaco-editor.vs-dark .debug-hover-widget {
border-color: #555;
}
.monaco-editor.vs-dark .debugHoverHighlight {
background-color: rgba(38, 79, 120, 0.25);
}
/* High Contrast Theming */
.monaco-workbench.hc-black .monaco-tree-row:not(.selected) .expression .name {

View file

@ -0,0 +1,109 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .debug-hover-widget {
padding: 0 3px 0 3px;
border: 1px solid #CCC;
position: absolute;
margin-top: -1px;
cursor: default;
z-index: 50;
-webkit-animation-duration: 0.15s;
-webkit-animation-name: fadeIn;
-moz-animation-duration: 0.15s;
-moz-animation-name: fadeIn;
-ms-animation-duration: 0.15s;
-ms-animation-name: fadeIn;
animation-duration: 0.15s;
animation-name: fadeIn;
white-space: pre;
-webkit-user-select: text;
-ms-user-select: text;
-khtml-user-select: text;
-moz-user-select: text;
-o-user-select: text;
overflow: hidden;
}
.monaco-editor .debug-hover-widget .debug-hover-tree {
line-height: 24px;
width: 350px;
height: 300px;
}
/* Disable tree hover highlight in debug hover tree. */
.monaco-editor .debug-hover-widget .debug-hover-tree .monaco-tree .monaco-tree-rows > .monaco-tree-row:hover:not(.highlighted):not(.selected):not(.focused) {
background-color: inherit;
}
.monaco-editor .debug-hover-widget .debug-hover-tree .monaco-tree .monaco-tree-rows > .monaco-tree-row {
cursor: default;
}
.monaco-editor .debug-hover-widget .debug-hover-tree .monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children {
cursor: pointer;
}
.monaco-editor .debug-hover-widget pre {
margin-top: 0;
margin-bottom: 0;
}
.monaco-editor .debugHoverHighlight {
background-color: rgba(173, 214, 255, 0.15);
}
.monaco-editor .debug-hover-widget .value {
color: rgba(108, 108, 108, 0.8);
}
.monaco-editor .debug-hover-widget .error {
color: #E51400;
}
.monaco-editor .debug-hover-widget .value.number {
color: #09885A;
}
.monaco-editor .debug-hover-widget .value.boolean {
color: #0000FF;
}
.monaco-editor .debug-hover-widget .value.string {
color: #A31515;
}
/* Dark theme */
.monaco-editor.vs-dark .debug-hover-widget .value {
color: rgba(204, 204, 204, 0.6);
}
.monaco-editor.vs-dark .debug-hover-widget .error {
color: #F48771;
}
.monaco-editor.vs-dark .debug-hover-widget .value.number {
color: #B5CEA8;
}
.monaco-editor.vs-dark .debug-hover-widget .value.boolean {
color: #4E94CE;
}
.monaco-editor.vs-dark .debug-hover-widget .value.string {
color: #CE9178;
}
.monaco-editor.vs-dark .debug-hover-widget {
border-color: #555;
}
.monaco-editor.vs-dark .debugHoverHighlight {
background-color: rgba(38, 79, 120, 0.25);
}

View file

@ -208,7 +208,7 @@ export class ReplExpressionsRenderer implements tree.IRenderer {
private renderInputOutputPair(tree: tree.ITree, expression: debug.IExpression, templateData: IInputOutputPairTemplateData): void {
templateData.input.textContent = expression.name;
debugviewer.renderExpressionValue(tree, expression, this.debugService.getState() === debug.State.Inactive, templateData.value);
debugviewer.renderExpressionValue(expression, this.debugService.getState() === debug.State.Inactive, templateData.value);
if (expression.reference > 0) {
templateData.annotation.className = 'annotation octicon octicon-info';
templateData.annotation.title = nls.localize('stateCapture', "Object state is captured from first evaluation");
@ -401,7 +401,7 @@ export class ReplExpressionsRenderer implements tree.IRenderer {
}
// value
debugviewer.renderExpressionValue(tree, output.value, false, templateData.value);
debugviewer.renderExpressionValue(output.value, false, templateData.value);
// annotation if any
if (output.annotation) {

View file

@ -22,7 +22,7 @@ export interface IRawModelUpdate {
threadId: number;
thread?: DebugProtocol.Thread;
callStack?: DebugProtocol.StackFrame[];
exception?: boolean;
stoppedReason?: string;
}
// model
@ -45,7 +45,7 @@ export interface IThread extends ITreeElement {
threadId: number;
name: string;
callStack: IStackFrame[];
exception: boolean;
stoppedReason: string;
}
export interface IScope extends IExpressionContainer {
@ -128,7 +128,7 @@ export interface IViewModel extends ee.EventEmitter {
}
export interface IModel extends ee.IEventEmitter, ITreeElement {
getThreads(): { [reference: number]: IThread; };
getThreads(): { [threadId: number]: IThread; };
getBreakpoints(): IBreakpoint[];
areBreakpointsActivated(): boolean;
getFunctionBreakpoints(): IFunctionBreakpoint[];

View file

@ -64,10 +64,10 @@ export function getFullExpressionName(expression: debug.IExpression, sessionType
export class Thread implements debug.IThread {
public exception: boolean;
public stoppedReason: string;
constructor(public name: string, public threadId, public callStack: debug.IStackFrame[]) {
this.exception = false;
this.stoppedReason = undefined;
}
public getId(): string {
@ -335,7 +335,7 @@ export class Model extends ee.EventEmitter implements debug.IModel {
delete this.threads[reference];
} else {
this.threads[reference].callStack = [];
this.threads[reference].exception = false;
this.threads[reference].stoppedReason = undefined;
}
} else {
if (removeThreads) {
@ -345,7 +345,7 @@ export class Model extends ee.EventEmitter implements debug.IModel {
for (let ref in this.threads) {
if (this.threads.hasOwnProperty(ref)) {
this.threads[ref].callStack = [];
this.threads[ref].exception = false;
this.threads[ref].stoppedReason = undefined;
}
}
}
@ -613,10 +613,10 @@ export class Model extends ee.EventEmitter implements debug.IModel {
return new StackFrame(data.threadId, 0, Source.fromUri(uri.parse('unknown')), nls.localize('unknownStack', "Unknown stack location"), undefined, undefined);
}
return new StackFrame(data.threadId, rsf.id, rsf.source ? Source.fromRawSource(rsf.source) : Source.fromUri(uri.parse('unknown')), rsf.name, rsf.line, rsf.column);
return new StackFrame(data.threadId, rsf.id, rsf.source ? new Source(rsf.source) : Source.fromUri(uri.parse('unknown')), rsf.name, rsf.line, rsf.column);
});
this.threads[data.threadId].exception = data.exception;
this.threads[data.threadId].stoppedReason = data.stoppedReason;
}
this.emit(debug.ModelEvents.CALLSTACK_UPDATED);

View file

@ -444,7 +444,7 @@ declare module DebugProtocol {
name: string;
}
/** A Source .*/
/** A Source is a descriptor for source code. It is returned from the debug adapter as part of a StackFrame and it is used by clients when specifying breakpoints. */
export interface Source {
/** The short name of the source. Every source returned from the debug adapter has a name. When specifying a source to the debug adapter this name is optional. */
name?: string;
@ -452,8 +452,10 @@ declare module DebugProtocol {
path?: string;
/** If sourceReference > 0 the contents of the source can be retrieved through the SourceRequest. A sourceReference is only valid for a session, so it must not be used to persist a source. */
sourceReference?: number;
/** The (optional) origin of this source: possible values "internal module", "inlined content from source map" */
origin?: string;
/** The (optional) origin of this source: possible values "internal module", "inlined content from source map", etc. */
origin?: string;
/** Optional data that a debug adapter might want to loop through the client. The client should leave the data intact and persist it across sessions. The client should not interpret the data. */
adapterData?: any;
}
/** A Stackframe contains the source location. */

View file

@ -14,11 +14,23 @@ export class Source {
private static INTERNAL_URI_PREFIX = 'debug://internal/';
constructor(public name: string, uriStr: string, public origin: string, public reference = 0) {
this.uri = uri.parse(uriStr);
constructor(private raw: DebugProtocol.Source) {
this.uri = raw.path ? uri.file(raw.path) : uri.parse(Source.INTERNAL_URI_PREFIX + raw.name);
this.available = true;
}
public get name() {
return this.raw.name;
}
public get origin() {
return this.raw.origin;
}
public get reference() {
return this.raw.sourceReference;
}
public get inMemory() {
return Source.isInMemory(this.uri);
}
@ -29,13 +41,8 @@ export class Source {
for (let threadId in threads) {
if (threads.hasOwnProperty(threadId) && threads[threadId].callStack) {
const found = threads[threadId].callStack.filter(sf => sf.source.uri.toString() === uri.toString()).pop();
if (found) {
return {
name: found.source.name,
path: found.source.inMemory ? null : found.source.uri.fsPath,
sourceReference: found.source.reference
}
return found.source.raw;
}
}
}
@ -45,13 +52,11 @@ export class Source {
{ path: paths.normalize(uri.fsPath, true) };
}
public static fromRawSource(rawSource: DebugProtocol.Source): Source {
const uriStr = rawSource.path ? uri.file(rawSource.path).toString() : Source.INTERNAL_URI_PREFIX + rawSource.name;
return new Source(rawSource.name, uriStr, rawSource.origin, rawSource.sourceReference);
}
public static fromUri(uri: uri): Source {
return new Source(Source.getName(uri), uri.toString(), '');
return new Source({
name: Source.getName(uri),
path: uri.fsPath,
});
}
private static getName(uri: uri): string {

View file

@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!../browser/media/debug.contribution';
import 'vs/css!../browser/media/debugHover';
import nls = require('vs/nls');
import { CommonEditorRegistry, ContextKey, EditorActionDescriptor } from 'vs/editor/common/editorCommonExtensions';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';

View file

@ -228,13 +228,13 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
}));
this.toDispose.push(this.session.addListener2(debug.SessionEvents.STOPPED, (event: DebugProtocol.StoppedEvent) => {
this.setStateAndEmit(debug.State.Stopped, event.body.reason);
this.setStateAndEmit(debug.State.Stopped);
const threadId = event.body.threadId;
this.getThreadData(threadId).then(() => {
this.session.stackTrace({ threadId: threadId, levels: 20 }).done((result) => {
this.model.rawUpdate({ threadId: threadId, callStack: result.body.stackFrames, exception: event.body && event.body.reason === 'exception' });
this.model.rawUpdate({ threadId: threadId, callStack: result.body.stackFrames, stoppedReason: event.body.reason });
this.windowService.getWindow().focus();
const callStack = this.model.getThreads()[threadId].callStack;
if (callStack.length > 0) {
@ -312,7 +312,8 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
private loadBreakpoints(): debug.IBreakpoint[] {
try {
return JSON.parse(this.storageService.get(DEBUG_BREAKPOINTS_KEY, StorageScope.WORKSPACE, '[]')).map((breakpoint: any) => {
return new model.Breakpoint(new Source(breakpoint.source.name, breakpoint.source.uri, breakpoint.source.reference), breakpoint.desiredLineNumber || breakpoint.lineNumber, breakpoint.enabled, breakpoint.condition);
return new model.Breakpoint(breakpoint.source.raw ? new Source(breakpoint.source.raw) : Source.fromUri(uri.parse(breakpoint.source.uri)),
breakpoint.desiredLineNumber || breakpoint.lineNumber, breakpoint.enabled, breakpoint.condition);
});
} catch (e) {
return [];
@ -356,9 +357,9 @@ export class DebugService extends ee.EventEmitter implements debug.IDebugService
return this.state;
}
private setStateAndEmit(newState: debug.State, data?: any): void {
private setStateAndEmit(newState: debug.State): void {
this.state = newState;
this.emit(debug.ServiceEvents.STATE_CHANGED, data);
this.emit(debug.ServiceEvents.STATE_CHANGED);
}
public get enabled(): boolean {

View file

@ -15,7 +15,6 @@ suite('Debug - Source', () => {
assert.equal(source.available, true);
assert.equal(source.inMemory, false);
assert.equal(source.reference, 0);
assert.equal(source.uri.toString(), u.toString());
assert.equal(source.name, 'd');
});
@ -26,7 +25,7 @@ suite('Debug - Source', () => {
path: '/xx/yy/zz',
sourceReference: 0
};
const source = Source.fromRawSource(rawSource);
const source = new Source(rawSource);
assert.equal(source.available, true);
assert.equal(source.name, rawSource.name);
@ -40,7 +39,7 @@ suite('Debug - Source', () => {
name: 'internalModule.js',
sourceReference: 11
};
const source = Source.fromRawSource(rawSource);
const source = new Source(rawSource);
assert.equal(source.available, true);
assert.equal(source.name, rawSource.name);

View file

@ -245,11 +245,11 @@
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
to { transform: rotate(1080deg); }
}
.monaco-shell .git-statusbar-group > .git-statusbar-sync-item.syncing > .octicon {
animation: 1.5s linear infinite spin;
animation: 2s ease-in-out infinite spin;
}
.monaco-shell .git-statusbar-group > .git-statusbar-sync-item.disabled > .ahead-behind,

View file

@ -1,2 +1,5 @@
#!/bin/sh
AMD_ENTRYPOINT="$VSCODE_GIT_ASKPASS_MODULE_ID" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_BOOTSTRAP" $*
VSCODE_GIT_ASKPASS_PIPE=`mktemp`
AMD_ENTRYPOINT="$VSCODE_GIT_ASKPASS_MODULE_ID" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_BOOTSTRAP" $*
cat $VSCODE_GIT_ASKPASS_PIPE
rm $VSCODE_GIT_ASKPASS_PIPE

View file

@ -8,6 +8,7 @@
import events = require('vs/base/common/eventEmitter');
import { connect } from 'vs/base/node/service.net';
import { TPromise } from 'vs/base/common/winjs.base';
import * as fs from 'fs';
export interface ICredentials {
username: string;
@ -42,7 +43,12 @@ function main(argv: string[]): void {
return fatal('Missing git id');
}
if (!process.env['VSCODE_GIT_ASKPASS_PIPE']) {
return fatal('Missing pipe');
}
var id = process.env['VSCODE_GIT_REQUEST_ID'];
var output = process.env['VSCODE_GIT_ASKPASS_PIPE'];
var request = argv[2];
var host = argv[4].substring(1, argv[4].length - 2);
@ -52,7 +58,7 @@ function main(argv: string[]): void {
return service.askpass(id, host, process.env['MONACO_GIT_COMMAND']).then(result => {
if (result) {
console.log(/^Username$/i.test(request) ? result.username : result.password);
fs.writeFileSync(output, (/^Username$/i.test(request) ? result.username : result.password) + '\n');
}
return client;

View file

@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import ipc = require('ipc');
import platform = require('vs/base/common/platform');
import { TPromise } from 'vs/base/common/winjs.base';
@ -51,7 +52,8 @@ export class GitAskpassService {
resizable: false,
width: 450,
height: platform.isWindows ? 280 : 260,
show: true
show: true,
title: nls.localize('git', "Git")
});
win.setMenuBarVisibility(false);

View file

@ -44,12 +44,12 @@ function exec(child: ChildProcess, encoding = 'utf8'): TPromise<IExecutionResult
new TPromise<string>(c => {
let buffers: Buffer[] = [];
on(child.stdout, 'data', b => buffers.push(b));
once(child.stdout, 'close', () => c(Buffer.concat(buffers).toString(encoding)));
once(child.stdout, 'close', () => c(iconv.decode(Buffer.concat(buffers), encoding)));
}),
new TPromise<string>(c => {
let buffers: Buffer[] = [];
on(child.stderr, 'data', b => buffers.push(b));
once(child.stderr, 'close', () => c(Buffer.concat(buffers).toString(encoding)));
once(child.stderr, 'close', () => c(iconv.decode(Buffer.concat(buffers), encoding)));
})
]).then(values => {
disposeAll(disposables);

View file

@ -180,7 +180,10 @@ export class MarkersHandler extends QuickOpenHandler {
// 2nd viewstate
const editor = this._editorService.getActiveEditor();
const viewState = (<ICommonCodeEditor>editor.getControl()).saveViewState();
let viewState: IEditorViewState;
if (editor) {
viewState = (<ICommonCodeEditor>editor.getControl()).saveViewState();
}
this._activeSession = [model, viewState];
}
@ -199,8 +202,10 @@ export class MarkersHandler extends QuickOpenHandler {
if (this._activeSession) {
if (canceled) {
const [, viewState] = this._activeSession;
const editor = this._editorService.getActiveEditor();
(<ICommonCodeEditor>editor.getControl()).restoreViewState(viewState);
if (viewState) {
const editor = this._editorService.getActiveEditor();
(<ICommonCodeEditor>editor.getControl()).restoreViewState(viewState);
}
}
this._activeSession = undefined;
}

View file

@ -19,9 +19,6 @@ import flow = require('vs/base/node/flow');
import {ISerializedFileMatch, IRawSearch, ISearchEngine} from 'vs/workbench/services/search/node/rawSearchService';
export class FileWalker {
private static ENOTDIR = 'ENOTDIR';
private config: IRawSearch;
private filePattern: string;
private excludePattern: glob.IExpression;
@ -43,6 +40,8 @@ export class FileWalker {
this.includePattern = config.includePattern;
this.maxResults = config.maxResults || null;
this.walkedPaths = Object.create(null);
this.resultCount = 0;
this.isLimitHit = false;
// Normalize file patterns to forward slashes
if (this.filePattern && this.filePattern.indexOf(paths.sep) >= 0) {
@ -51,23 +50,17 @@ export class FileWalker {
}
}
private resetState(): void {
this.walkedPaths = Object.create(null);
this.resultCount = 0;
this.isLimitHit = false;
}
public cancel(): void {
this.isCanceled = true;
}
public walk(rootFolders: string[], extraFiles: string[], onResult: (result: ISerializedFileMatch) => void, done: (error: Error, isLimitHit: boolean) => void): void {
// Reset state
this.resetState();
// Support that the file pattern is a full path to a file that exists
this.checkFilePatternAbsoluteMatch((exists) => {
if (this.isCanceled) {
return done(null, this.isLimitHit);
}
// Report result from file pattern if matching
if (exists) {
@ -76,7 +69,7 @@ export class FileWalker {
// Optimization: a match on an absolute path is a good result and we do not
// continue walking the entire root paths array for other matches because
// it is very unlikely that another file would match on the full absolute path
return done(null, false);
return done(null, this.isLimitHit);
}
// For each extra file

View file

@ -17,6 +17,11 @@ import {FileWalker} from 'vs/workbench/services/search/node/fileSearch';
import {UTF16le, UTF16be, UTF8} from 'vs/base/node/encoding';
import {ISerializedFileMatch, IRawSearch, ISearchEngine} from 'vs/workbench/services/search/node/rawSearchService';
interface ReadLinesOptions {
bufferLength: number;
encoding: string;
}
export class Engine implements ISearchEngine {
private rootFolders: string[];
private extraFiles: string[];
@ -30,6 +35,7 @@ export class Engine implements ISearchEngine {
private walkerError: Error;
private walkerIsDone: boolean;
private fileEncoding: string;
private limitReached: boolean;
constructor(config: IRawSearch, walker: FileWalker) {
this.rootFolders = config.rootFolders;
@ -37,6 +43,7 @@ export class Engine implements ISearchEngine {
this.walker = walker;
this.contentPattern = strings.createRegExp(config.contentPattern.pattern, config.contentPattern.isRegExp, config.contentPattern.isCaseSensitive, config.contentPattern.isWordMatch);
this.isCanceled = false;
this.limitReached = false;
this.maxResults = config.maxResults;
this.worked = 0;
this.total = 0;
@ -50,53 +57,46 @@ export class Engine implements ISearchEngine {
public search(onResult: (match: ISerializedFileMatch) => void, onProgress: (progress: IProgress) => void, done: (error: Error, isLimitHit: boolean) => void): void {
let resultCounter = 0;
let limitReached = false;
let unwind = (processed: number) => {
this.worked += processed;
// Emit progress()
if (processed && !this.isDone) {
// Emit progress() unless we got canceled or hit the limit
if (processed && !this.isDone && !this.isCanceled && !this.limitReached) {
onProgress({ total: this.total, worked: this.worked });
}
// Emit done()
if (this.worked === this.total && this.walkerIsDone && !this.isDone) {
this.isDone = true;
done(this.walkerError, limitReached);
done(this.walkerError, this.limitReached);
}
};
// Walk over the file system
this.walker.walk(this.rootFolders, this.extraFiles, (result) => {
// Indicate progress to the outside
this.total++;
onProgress({ total: this.total, worked: this.worked });
// If the result is empty or we have reached the limit or we are canceled, ignore it
if (limitReached || this.isCanceled) {
if (this.limitReached || this.isCanceled) {
return unwind(1);
}
// Indicate progress to the outside
onProgress({ total: this.total, worked: this.worked });
let fileMatch: FileMatch = null;
let doneCallback = (error?: Error) => {
// If the result is empty or we have reached the limit or we are canceled, ignore it
if (error || !fileMatch || fileMatch.isEmpty() || this.isCanceled) {
return unwind(1);
}
// Otherwise send it back as result
else {
if (!error && !this.isCanceled && fileMatch && !fileMatch.isEmpty()) {
onResult(fileMatch.serialize());
return unwind(1);
}
return unwind(1);
};
let perLineCallback = (line: string, lineNumber: number) => {
if (limitReached || this.isCanceled) {
if (this.limitReached || this.isCanceled) {
return; // return early if canceled or limit reached
}
@ -104,10 +104,10 @@ export class Engine implements ISearchEngine {
let match = this.contentPattern.exec(line);
// Record all matches into file result
while (match !== null && match[0].length > 0 && !limitReached && !this.isCanceled) {
while (match !== null && match[0].length > 0 && !this.limitReached && !this.isCanceled) {
resultCounter++;
if (this.maxResults && resultCounter >= this.maxResults) {
limitReached = true;
this.limitReached = true;
}
if (fileMatch === null) {
@ -126,132 +126,129 @@ export class Engine implements ISearchEngine {
};
// Read lines buffered to support large files
readlinesAsync(result.path, perLineCallback, { bufferLength: 8096, encoding: this.fileEncoding }, doneCallback);
this.readlinesAsync(result.path, perLineCallback, { bufferLength: 8096, encoding: this.fileEncoding }, doneCallback);
}, (error, isLimitHit) => {
this.walkerIsDone = true;
this.walkerError = error;
unwind(0 /* walker is done, indicate this back to our handler to be able to unwind */);
});
}
}
interface ReadLinesOptions {
bufferLength: number;
encoding: string;
}
function readlinesAsync(filename: string, perLineCallback: (line: string, lineNumber: number) => void, options: ReadLinesOptions, callback: (error: Error) => void): void {
fs.open(filename, 'r', null, (error: Error, fd: number) => {
if (error) {
return callback(error);
}
let buffer = new Buffer(options.bufferLength);
let pos: number;
let i: number;
let line = '';
let lineNumber = 0;
let lastBufferHadTraillingCR = false;
function decode(buffer: NodeBuffer): string {
if (options.encoding === UTF8) {
return buffer.toString(); // much faster to use built in toString() when encoding is default
}
return iconv.decode(buffer, options.encoding);
}
function lineFinished(offset: number): void {
line += decode(buffer.slice(pos, i + offset));
perLineCallback(line, lineNumber);
line = '';
lineNumber++;
pos = i + offset;
}
function readFile(isFirstRead: boolean, clb: (error: Error) => void): void {
fs.read(fd, buffer, 0, buffer.length, null, (error: Error, bytesRead: number, buffer: NodeBuffer) => {
if (error) {
return clb(error);
}
if (bytesRead === 0) {
return clb(null);
}
pos = 0;
i = 0;
// Detect encoding and mime when this is the beginning of the file
if (isFirstRead) {
let mimeAndEncoding = detectMimeAndEncodingFromBuffer(buffer, bytesRead);
if (mimeAndEncoding.mimes[mimeAndEncoding.mimes.length - 1] !== baseMime.MIME_TEXT) {
return clb(null); // skip files that seem binary
}
// Check for BOM offset
switch (mimeAndEncoding.encoding) {
case UTF8:
pos = i = 3;
options.encoding = UTF8;
break;
case UTF16be:
pos = i = 2;
options.encoding = UTF16be;
break;
case UTF16le:
pos = i = 2;
options.encoding = UTF16le;
break;
}
}
if (lastBufferHadTraillingCR) {
if (buffer[i] === 0x0a) { // LF (Line Feed)
lineFinished(1);
i++;
} else {
lineFinished(0);
}
lastBufferHadTraillingCR = false;
}
for (; i < bytesRead; ++i) {
if (buffer[i] === 0x0a) { // LF (Line Feed)
lineFinished(1);
} else if (buffer[i] === 0x0d) { // CR (Carriage Return)
if (i + 1 === bytesRead) {
lastBufferHadTraillingCR = true;
} else if (buffer[i + 1] === 0x0a) { // LF (Line Feed)
lineFinished(2);
i++;
} else {
lineFinished(1);
}
}
}
line += decode(buffer.slice(pos, bytesRead));
readFile(false /* isFirstRead */, clb); // Continue reading
});
}
readFile(true /* isFirstRead */, (error: Error) => {
private readlinesAsync(filename: string, perLineCallback: (line: string, lineNumber: number) => void, options: ReadLinesOptions, callback: (error: Error) => void): void {
fs.open(filename, 'r', null, (error: Error, fd: number) => {
if (error) {
return callback(error);
}
if (line.length) {
perLineCallback(line, lineNumber); // handle last line
let buffer = new Buffer(options.bufferLength);
let pos: number;
let i: number;
let line = '';
let lineNumber = 0;
let lastBufferHadTraillingCR = false;
const outer = this;
function decode(buffer: NodeBuffer): string {
if (options.encoding === UTF8) {
return buffer.toString(); // much faster to use built in toString() when encoding is default
}
return iconv.decode(buffer, options.encoding);
}
fs.close(fd, (error: Error) => {
callback(error);
function lineFinished(offset: number): void {
line += decode(buffer.slice(pos, i + offset));
perLineCallback(line, lineNumber);
line = '';
lineNumber++;
pos = i + offset;
}
function readFile(isFirstRead: boolean, clb: (error: Error) => void): void {
if (outer.limitReached || outer.isCanceled) {
return clb(null); // return early if canceled or limit reached
}
fs.read(fd, buffer, 0, buffer.length, null, (error: Error, bytesRead: number, buffer: NodeBuffer) => {
if (error || bytesRead === 0 || outer.limitReached || outer.isCanceled) {
return clb(error); // return early if canceled or limit reached or no more bytes to read
}
pos = 0;
i = 0;
// Detect encoding and mime when this is the beginning of the file
if (isFirstRead) {
let mimeAndEncoding = detectMimeAndEncodingFromBuffer(buffer, bytesRead);
if (mimeAndEncoding.mimes[mimeAndEncoding.mimes.length - 1] !== baseMime.MIME_TEXT) {
return clb(null); // skip files that seem binary
}
// Check for BOM offset
switch (mimeAndEncoding.encoding) {
case UTF8:
pos = i = 3;
options.encoding = UTF8;
break;
case UTF16be:
pos = i = 2;
options.encoding = UTF16be;
break;
case UTF16le:
pos = i = 2;
options.encoding = UTF16le;
break;
}
}
if (lastBufferHadTraillingCR) {
if (buffer[i] === 0x0a) { // LF (Line Feed)
lineFinished(1);
i++;
} else {
lineFinished(0);
}
lastBufferHadTraillingCR = false;
}
for (; i < bytesRead; ++i) {
if (buffer[i] === 0x0a) { // LF (Line Feed)
lineFinished(1);
} else if (buffer[i] === 0x0d) { // CR (Carriage Return)
if (i + 1 === bytesRead) {
lastBufferHadTraillingCR = true;
} else if (buffer[i + 1] === 0x0a) { // LF (Line Feed)
lineFinished(2);
i++;
} else {
lineFinished(1);
}
}
}
line += decode(buffer.slice(pos, bytesRead));
readFile(false /* isFirstRead */, clb); // Continue reading
});
}
readFile(true /* isFirstRead */, (error: Error) => {
if (error) {
return callback(error);
}
if (line.length) {
perLineCallback(line, lineNumber); // handle last line
}
fs.close(fd, (error: Error) => {
callback(error);
});
});
});
});
}
}
class FileMatch implements ISerializedFileMatch {

View file

@ -14,7 +14,7 @@ import * as types from 'vs/workbench/api/common/extHostTypes';
import {Range as CodeEditorRange} from 'vs/editor/common/core/range';
import * as EditorCommon from 'vs/editor/common/editorCommon';
import {Model as EditorModel} from 'vs/editor/common/model/model';
import threadService from './testThreadService'
import {TestThreadService} from './testThreadService'
import {create as createInstantiationService} from 'vs/platform/instantiation/common/instantiationService';
import {MarkerService} from 'vs/platform/markers/common/markerService';
import {IMarkerService} from 'vs/platform/markers/common/markers';
@ -27,6 +27,7 @@ import {registerApiCommands} from 'vs/workbench/api/common/extHostApiCommands';
import {ExtHostCommands, MainThreadCommands} from 'vs/workbench/api/common/extHostCommands';
import {ExtHostModelService} from 'vs/workbench/api/common/extHostDocuments';
const defaultSelector = { scheme: 'far' };
const model: EditorCommon.IModel = new EditorModel(
[
'This is the first line',
@ -36,6 +37,7 @@ const model: EditorCommon.IModel = new EditorModel(
undefined,
URI.parse('far://testing/file.b'));
let threadService: TestThreadService;
let extHost: ExtHostLanguageFeatures;
let mainThread: MainThreadLanguageFeatures;
let commands: ExtHostCommands;
@ -44,13 +46,20 @@ let originalErrorHandler: (e: any) => any;
suite('ExtHostLanguageFeatureCommands', function() {
suiteSetup(() => {
suiteSetup((done) => {
originalErrorHandler = errorHandler.getUnexpectedErrorHandler();
setUnexpectedErrorHandler(() => { });
let instantiationService = createInstantiationService();
threadService.setInstantiationService(instantiationService);
threadService = new TestThreadService(instantiationService);
instantiationService.addSingleton(IKeybindingService, <IKeybindingService>{
executeCommand(id, args): any {
let handler = KeybindingsRegistry.getCommands()[id];
return TPromise.as(instantiationService.invokeFunction(handler, args));
}
});
instantiationService.addSingleton(IMarkerService, new MarkerService(threadService));
instantiationService.addSingleton(IThreadService, threadService);
instantiationService.addSingleton(IModelService, <IModelService>{
@ -63,12 +72,6 @@ suite('ExtHostLanguageFeatureCommands', function() {
onModelModeChanged: undefined,
onModelRemoved: undefined
});
instantiationService.addSingleton(IKeybindingService, <IKeybindingService>{
executeCommand(id, args): any {
let handler = KeybindingsRegistry.getCommands()[id];
return TPromise.as(instantiationService.invokeFunction(handler, args));
}
})
threadService.getRemotable(ExtHostModelService)._acceptModelAdd({
isDirty: false,
@ -88,6 +91,8 @@ suite('ExtHostLanguageFeatureCommands', function() {
registerApiCommands(threadService);
mainThread = threadService.getRemotable(MainThreadLanguageFeatures);
extHost = threadService.getRemotable(ExtHostLanguageFeatures);
threadService.sync().then(done, done)
});
suiteTeardown(() => {
@ -122,38 +127,38 @@ suite('ExtHostLanguageFeatureCommands', function() {
// });
});
// test('WorkspaceSymbols, back and forth', function(done) {
test('WorkspaceSymbols, back and forth', function(done) {
// disposables.push(extHost.registerWorkspaceSymbolProvider(<vscode.WorkspaceSymbolProvider>{
// provideWorkspaceSymbols(query): any {
// return [
// new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first')),
// new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/second'))
// ]
// }
// }));
disposables.push(extHost.registerWorkspaceSymbolProvider(<vscode.WorkspaceSymbolProvider>{
provideWorkspaceSymbols(query): any {
return [
new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first')),
new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/second'))
]
}
}));
// disposables.push(extHost.registerWorkspaceSymbolProvider(<vscode.WorkspaceSymbolProvider>{
// provideWorkspaceSymbols(query): any {
// return [
// new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first'))
// ]
// }
// }));
disposables.push(extHost.registerWorkspaceSymbolProvider(<vscode.WorkspaceSymbolProvider>{
provideWorkspaceSymbols(query): any {
return [
new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first'))
]
}
}));
// threadService.sync().then(() => {
// commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', 'testing').then(value => {
threadService.sync().then(() => {
commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeWorkspaceSymbolProvider', 'testing').then(value => {
// for (let info of value) {
// assert.ok(info instanceof types.SymbolInformation);
// assert.equal(info.name, 'testing');
// assert.equal(info.kind, types.SymbolKind.Array);
// }
// assert.equal(value.length, 3);
// done();
// });
// });
// });
for (let info of value) {
assert.ok(info instanceof types.SymbolInformation);
assert.equal(info.name, 'testing');
assert.equal(info.kind, types.SymbolKind.Array);
}
assert.equal(value.length, 3);
done();
}, done);
}, done);
});
// --- definition
@ -175,150 +180,159 @@ suite('ExtHostLanguageFeatureCommands', function() {
// });
});
// test('Definition, back and forth', function(done) {
test('Definition, back and forth', function(done) {
// disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
// provideDefinition(doc: any): any {
// return new types.Location(doc.uri, new types.Range(0, 0, 0, 0));
// }
// }));
// disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
// provideDefinition(doc: any): any {
// return [
// new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
// new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
// new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
// ]
// }
// }));
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(doc: any): any {
return new types.Location(doc.uri, new types.Range(0, 0, 0, 0));
}
}));
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(doc: any): any {
return [
new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
]
}
}));
// threadService.sync().then(() => {
// commands.executeCommand<vscode.Location[]>('vscode.executeDefinitionProvider', model.getAssociatedResource(), new types.Position(0, 0)).then(values => {
// assert.equal(values.length, 4);
// done();
// });
// });
// });
threadService.sync().then(() => {
commands.executeCommand<vscode.Location[]>('vscode.executeDefinitionProvider', model.getAssociatedResource(), new types.Position(0, 0)).then(values => {
assert.equal(values.length, 4);
done();
}, done);
}, done);
});
// --- outline
// test('Outline, back and forth', function(done) {
// disposables.push(extHost.registerDocumentSymbolProvider(defaultSelector, <vscode.DocumentSymbolProvider>{
// provideDocumentSymbols(): any {
// return [
// new types.SymbolInformation('testing1', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0)),
// new types.SymbolInformation('testing2', types.SymbolKind.Enum, new types.Range(0, 1, 0, 3)),
// ]
// }
// }));
test('Outline, back and forth', function(done) {
disposables.push(extHost.registerDocumentSymbolProvider(defaultSelector, <vscode.DocumentSymbolProvider>{
provideDocumentSymbols(): any {
return [
new types.SymbolInformation('testing1', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0)),
new types.SymbolInformation('testing2', types.SymbolKind.Enum, new types.Range(0, 1, 0, 3)),
]
}
}));
// threadService.sync().then(() => {
// commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeDocumentSymbolProvider', model.getAssociatedResource()).then(values => {
// assert.equal(values.length, 2);
// let [first, second] = values;
// assert.equal(first.name, 'testing2');
// assert.equal(second.name, 'testing1');
// done();
// });
// });
// });
threadService.sync().then(() => {
commands.executeCommand<vscode.SymbolInformation[]>('vscode.executeDocumentSymbolProvider', model.getAssociatedResource()).then(values => {
assert.equal(values.length, 2);
let [first, second] = values;
assert.equal(first.name, 'testing2');
assert.equal(second.name, 'testing1');
done();
}, done);
}, done);
});
// --- suggest
// test('Suggest, back and forth', function(done) {
// disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
// provideCompletionItems(doc, pos): any {
// let a = new types.CompletionItem('item1');
// let b = new types.CompletionItem('item2');
// b.textEdit = types.TextEdit.replace(new types.Range(0, 4, 0, 8), 'foo'); // overwite after
// let c = new types.CompletionItem('item3');
// c.textEdit = types.TextEdit.replace(new types.Range(0, 1, 0, 6), 'foobar'); // overwite before & after
// let d = new types.CompletionItem('item4');
// d.textEdit = types.TextEdit.replace(new types.Range(0, 1, 0, 4), ''); // overwite before
// return [a, b, c, d];
// }
// }, []));
test('Suggest, back and forth', function(done) {
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(doc, pos): any {
let a = new types.CompletionItem('item1');
let b = new types.CompletionItem('item2');
b.textEdit = types.TextEdit.replace(new types.Range(0, 4, 0, 8), 'foo'); // overwite after
let c = new types.CompletionItem('item3');
c.textEdit = types.TextEdit.replace(new types.Range(0, 1, 0, 6), 'foobar'); // overwite before & after
let d = new types.CompletionItem('item4');
d.textEdit = types.TextEdit.replace(new types.Range(0, 1, 0, 4), ''); // overwite before
return [a, b, c, d];
}
}, []));
// threadService.sync().then(() => {
// commands.executeCommand<vscode.CompletionItem[]>('vscode.executeCompletionItemProvider', model.getAssociatedResource(), new types.Position(0, 4)).then(values => {
// try {
// assert.equal(values.length, 4);
// let [first, second, third, forth] = values;
// assert.equal(first.label, 'item1');
// assert.equal(first.textEdit.newText, 'item1');
// assert.equal(first.textEdit.range.start.line, 0);
// assert.equal(first.textEdit.range.start.character, 0);
// assert.equal(first.textEdit.range.end.line, 0);
// assert.equal(first.textEdit.range.end.character, 4);
threadService.sync().then(() => {
commands.executeCommand<vscode.CompletionItem[]>('vscode.executeCompletionItemProvider', model.getAssociatedResource(), new types.Position(0, 4)).then(values => {
try {
assert.equal(values.length, 4);
let [first, second, third, forth] = values;
assert.equal(first.label, 'item1');
assert.equal(first.textEdit.newText, 'item1');
assert.equal(first.textEdit.range.start.line, 0);
assert.equal(first.textEdit.range.start.character, 0);
assert.equal(first.textEdit.range.end.line, 0);
assert.equal(first.textEdit.range.end.character, 4);
// assert.equal(second.label, 'item2');
// assert.equal(second.textEdit.newText, 'foo');
// assert.equal(second.textEdit.range.start.line, 0);
// assert.equal(second.textEdit.range.start.character, 4);
// assert.equal(second.textEdit.range.end.line, 0);
// assert.equal(second.textEdit.range.end.character, 8);
assert.equal(second.label, 'item2');
assert.equal(second.textEdit.newText, 'foo');
assert.equal(second.textEdit.range.start.line, 0);
assert.equal(second.textEdit.range.start.character, 4);
assert.equal(second.textEdit.range.end.line, 0);
assert.equal(second.textEdit.range.end.character, 8);
// assert.equal(third.label, 'item3');
// assert.equal(third.textEdit.newText, 'foobar');
// assert.equal(third.textEdit.range.start.line, 0);
// assert.equal(third.textEdit.range.start.character, 1);
// assert.equal(third.textEdit.range.end.line, 0);
// assert.equal(third.textEdit.range.end.character, 6);
assert.equal(third.label, 'item3');
assert.equal(third.textEdit.newText, 'foobar');
assert.equal(third.textEdit.range.start.line, 0);
assert.equal(third.textEdit.range.start.character, 1);
assert.equal(third.textEdit.range.end.line, 0);
assert.equal(third.textEdit.range.end.character, 6);
// assert.equal(forth.label, 'item4');
// assert.equal(forth.textEdit.newText, '');
// assert.equal(forth.textEdit.range.start.line, 0);
// assert.equal(forth.textEdit.range.start.character, 1);
// assert.equal(forth.textEdit.range.end.line, 0);
// assert.equal(forth.textEdit.range.end.character, 4);
// done();
// } catch (e) {
// done(e);
// }
// });
// });
// });
assert.equal(forth.label, 'item4');
assert.equal(forth.textEdit.newText, '');
assert.equal(forth.textEdit.range.start.line, 0);
assert.equal(forth.textEdit.range.start.character, 1);
assert.equal(forth.textEdit.range.end.line, 0);
assert.equal(forth.textEdit.range.end.character, 4);
done();
} catch (e) {
done(e);
}
}, done);
}, done);
});
// --- quickfix
// test('QuickFix, back and forth', function(done) {
// disposables.push(extHost.registerCodeActionProvider(defaultSelector, <vscode.CodeActionProvider>{
// provideCodeActions(): any {
// return [{ command: 'testing', title: 'Title', arguments: [1, 2, true] }];
// }
// }));
test('QuickFix, back and forth', function(done) {
disposables.push(extHost.registerCodeActionProvider(defaultSelector, <vscode.CodeActionProvider>{
provideCodeActions(): any {
return [{ command: 'testing', title: 'Title', arguments: [1, 2, true] }];
}
}));
// threadService.sync().then(() => {
// commands.executeCommand<vscode.Command[]>('vscode.executeCodeActionProvider', model.getAssociatedResource(), new types.Range(0, 0, 1, 1)).then(value => {
// assert.equal(value.length, 1);
// let [first] = value;
// assert.equal(first.title, 'Title');
// assert.equal(first.command, 'testing');
// assert.deepEqual(first.arguments, [1, 2, true]);
// done();
// });
// });
// });
threadService.sync().then(() => {
commands.executeCommand<vscode.Command[]>('vscode.executeCodeActionProvider', model.getAssociatedResource(), new types.Range(0, 0, 1, 1)).then(value => {
assert.equal(value.length, 1);
let [first] = value;
assert.equal(first.title, 'Title');
assert.equal(first.command, 'testing');
assert.deepEqual(first.arguments, [1, 2, true]);
done();
}, done);
});
});
// --- code lens
// test('CodeLens, back and forth', function(done) {
// disposables.push(extHost.registerCodeLensProvider(defaultSelector, <vscode.CodeLensProvider>{
// provideCodeLenses(): any {
// return [new types.CodeLens(new types.Range(0, 0, 1, 1), { title: 'Title', command: 'cmd', arguments: [1, 2, true] })];
// }
// }));
test('CodeLens, back and forth', function(done) {
// threadService.sync().then(() => {
// commands.executeCommand<vscode.CodeLens[]>('vscode.executeCodeLensProvider', model.getAssociatedResource()).then(value => {
// assert.equal(value.length, 1);
// let [first] = value;
const complexArg = {
foo() { },
bar() { },
big: extHost
}
// assert.equal(first.command.title, 'Title');
// assert.equal(first.command.command, 'cmd');
// assert.deepEqual(first.command.arguments, [1, 2, true]);
// done();
// });
// });
// });
disposables.push(extHost.registerCodeLensProvider(defaultSelector, <vscode.CodeLensProvider>{
provideCodeLenses(): any {
return [new types.CodeLens(new types.Range(0, 0, 1, 1), { title: 'Title', command: 'cmd', arguments: [1, true, complexArg] })];
}
}));
threadService.sync().then(() => {
commands.executeCommand<vscode.CodeLens[]>('vscode.executeCodeLensProvider', model.getAssociatedResource()).then(value => {
assert.equal(value.length, 1);
let [first] = value;
assert.equal(first.command.title, 'Title');
assert.equal(first.command.command, 'cmd');
assert.equal(first.command.arguments[0], 1);
assert.equal(first.command.arguments[1], true);
assert.equal(first.command.arguments[2], complexArg);
done();
}, done);
});
});
});

View file

@ -13,7 +13,7 @@ import * as types from 'vs/workbench/api/common/extHostTypes';
import {Range as CodeEditorRange} from 'vs/editor/common/core/range';
import * as EditorCommon from 'vs/editor/common/editorCommon';
import {Model as EditorModel} from 'vs/editor/common/model/model';
import threadService from './testThreadService'
import {TestThreadService} from './testThreadService'
import {create as createInstantiationService} from 'vs/platform/instantiation/common/instantiationService';
import {MarkerService} from 'vs/platform/markers/common/markerService';
import {IMarkerService} from 'vs/platform/markers/common/markers';
@ -47,6 +47,7 @@ const model: EditorCommon.IModel = new EditorModel(
let extHost: ExtHostLanguageFeatures;
let mainThread: MainThreadLanguageFeatures;
let disposables: vscode.Disposable[] = [];
let threadService: TestThreadService;
let originalErrorHandler: (e: any) => any;
suite('ExtHostLanguageFeatures', function() {
@ -54,7 +55,7 @@ suite('ExtHostLanguageFeatures', function() {
suiteSetup(() => {
let instantiationService = createInstantiationService();
threadService.setInstantiationService(instantiationService);
threadService = new TestThreadService(instantiationService);
instantiationService.addSingleton(IMarkerService, new MarkerService(threadService));
instantiationService.addSingleton(IThreadService, threadService);

View file

@ -7,10 +7,16 @@
import {NullThreadService} from 'vs/platform/test/common/nullThreadService';
import {SyncDescriptor0} from 'vs/platform/instantiation/common/descriptors';
import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation';
import {TPromise} from 'vs/base/common/winjs.base';
export class TestThreadService extends NullThreadService {
constructor(instantiationService: IInstantiationService) {
super();
this.setInstantiationService(instantiationService);
}
private _callCountValue: number = 0;
private _idle: TPromise<any>;
private _completeIdle: Function;
@ -90,6 +96,3 @@ export class TestThreadService extends NullThreadService {
return this._getOrCreateLocalInstance(id, descriptor);
}
}
const Instance = new TestThreadService();
export default Instance;