diff --git a/extensions/csharp/package.json b/extensions/csharp/package.json index 180fba39a2e014cd3afd050be2e1ce58e1c2d5be..82e1a8d701aee8bbf252739e48df6dda4876904f 100644 --- a/extensions/csharp/package.json +++ b/extensions/csharp/package.json @@ -14,6 +14,10 @@ "language": "csharp", "scopeName": "source.cs", "path": "./syntaxes/csharp.json" + }], + "jsonValidation": [{ + "fileMatch": "project.json", + "url": "http://json.schemastore.org/project" }] } } \ No newline at end of file diff --git a/extensions/javascript/package.json b/extensions/javascript/package.json index 17834d8ee293f79e2f8ce1928b398e1a747e7636..a1e458939b1667e868e5c36024a1c9b9ebf94219 100644 --- a/extensions/javascript/package.json +++ b/extensions/javascript/package.json @@ -2,37 +2,86 @@ "name": "javascript", "version": "0.1.0", "publisher": "vscode", - "engines": { "vscode": "*" }, + "engines": { + "vscode": "*" + }, "contributes": { - "languages": [{ - "id": "javascriptreact", - "aliases": ["JavaScript React","jsx"], - "extensions": [".jsx"], - "configuration": "./javascript.configuration.json" - },{ - "id": "javascript", - "aliases": ["JavaScript", "javascript", "js"], - "extensions": [".js", ".es6"], - "filenames": ["jakefile"], - "firstLine": "^#!.*\\bnode", - "mimetypes": ["text/javascript"] - }], - "grammars": [{ - "language": "javascriptreact", - "scopeName": "source.jsx", - "path": "./syntaxes/JavaScriptReact.tmLanguage" - },{ - "language": "javascript", - "scopeName": "source.js", - "path": "./syntaxes/JavaScript.tmLanguage" - },{ - // referenced by other grammars - "scopeName": "source.js.regexp", - "path": "./syntaxes/Regular Expressions (JavaScript).tmLanguage" - }], - "snippets": [{ - "language": "javascript", - "path": "./snippets/javascript.json" - }] + "languages": [ + { + "id": "javascriptreact", + "aliases": [ + "JavaScript React", + "jsx" + ], + "extensions": [ + ".jsx" + ], + "configuration": "./javascript.configuration.json" + }, + { + "id": "javascript", + "aliases": [ + "JavaScript", + "javascript", + "js" + ], + "extensions": [ + ".js", + ".es6" + ], + "filenames": [ + "jakefile" + ], + "firstLine": "^#!.*\\bnode", + "mimetypes": [ + "text/javascript" + ] + } + ], + "grammars": [ + { + "language": "javascriptreact", + "scopeName": "source.jsx", + "path": "./syntaxes/JavaScriptReact.tmLanguage" + }, + { + "language": "javascript", + "scopeName": "source.js", + "path": "./syntaxes/JavaScript.tmLanguage" + }, + { + // referenced by other grammars + "scopeName": "source.js.regexp", + "path": "./syntaxes/Regular Expressions (JavaScript).tmLanguage" + } + ], + "snippets": [ + { + "language": "javascript", + "path": "./snippets/javascript.json" + } + ], + "jsonValidation": [ + { + "fileMatch": "package.json", + "url": "http://json.schemastore.org/project" + }, + { + "fileMatch": "bower.json", + "url": "http://json.schemastore.org/bower" + }, + { + "fileMatch": ".bower.json", + "url": "http://json.schemastore.org/bower" + }, + { + "fileMatch": ".bowerrc", + "url": "http://json.schemastore.org/bowerrc" + }, + { + "fileMatch": "jsconfig.json", + "url": "./schemas/jsconfig.schema.json" + } + ] } } \ No newline at end of file diff --git a/extensions/javascript/schemas/jsconfig.schema.json b/extensions/javascript/schemas/jsconfig.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..ad1b317e7074bbe1fc7bee939234da7d6550f577 --- /dev/null +++ b/extensions/javascript/schemas/jsconfig.schema.json @@ -0,0 +1,79 @@ +{ + "title": "JSON schema for the JavaScript configuration file", + "type": "object", + "default": { + "compilerOptions": { + "target": "ES5" + } + }, + "properties": { + "compilerOptions": { + "type": "object", + "description": "Instructs the JavaScript language service how to validate .js files", + "properties": { + "charset": { + "description": "The character set of the input files", + "type": "string" + }, + "diagnostics": { + "description": "Show diagnostic information.", + "type": "boolean" + }, + "locale": { + "description": "The locale to use to show error messages, e.g. en-us.", + "type": "string" + }, + "mapRoot": { + "description": "Specifies the location where debugger should locate map files instead of generated locations", + "type": "string", + "format": "uri" + }, + "module": { + "description": "Module code generation to resolve against: 'commonjs', 'amd', 'system', or 'umd'.", + "enum": [ + "commonjs", + "amd", + "system", + "umd" + ] + }, + "noLib": { + "description": "Do not include the default library file (lib.d.ts).", + "type": "boolean" + }, + "target": { + "description": "Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES6' (experimental).", + "enum": [ + "ES3", + "ES5", + "ES6", + "es3", + "es5", + "es6" + ], + "default": "ES3" + }, + "experimentalDecorators": { + "description": "Enables experimental support for ES7 decorators.", + "type": "boolean" + } + } + }, + "files": { + "type": "array", + "description": "If no 'files' property is present in a jsconfig.json, the language service defaults to including all files the containing directory and subdirectories. When a 'files' property is specified, only those files are included.", + "items": { + "type": "string", + "format": "uri" + } + }, + "exclude": { + "type": "array", + "description": "List files and folders that should not be included. This property is not honored when the 'files' property is present.", + "items": { + "type": "string", + "format": "uri" + } + } + } +} \ No newline at end of file diff --git a/extensions/json/package.json b/extensions/json/package.json index 224e446f8a02898131a832e11d6b423876809079..0ba31d875a6f04f33a1989624fccee8a3a7f23f5 100644 --- a/extensions/json/package.json +++ b/extensions/json/package.json @@ -2,18 +2,41 @@ "name": "json", "version": "0.1.0", "publisher": "vscode", - "engines": { "vscode": "*" }, + "engines": { + "vscode": "*" + }, "contributes": { - "languages": [{ - "id": "json", - "aliases": ["JSON", "json"], - "extensions": [".json", ".bowerrc", ".jshintrc", ".jscsrc", ".eslintrc"], - "mimetypes": ["application/json"] - }], - "grammars": [{ - "language": "json", - "scopeName": "source.json", - "path": "./syntaxes/JSON.tmLanguage" - }] + "languages": [ + { + "id": "json", + "aliases": [ + "JSON", + "json" + ], + "extensions": [ + ".json", + ".bowerrc", + ".jshintrc", + ".jscsrc", + ".eslintrc" + ], + "mimetypes": [ + "application/json" + ] + } + ], + "grammars": [ + { + "language": "json", + "scopeName": "source.json", + "path": "./syntaxes/JSON.tmLanguage" + } + ], + "jsonValidation": [ + { + "fileMatch": "*.schema.json", + "url": "http://json-schema.org/draft-04/schema#" + } + ] } } \ No newline at end of file diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index 962e0a13f4d6aaabed81fc535099f11b96d61710..162ac035bd2c5db126dc475afa7ec6a62c9f2e88 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -101,6 +101,12 @@ "language": "typescriptreact", "path": "./snippets/typescriptreact.json" } + ], + "jsonValidation": [ + { + "fileMatch": "tsconfig.json", + "url": "http://json.schemastore.org/tsconfig" + } ] } } \ No newline at end of file diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 8b08c4d543e171b5d8a5f0c0dbf07c431177f34b..7d053110f7c833f3cd1f6de486414115de144262 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -416,9 +416,9 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz" }, "vscode-debugprotocol": { - "version": "1.0.0", - "from": "vscode-debugprotocol@1.0.0", - "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.0.0.tgz" + "version": "1.0.1", + "from": "vscode-debugprotocol@>=1.0.1", + "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.0.1.tgz" }, "vscode-textmate": { "version": "1.0.9", diff --git a/product.json b/product.json index e17a8d3020e676c037ccbcb5bdc7ec092a2f3a09..aafbf1db2da183ab6df6a8da23b93f3b41a6fbe3 100644 --- a/product.json +++ b/product.json @@ -2,10 +2,11 @@ "nameShort": "Code [OSS Build]", "nameLong": "Code [OSS Build]", "win32ExeBasename": "CodeOSS", + "win32MutexName": "vscodeoss", "companyName": "Microsoft Corporation", "copyright": "Copyright (C) 2015 Microsoft. All rights reserved", "licenseUrl": "https://github.com/Microsoft/vscode/blob/master/LICENSE.txt", - "darwinBundleIdentifier": "code.visualstudio.com.Code", + "darwinBundleIdentifier": "com.visualstudio.code.oss", "darwinApplicationCategoryType": "public.app-category.developer-tools", "darwinBundleDocumentTypes": [{ "name": "Code OSS Build document", diff --git a/src/vs/base/common/OSSREADME.json b/src/vs/base/common/OSSREADME.json new file mode 100644 index 0000000000000000000000000000000000000000..8d5e021bf26a75e342adada5cc42013c8b3f6038 --- /dev/null +++ b/src/vs/base/common/OSSREADME.json @@ -0,0 +1,8 @@ +// ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS: +[{ + "name": "string_scorer", + "version": "10 March 2015", + "license": "MIT License", + "repositoryURL": "https://github.com/joshaven/string_score", + "description": "The file scorer.ts was inspired by the string_score algorithm from Joshaven Potter." +}] diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index d1aaaba325940ac07a6d71354841d74816317e94..2e627a9ace3c0a7983c1f32964ca219fd349c75c 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -251,12 +251,7 @@ const fuzzyContiguousFilter = or(matchesPrefix, matchesCamelCase, matchesContigu const fuzzySeparateFilter = or(matchesPrefix, matchesCamelCase, matchesSubString); const fuzzyRegExpCache: { [key: string]: RegExp; } = {}; -let defaultFuzzyMatching = SubstringMatching.Contiguous; -export function setDefaultFuzzyMatching(matcher: SubstringMatching): void { - defaultFuzzyMatching = matcher; -} - -export function matchesFuzzy(word: string, wordToMatchAgainst: string, matcher = defaultFuzzyMatching): IMatch[] { +export function matchesFuzzy(word: string, wordToMatchAgainst: string, enableSeparateSubstringMatching = false): IMatch[] { // Form RegExp for wildcard matches let regexp = fuzzyRegExpCache[word]; @@ -272,5 +267,5 @@ export function matchesFuzzy(word: string, wordToMatchAgainst: string, matcher = } // Default Filter - return matcher === SubstringMatching.Contiguous ? fuzzyContiguousFilter(word, wordToMatchAgainst) : fuzzySeparateFilter(word, wordToMatchAgainst); + return enableSeparateSubstringMatching ? fuzzySeparateFilter(word, wordToMatchAgainst) : fuzzyContiguousFilter(word, wordToMatchAgainst); } diff --git a/src/vs/base/common/scorer.ts b/src/vs/base/common/scorer.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c6435fddbd856735e3c839643fa8bd36dd6d937 --- /dev/null +++ b/src/vs/base/common/scorer.ts @@ -0,0 +1,85 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +// Based on material from: + +/*! +* string_score.js: String Scoring Algorithm 0.1.22 +* +* http://joshaven.com/string_score +* https://github.com/joshaven/string_score +* +* Copyright (C) 2009-2014 Joshaven Potter +* Special thanks to all of the contributors listed here https://github.com/joshaven/string_score +* MIT License: http://opensource.org/licenses/MIT +* +* Date: Tue Mar 1 2011 +* Updated: Tue Mar 10 2015 +*/ + +/** + * Compute a score for the given string and the given query. + * + * Rules: + * Character score: 1 + * Same case bonus: 1 + * Upper case bonus: 1 + * Start of word/path bonus: 7 + * Start of string bonus: 8 + */ +export function score(target: string, query: string): number { + let score = 0; + + if (!target || !query) { + return score; // return early if target or query are undefined + } + + const queryLen = query.length; + const targetLower = target.toLowerCase(); + const queryLower = query.toLowerCase(); + const wordPathBoundary = ['-', '_', ' ', '/', '\\']; + + let index = 0; + while (index < queryLen) { + var indexOf = targetLower.indexOf(queryLower[index]); + if (indexOf < 0) { + index++; + continue; // no match + } + + // Character Match Bonus + score += 1; + + // Same Case Bonous + if (target[indexOf] === query[indexOf]) { + score += 1; + } + + // Upper Case Bonus + if (isUpper(target.charCodeAt(indexOf))) { + score += 1; + } + + // Prefix Bonus + if (indexOf === 0) { + score += 8; + } + + // Start of Word/Path Bonous + if (wordPathBoundary.some(w => w === target[indexOf - 1])) { + score += 7; + } + + index++; + } + + return score; +} + +function isUpper(code: number): boolean { + return 65 <= code && code <= 90; +} \ No newline at end of file diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 2ad45d3c521447c4cc644415b8df85f782c09537..c1f672641d948b1f769875faf4f042d7f2bd4cf0 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -604,4 +604,4 @@ export var UTF8_BOM_CHARACTER = String.fromCharCode(__utf8_bom); export function startsWithUTF8BOM(str: string): boolean { return (str && str.length > 0 && str.charCodeAt(0) === __utf8_bom); -} +} \ No newline at end of file diff --git a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts index 9ae9befd9ab71d68014155efe7db439715efd8f2..dab1493701db011b6d70e931be08e1384e44066f 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts @@ -134,7 +134,8 @@ export class QuickOpenEntry { } /** - * A good default sort implementation for quick open entries + * A good default sort implementation for quick open entries respecting highlight information + * as well as associated resources. */ public static compare(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string): number { @@ -153,7 +154,7 @@ export class QuickOpenEntry { return 1; } - // Sort by name/path + // Fallback to the full path if labels are identical and we have associated resources let nameA = elementA.getLabel(); let nameB = elementB.getLabel(); if (nameA === nameB) { @@ -169,20 +170,24 @@ export class QuickOpenEntry { return compareAnything(nameA, nameB, lookFor); } - public static highlight(entry: QuickOpenEntry, lookFor: string): { labelHighlights: IHighlight[], descriptionHighlights: IHighlight[] } { + /** + * A good default highlight implementation for an entry with label and description. + */ + public static highlight(entry: QuickOpenEntry, lookFor: string, fuzzyHighlight = false): { labelHighlights: IHighlight[], descriptionHighlights: IHighlight[] } { let labelHighlights: IHighlight[] = []; let descriptionHighlights: IHighlight[] = []; // Highlight file aware if (entry.getResource()) { - // Highlight only inside label - if (lookFor.indexOf(Paths.nativeSep) < 0) { - labelHighlights = Filters.matchesFuzzy(lookFor, entry.getLabel()); + // Fuzzy: Highlight in label and description + if (fuzzyHighlight) { + labelHighlights = Filters.matchesFuzzy(lookFor, entry.getLabel(), true); + descriptionHighlights = Filters.matchesFuzzy(lookFor, entry.getDescription(), true); } - // Highlight in label and description - else { + // Path search: Highlight in label and description + else if (lookFor.indexOf(Paths.nativeSep) >= 0) { descriptionHighlights = Filters.matchesFuzzy(Strings.trim(lookFor, Paths.nativeSep), entry.getDescription()); // If we have no highlights, assume that the match is split among name and parent folder @@ -191,6 +196,11 @@ export class QuickOpenEntry { descriptionHighlights = Filters.matchesFuzzy(Strings.trim(Paths.dirname(lookFor), Paths.nativeSep), entry.getDescription()); } } + + // Highlight only inside label + else { + labelHighlights = Filters.matchesFuzzy(lookFor, entry.getLabel()); + } } // Highlight by label otherwise diff --git a/src/vs/base/test/common/scorer.test.ts b/src/vs/base/test/common/scorer.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6de190abcbaeca9228396b698556860cdfbd8598 --- /dev/null +++ b/src/vs/base/test/common/scorer.test.ts @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * 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 * as assert from 'assert'; +import scorer = require('vs/base/common/scorer'); + +suite('Scorer', () => { + + test("score", function() { + const target = 'HelLo-World'; + + const scores = []; + scores.push(scorer.score(target, 'HelLo-World')); // direct case match + scores.push(scorer.score(target, 'hello-world')); // direct mix-case match + scores.push(scorer.score(target, 'HW')); // direct case prefix (multiple) + scores.push(scorer.score(target, 'H')); // direct case prefix + scores.push(scorer.score(target, 'hw')); // direct mix-case prefix (multiple) + scores.push(scorer.score(target, 'h')); // direct mix-case prefix + scores.push(scorer.score(target, 'W')); // direct case word prefix + scores.push(scorer.score(target, 'w')); // direct mix-case word prefix + scores.push(scorer.score(target, 'Ld')); // in-string case match (multiple) + scores.push(scorer.score(target, 'L')); // in-string case match + scores.push(scorer.score(target, 'ld')); // in-string mix-case match + scores.push(scorer.score(target, 'l')); // in-string mix-case match + scores.push(scorer.score(target, '4')); // no match + + // Assert scoring order + let sortedScores = scores.sort(); + assert.deepEqual(scores.reverse(), sortedScores); + }); +}); \ No newline at end of file diff --git a/src/vs/editor/browser/standalone/standaloneSchemas.ts b/src/vs/editor/browser/standalone/standaloneSchemas.ts index f4e85fa5d3421e89dd4fc3813c7efa81bb8d9def..a6a47ac159daa03ee1c1844826cc8a16ad4b1fb6 100644 --- a/src/vs/editor/browser/standalone/standaloneSchemas.ts +++ b/src/vs/editor/browser/standalone/standaloneSchemas.ts @@ -1015,7 +1015,7 @@ MonacoEditorSchemas['http://json.schemastore.org/tsconfig'] = { MonacoEditorSchemas['http://opentools.azurewebsites.net/jsconfig'] = { 'title': nls.localize('jsconfig.json.title', "JSON schema for the JavaScript configuration file"), 'type': 'object', - 'default': { 'compilerOptions': { 'target': 'ES5' } }, + 'default': { 'compilerOptions': { 'target': 'ES6' } }, 'properties': { 'compilerOptions': { 'type': 'object', diff --git a/src/vs/editor/common/controller/oneCursor.ts b/src/vs/editor/common/controller/oneCursor.ts index b41eac7fbee11d7fde9992c568f65eb59c50e595..4ca3774e40167e4ba1415dca9173e360c9909183 100644 --- a/src/vs/editor/common/controller/oneCursor.ts +++ b/src/vs/editor/common/controller/oneCursor.ts @@ -492,23 +492,25 @@ export class OneCursorOp { // -------------------- START handlers that simply change cursor state public static jumpToBracket(cursor:OneCursor, ctx: IOneCursorOperationContext): boolean { - var bracketDecorations = cursor.getBracketsDecorations(); - var len = bracketDecorations.length; + let bracketDecorations = cursor.getBracketsDecorations(); - if (len !== 2) { + if (bracketDecorations.length !== 2) { return false; } - var position = cursor.getPosition(); + let firstBracket = cursor.model.getDecorationRange(bracketDecorations[0]); + let secondBracket = cursor.model.getDecorationRange(bracketDecorations[1]); - for (var i = 0; i < 2; i++) { - var range = cursor.model.getDecorationRange(bracketDecorations[i]); - var otherRange = cursor.model.getDecorationRange(bracketDecorations[1 - i]); + let position = cursor.getPosition(); - if (Utils.isPositionAtRangeEdges(position, range) || Utils.isPositionInsideRange(position, range)) { - cursor.moveModelPosition(false, otherRange.startLineNumber, otherRange.startColumn, 0, false); - return true; - } + if (Utils.isPositionAtRangeEdges(position, firstBracket) || Utils.isPositionInsideRange(position, firstBracket)) { + cursor.moveModelPosition(false, secondBracket.endLineNumber, secondBracket.endColumn, 0, false); + return true; + } + + if (Utils.isPositionAtRangeEdges(position, secondBracket) || Utils.isPositionInsideRange(position, secondBracket)) { + cursor.moveModelPosition(false, firstBracket.endLineNumber, firstBracket.endColumn, 0, false); + return true; } return false; diff --git a/src/vs/editor/common/modes/textToHtmlTokenizer.ts b/src/vs/editor/common/modes/textToHtmlTokenizer.ts index f2d8cf44d80c824482ac710b2ffea91ae68cd618..0261c1fbe163846a7df80791f6e37c976105793b 100644 --- a/src/vs/editor/common/modes/textToHtmlTokenizer.ts +++ b/src/vs/editor/common/modes/textToHtmlTokenizer.ts @@ -31,7 +31,7 @@ function _getSafeTokenizationSupport(mode: Modes.IMode): Modes.ITokenizationSupp function _tokenizeToHtmlContent(text: string, tokenizationSupport: Modes.ITokenizationSupport): IHTMLContentElement { var result: IHTMLContentElement = { tagName: 'div', - style: 'white-space: pre', + style: 'white-space: pre-wrap', children: [] }; diff --git a/src/vs/editor/test/common/controller/cursor.test.ts b/src/vs/editor/test/common/controller/cursor.test.ts index 77cad786f5535b10864451de896b4df11dede0f4..490fd0663f40790229a9ca6f5eda4e59457ea247 100644 --- a/src/vs/editor/test/common/controller/cursor.test.ts +++ b/src/vs/editor/test/common/controller/cursor.test.ts @@ -814,6 +814,31 @@ suite('Editor Controller - Cursor Configuration', () => { var thisHighlighter = new ModelModes.CursorMode(); + test('issue #183: jump to matching bracket position', () => { + let mode = new ModelModes.BracketMode(); + let model = new Model.Model([ + 'var x = (3 + (5-7));' + ].join('\n'), mode); + let cursor = new Cursor.Cursor(1, new MockConfiguration(null), model, null, false); + + // ensure is tokenized + model.getLineContext(1); + + moveTo(cursor, 1, 20); + + cursorCommand(cursor, H.JumpToBracket, null, null, 'keyboard'); + cursorEqual(cursor, 1, 10); + + cursorCommand(cursor, H.JumpToBracket, null, null, 'keyboard'); + cursorEqual(cursor, 1, 20); + + cursorCommand(cursor, H.JumpToBracket, null, null, 'keyboard'); + cursorEqual(cursor, 1, 10); + + cursor.dispose(); + model.dispose(); + }); + test('Cursor honors insertSpaces configuration on new line', () => { var text = ' \tMy First Line\t \n' + '\tMy Second Line\n' + ' Third Line\n' + '\n' + '1'; var model = new Model.Model(text, thisHighlighter); diff --git a/src/vs/languages/typescript/common/project/projectService.ts b/src/vs/languages/typescript/common/project/projectService.ts index d98593d8b665c74d3ec4c10df952811b0a5af6de..4c9e3443e9e2c5063c78b81b9d608233947c6320 100644 --- a/src/vs/languages/typescript/common/project/projectService.ts +++ b/src/vs/languages/typescript/common/project/projectService.ts @@ -113,6 +113,7 @@ export class LanguageServiceHost implements ts.LanguageServiceHost { this._compilerOptions = options || ts.getDefaultCompilerOptions(); this._compilerOptions.allowNonTsExtensions = true; // because of JS* and mirror model we need this this._compilerOptions.module = ts.ModuleKind.CommonJS; // because of JS* + this._compilerOptions.target = options && options.target !== undefined ? options.target : ts.ScriptTarget.Latest; // because of JS* } getCompilationSettings(): ts.CompilerOptions { diff --git a/src/vs/platform/jsonschemas/common/jsonValidationExtensionPoint.ts b/src/vs/platform/jsonschemas/common/jsonValidationExtensionPoint.ts index 2656753177f0b1989742cf51f78fe400dc8e3208..65934eaf5d406d75f847773df363761cc8f3292e 100644 --- a/src/vs/platform/jsonschemas/common/jsonValidationExtensionPoint.ts +++ b/src/vs/platform/jsonschemas/common/jsonValidationExtensionPoint.ts @@ -71,7 +71,11 @@ export class JSONValidationExtensionPoint { collector.error(nls.localize('invalid.url.schema', "'configuration.jsonValidation.url' must start with 'http:', 'https:' or './' to reference schemas located in the extension")); return; } - schemaRegistry.addSchemaFileAssociation(extension.fileMatch, uri); + var fileMatch = extension.fileMatch; + if (!strings.startsWith(extension.fileMatch, '/')) { + fileMatch = '/' + fileMatch; + } + schemaRegistry.addSchemaFileAssociation(fileMatch, uri); }); } }); diff --git a/src/vs/platform/search/common/search.ts b/src/vs/platform/search/common/search.ts index 3dd44ffc0df8a7b3e47fb2010a83b8b50e006961..f4005e8a4cad21872c178daacd83598bcd9076ae 100644 --- a/src/vs/platform/search/common/search.ts +++ b/src/vs/platform/search/common/search.ts @@ -28,6 +28,7 @@ export interface IQueryOptions { includePattern?: glob.IExpression; maxResults?: number; fileEncoding?: string; + matchFuzzy?: boolean; } export interface ISearchQuery extends IQueryOptions { @@ -91,5 +92,6 @@ export class LineMatch implements ILineMatch { export interface ISearchConfiguration extends IFilesConfiguration { search: { exclude: glob.IExpression; + fuzzyFilePicker: boolean; }; } \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 026883bd5826ca8ba060c61d83b3985812de86ea..34124b92610843bc0673bfe33df785abc3558f33 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -38,7 +38,7 @@ import {IEventService} from 'vs/platform/event/common/event'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {IMessageService, Severity} from 'vs/platform/message/common/message'; import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; -import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; +import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService'; import {IKeybindingService, IKeybindingContextKey} from 'vs/platform/keybinding/common/keybindingService'; const ID = 'workbench.component.quickopen'; diff --git a/src/vs/workbench/electron-main/menus.ts b/src/vs/workbench/electron-main/menus.ts index f7814f9f4e6922e38e16c211910df9d0f9430037..a9409a0e4df2820f48e8ca1029b25cd76b7b3450 100644 --- a/src/vs/workbench/electron-main/menus.ts +++ b/src/vs/workbench/electron-main/menus.ts @@ -253,10 +253,10 @@ export class VSCodeMenu { let mru = this.getOpenedPathsList(); if (isFile || platform.isMacintosh /* on mac we don't treat files any different from folders */) { mru.files.unshift(path); - mru.files = arrays.distinct(mru.files); + mru.files = arrays.distinct(mru.files, (f) => platform.isLinux ? f : f.toLowerCase()); } else { mru.folders.unshift(path); - mru.folders = arrays.distinct(mru.folders); + mru.folders = arrays.distinct(mru.folders, (f) => platform.isLinux ? f : f.toLowerCase()); } // Make sure its bounded diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.css b/src/vs/workbench/parts/extensions/electron-browser/extensions.css index ac981ecc570e17a3084a5d59c1ae44f5fd50b109..387f69654a6f7d769108d95cc5e24825966786a1 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.css @@ -123,7 +123,8 @@ /* Status bar */ .monaco-shell .extensions-statusbar { - cursor: pointer; + padding: 0 5px 0 5px; + line-height: 22px; } .monaco-shell .extensions-statusbar.warning::before { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts index 8d8baa625471b255ebefece62aa1ca9fdc94feb4..d90153e2ff3d83582fc7e1dbb4ce8928dcac637d 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWidgets.ts @@ -35,7 +35,7 @@ export class ExtensionsStatusbarItem implements statusbar.IStatusbarItem { } public render(container: HTMLElement): lifecycle.IDisposable { - this.domNode = dom.append(container, $('.extensions-statusbar octicon octicon-package')); + this.domNode = dom.append(container, $('a.extensions-statusbar octicon octicon-package')); this.domNode.title = nls.localize('extensions', "Extensions"), this.toDispose.push(dom.addDisposableListener(this.domNode, 'click', () => { this.quickOpenService.show('>extensions: ').done(null, errors.onUnexpectedError); diff --git a/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts b/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts index 9d69c986e25a9c2f73c3d2340d5cf50714093c78..82d84312b492aded85c655ef71611a75fe53e357 100644 --- a/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts @@ -32,13 +32,14 @@ import {KeybindingsUtils} from 'vs/platform/keybinding/common/keybindingsUtils'; import {IQuickOpenService} from 'vs/workbench/services/quickopen/browser/quickOpenService'; import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; -const ACTION_ID = 'workbench.action.showCommands'; -const ACTION_LABEL = nls.localize('showTriggerActions', "Show All Commands"); -const ALL_COMMANDS_PREFIX = '>'; -const EDITOR_COMMANDS_PREFIX = '$'; +export const ALL_COMMANDS_PREFIX = '>'; +export const EDITOR_COMMANDS_PREFIX = '$'; export class ShowAllCommandsAction extends QuickOpenAction { + public static ID = 'workbench.action.showCommands'; + public static LABEL = nls.localize('showTriggerActions', "Show All Commands"); + constructor(actionId: string, actionLabel: string, @IQuickOpenService quickOpenService: IQuickOpenService) { super(actionId, actionLabel, ALL_COMMANDS_PREFIX, quickOpenService); } @@ -320,7 +321,6 @@ export class CommandsHandler extends QuickOpenHandler { public getEmptyLabel(searchString: string): string { return nls.localize('noCommandsMatching', "No commands matching"); } - } export class EditorCommandsHandler extends CommandsHandler { @@ -358,21 +358,4 @@ export class QuickCommandsEditorAction extends EditorAction { return super.run(); } -} - -// Register Action -let registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllCommandsAction, ACTION_ID, ACTION_LABEL, { - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_P, - secondary: [KeyCode.F1] -})); - -// Register Quick Open Handler -(Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/quickopen/browser/commandsHandler', - 'CommandsHandler', - ALL_COMMANDS_PREFIX, - nls.localize('commandsHandlerDescriptionDefault', "Show and Run Commands") - ) -); \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.ts b/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.ts index 7ad4536fae5f0c240a18bad154900d9c5d8139e1..17665c205449d17d28175aca4602bfb8e31427e6 100644 --- a/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.ts @@ -24,11 +24,13 @@ import {Position} from 'vs/platform/editor/common/editor'; import {IQuickOpenService} from 'vs/workbench/services/quickopen/browser/quickOpenService'; import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; -const ACTION_ID = 'workbench.action.gotoLine'; -const ACTION_LABEL = nls.localize('gotoLine', "Go to Line..."); -const GOTO_LINE_PREFIX = ':'; +export const GOTO_LINE_PREFIX = ':'; export class GotoLineAction extends QuickOpenAction { + + public static ID = 'workbench.action.gotoLine'; + public static LABEL = nls.localize('gotoLine', "Go to Line..."); + constructor(actionId: string, actionLabel: string, @IQuickOpenService quickOpenService: IQuickOpenService) { super(actionId, actionLabel, GOTO_LINE_PREFIX, quickOpenService); } @@ -281,27 +283,4 @@ export class GotoLineHandler extends QuickOpenHandler { autoFocusFirstEntry: searchValue.trim().length > 0 }; } -} - -// Register Action -let registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(GotoLineAction, ACTION_ID, ACTION_LABEL, { - primary: KeyMod.CtrlCmd | KeyCode.KEY_G, - mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_G } -})); - -// Register Quick Open Handler -(Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/quickopen/browser/gotoLineHandler', - 'GotoLineHandler', - GOTO_LINE_PREFIX, - [ - { - prefix: GOTO_LINE_PREFIX, - needsEditor: true, - description: env.isMacintosh ? nls.localize('gotoLineDescriptionMac', "Go to Line") : nls.localize('gotoLineDescriptionWin', "Go to Line") - }, - ] - ) -); \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts b/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts index aa7743ebfdb9d905022cd75d56c1a07ed202935a..265488010508b92584d8d01cca1aa7b10e4a766e 100644 --- a/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.ts @@ -33,13 +33,14 @@ import {Position} from 'vs/platform/editor/common/editor'; import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; import {OutlineRegistry, getOutlineEntries} from 'vs/editor/contrib/quickOpen/common/quickOpen'; -const ACTION_ID = 'workbench.action.gotoSymbol'; -const ACTION_LABEL = nls.localize('gotoSymbol', "Go to Symbol..."); - -const GOTO_SYMBOL_PREFIX = '@'; -const SCOPE_PREFIX = ':'; +export const GOTO_SYMBOL_PREFIX = '@'; +export const SCOPE_PREFIX = ':'; export class GotoSymbolAction extends QuickOpenAction { + + public static ID = 'workbench.action.gotoSymbol'; + public static LABEL = nls.localize('gotoSymbol', "Go to Symbol..."); + constructor(actionId: string, actionLabel: string, @IQuickOpenService quickOpenService: IQuickOpenService) { super(actionId, actionLabel, GOTO_SYMBOL_PREFIX, quickOpenService); } @@ -432,7 +433,7 @@ export class GotoSymbolHandler extends QuickOpenHandler { if (model && types.isFunction((model).getMode)) { - canRun = OutlineRegistry.has( model); + canRun = OutlineRegistry.has(model); } } @@ -527,7 +528,7 @@ export class GotoSymbolHandler extends QuickOpenHandler { return TPromise.as(this.outlineToModelCache[modelId]); } - return getOutlineEntries( model).then(outline => { + return getOutlineEntries(model).then(outline => { let model = new OutlineModel(outline, this.toQuickOpenEntries(outline)); @@ -627,29 +628,4 @@ export class GotoSymbolHandler extends QuickOpenHandler { this.lastKnownEditorViewState = null; this.activeOutlineRequest = null; } -} - -// Register Action -let registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(GotoSymbolAction, ACTION_ID, ACTION_LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_O })); - -// Register Quick Outline Handler -(Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/quickopen/browser/gotoSymbolHandler', - 'GotoSymbolHandler', - GOTO_SYMBOL_PREFIX, - [ - { - prefix: GOTO_SYMBOL_PREFIX, - needsEditor: true, - description: env.isMacintosh ? nls.localize('gotoSymbolDescriptionNormalMac', "Go to Symbol") : nls.localize('gotoSymbolDescriptionNormalWin', "Go to Symbol") - }, - { - prefix: GOTO_SYMBOL_PREFIX + SCOPE_PREFIX, - needsEditor: true, - description: nls.localize('gotoSymbolDescriptionScoped', "Go to Symbol by Category") - } - ] - ) -); \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/workbench/parts/quickopen/browser/helpHandler.ts b/src/vs/workbench/parts/quickopen/browser/helpHandler.ts index 4cd1b9b87bdd70b6a0ce4f29c1e8feae91353e08..cd0e4c8f1ad03b0127df562329c912919b279913 100644 --- a/src/vs/workbench/parts/quickopen/browser/helpHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/helpHandler.ts @@ -15,7 +15,7 @@ import {ITree, IElementCallback} from 'vs/base/parts/tree/common/tree'; import {QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions, QuickOpenHandler} from 'vs/workbench/browser/quickopen'; import {IQuickOpenService} from 'vs/workbench/services/quickopen/browser/quickOpenService'; -const HELP_PREFIX = '?'; +export const HELP_PREFIX = '?'; class HelpEntry extends QuickOpenEntryItem { private prefix: string; @@ -182,14 +182,4 @@ export class HelpHandler extends QuickOpenHandler { autoFocusPrefixMatch: searchValue }; } -} - -// Register Quick Open Handler -(Registry.as(Extensions.Quickopen)).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/quickopen/browser/helpHandler', - 'HelpHandler', - HELP_PREFIX, - nls.localize('helpDescription', "Show Help") - ) -); \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/workbench/parts/quickopen/browser/markersHandler.ts b/src/vs/workbench/parts/quickopen/browser/markersHandler.ts index 2f007cc8d825fbf5b4198eb90cbce3f634bf9fc9..7b266cfaf31016cc4bd473277f03fdc98b1faa58 100644 --- a/src/vs/workbench/parts/quickopen/browser/markersHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/markersHandler.ts @@ -67,9 +67,8 @@ class MarkerEntry extends QuickOpenEntryItem { return null; } - public run(mode:Mode, context:IContext):boolean { - - if(mode !== Mode.OPEN) { + public run(mode: Mode, context: IContext): boolean { + if (mode !== Mode.OPEN) { return false; } @@ -107,7 +106,7 @@ export class MarkersHandler extends QuickOpenHandler { this._contextService = contextService; } - public getResults(searchValue:string):TPromise { + public getResults(searchValue: string): TPromise { searchValue = searchValue.trim(); let markers = this._markerService.read({ take: 500 }); @@ -121,7 +120,6 @@ export class MarkersHandler extends QuickOpenHandler { } private static _sort(a: IMarker, b: IMarker): number { - let ret: number; // 1st: severity matters first @@ -144,7 +142,7 @@ export class MarkersHandler extends QuickOpenHandler { // 4th: start column matters ret = a.startColumn - b.startColumn; - if(ret !== 0) { + if (ret !== 0) { return ret; } @@ -153,7 +151,7 @@ export class MarkersHandler extends QuickOpenHandler { private _filter(marker: IMarker, query: string): boolean { - if(marker.resource.scheme === network.schemas.inMemory) { + if (marker.resource.scheme === network.schemas.inMemory) { // ignore inmemory-models return false; } @@ -172,7 +170,7 @@ export class MarkersHandler extends QuickOpenHandler { return 'marker-handler'; } - public getAutoFocus(searchValue:string):IAutoFocus { + public getAutoFocus(searchValue: string): IAutoFocus { return { autoFocusFirstEntry: !!searchValue }; @@ -187,7 +185,7 @@ export class MarkersHandler extends QuickOpenHandler { } -class GotoMarkerAction extends QuickOpenAction { +export class GotoMarkerAction extends QuickOpenAction { static Prefix = '!'; static Id = 'workbench.action.showErrorsWarnings'; @@ -196,24 +194,4 @@ class GotoMarkerAction extends QuickOpenAction { constructor(actionId: string, actionLabel: string, @IQuickOpenService quickOpenService: IQuickOpenService) { super(actionId, actionLabel, GotoMarkerAction.Prefix, quickOpenService); } -} - -// Register Action -let registry = Registry.as(ActionExtensions.WorkbenchActions); -registry.registerWorkbenchAction(new SyncActionDescriptor(GotoMarkerAction, GotoMarkerAction.Id, GotoMarkerAction.Label, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_M })); - -// Register Quick Open Handler -(Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler( - new QuickOpenHandlerDescriptor( - 'vs/workbench/parts/quickopen/browser/markersHandler', - 'MarkersHandler', - GotoMarkerAction.Prefix, - [ - { - prefix: GotoMarkerAction.Prefix, - needsEditor: false, - description: env.isMacintosh ? nls.localize('desc.mac', "Show Errors or Warnings") : nls.localize('desc.win', "Show Errors and Warnings") - }, - ] - ) -); \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/workbench/parts/quickopen/browser/quickopen.contribution.ts b/src/vs/workbench/parts/quickopen/browser/quickopen.contribution.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d9e1440d6fc24e78f2526249b15e52cf79ef413 --- /dev/null +++ b/src/vs/workbench/parts/quickopen/browser/quickopen.contribution.ts @@ -0,0 +1,110 @@ +/*--------------------------------------------------------------------------------------------- + * 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 env = require('vs/base/common/platform'); +import nls = require('vs/nls'); +import {QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandler} from 'vs/workbench/browser/quickopen'; +import {Registry} from 'vs/platform/platform'; +import {SyncActionDescriptor} from 'vs/platform/actions/common/actions'; +import {IWorkbenchActionRegistry, Extensions as ActionExtensions} from 'vs/workbench/browser/actionRegistry'; +import {KeyMod, KeyCode} from 'vs/base/common/keyCodes'; +import {IConfigurationRegistry, Extensions as ConfigurationExtensions} from 'vs/platform/configuration/common/configurationRegistry'; +import {GotoSymbolHandler, GotoSymbolAction, GOTO_SYMBOL_PREFIX, SCOPE_PREFIX} from 'vs/workbench/parts/quickopen/browser/gotoSymbolHandler'; +import {CommandsHandler, ShowAllCommandsAction, ALL_COMMANDS_PREFIX} from 'vs/workbench/parts/quickopen/browser/commandsHandler'; +import {GotoLineAction, GotoLineHandler, GOTO_LINE_PREFIX} from 'vs/workbench/parts/quickopen/browser/gotoLineHandler'; +import {HelpHandler, HELP_PREFIX} from 'vs/workbench/parts/quickopen/browser/helpHandler'; +import {MarkersHandler, GotoMarkerAction} from 'vs/workbench/parts/quickopen/browser/markersHandler'; + +// Register Actions +let registry = Registry.as(ActionExtensions.WorkbenchActions); +registry.registerWorkbenchAction(new SyncActionDescriptor(GotoMarkerAction, GotoMarkerAction.Id, GotoMarkerAction.Label, { + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_M +})); + +registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAllCommandsAction, ShowAllCommandsAction.ID, ShowAllCommandsAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_P, + secondary: [KeyCode.F1] +})); + +registry.registerWorkbenchAction(new SyncActionDescriptor(GotoLineAction, GotoLineAction.ID, GotoLineAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.KEY_G, + mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_G } +})); + +registry.registerWorkbenchAction(new SyncActionDescriptor(GotoSymbolAction, GotoSymbolAction.ID, GotoSymbolAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_O +})); + +// Register Quick Open Handler + +(Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler( + new QuickOpenHandlerDescriptor( + 'vs/workbench/parts/quickopen/browser/markersHandler', + 'MarkersHandler', + GotoMarkerAction.Prefix, + [ + { + prefix: GotoMarkerAction.Prefix, + needsEditor: false, + description: env.isMacintosh ? nls.localize('desc.mac', "Show Errors or Warnings") : nls.localize('desc.win', "Show Errors and Warnings") + }, + ] + ) +); + +(Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler( + new QuickOpenHandlerDescriptor( + 'vs/workbench/parts/quickopen/browser/commandsHandler', + 'CommandsHandler', + ALL_COMMANDS_PREFIX, + nls.localize('commandsHandlerDescriptionDefault', "Show and Run Commands") + ) +); + +(Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler( + new QuickOpenHandlerDescriptor( + 'vs/workbench/parts/quickopen/browser/gotoLineHandler', + 'GotoLineHandler', + GOTO_LINE_PREFIX, + [ + { + prefix: GOTO_LINE_PREFIX, + needsEditor: true, + description: env.isMacintosh ? nls.localize('gotoLineDescriptionMac', "Go to Line") : nls.localize('gotoLineDescriptionWin', "Go to Line") + }, + ] + ) +); + +(Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler( + new QuickOpenHandlerDescriptor( + 'vs/workbench/parts/quickopen/browser/gotoSymbolHandler', + 'GotoSymbolHandler', + GOTO_SYMBOL_PREFIX, + [ + { + prefix: GOTO_SYMBOL_PREFIX, + needsEditor: true, + description: env.isMacintosh ? nls.localize('gotoSymbolDescriptionNormalMac', "Go to Symbol") : nls.localize('gotoSymbolDescriptionNormalWin', "Go to Symbol") + }, + { + prefix: GOTO_SYMBOL_PREFIX + SCOPE_PREFIX, + needsEditor: true, + description: nls.localize('gotoSymbolDescriptionScoped', "Go to Symbol by Category") + } + ] + ) +); + +(Registry.as(QuickOpenExtensions.Quickopen)).registerQuickOpenHandler( + new QuickOpenHandlerDescriptor( + 'vs/workbench/parts/quickopen/browser/helpHandler', + 'HelpHandler', + HELP_PREFIX, + nls.localize('helpDescription', "Show Help") + ) +); \ No newline at end of file diff --git a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts index 1e020c636e7ffd251bfdf1b66b9e46f0978b6ee6..51916d63169a181aa1d41d87ad5362ce24f74a5b 100644 --- a/src/vs/workbench/parts/search/browser/openAnythingHandler.ts +++ b/src/vs/workbench/parts/search/browser/openAnythingHandler.ts @@ -10,11 +10,12 @@ import nls = require('vs/nls'); import {ThrottledDelayer} from 'vs/base/common/async'; import types = require('vs/base/common/types'); import strings = require('vs/base/common/strings'); +import scorer = require('vs/base/common/scorer'); import paths = require('vs/base/common/paths'); import filters = require('vs/base/common/filters'); import labels = require('vs/base/common/labels'); import {IRange} from 'vs/editor/common/editorCommon'; -import {compareAnything} from 'vs/base/common/comparers'; +import {ListenerUnbind} from 'vs/base/common/eventEmitter'; import {IAutoFocus} from 'vs/base/parts/quickopen/browser/quickOpen'; import {QuickOpenEntry, QuickOpenModel} from 'vs/base/parts/quickopen/browser/quickOpenModel'; import {QuickOpenHandler} from 'vs/workbench/browser/quickopen'; @@ -22,7 +23,9 @@ import {FileEntry, OpenFileHandler} from 'vs/workbench/parts/search/browser/open import {OpenSymbolHandler as _OpenSymbolHandler} from 'vs/workbench/parts/search/browser/openSymbolHandler'; import {IMessageService, Severity} from 'vs/platform/message/common/message'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; -import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; +import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService'; +import {ISearchConfiguration} from 'vs/platform/search/common/search'; +import {IConfigurationService, IConfigurationServiceEvent, ConfigurationServiceEventTypes} from 'vs/platform/configuration/common/configuration'; // OpenSymbolHandler is used from an extension and must be in the main bundle file so it can load export const OpenSymbolHandler = _OpenSymbolHandler @@ -42,11 +45,14 @@ export class OpenAnythingHandler extends QuickOpenHandler { private delayer: ThrottledDelayer; private pendingSearch: TPromise; private isClosed: boolean; + private fuzzyMatchingEnabled: boolean; + private configurationListenerUnbind: ListenerUnbind; constructor( @IMessageService private messageService: IMessageService, @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IInstantiationService instantiationService: IInstantiationService + @IInstantiationService instantiationService: IInstantiationService, + @IConfigurationService private configurationService: IConfigurationService ) { super(); @@ -59,6 +65,19 @@ export class OpenAnythingHandler extends QuickOpenHandler { this.resultsToSearchCache = Object.create(null); this.delayer = new ThrottledDelayer(OpenAnythingHandler.SEARCH_DELAY); + + this.updateFuzzyMatching(contextService.getOptions().globalSettings.settings); + + this.registerListeners(); + } + + private registerListeners(): void { + this.configurationListenerUnbind = this.configurationService.addListener(ConfigurationServiceEventTypes.UPDATED, (e: IConfigurationServiceEvent) => this.updateFuzzyMatching(e.config)); + } + + private updateFuzzyMatching(configuration: ISearchConfiguration): void { + this.fuzzyMatchingEnabled = configuration.search && configuration.search.fuzzyFilePicker; + this.openFileHandler.setFuzzyMatchingEnabled(this.fuzzyMatchingEnabled); } public getResults(searchValue: string): TPromise { @@ -143,7 +162,7 @@ export class OpenAnythingHandler extends QuickOpenHandler { let result = [...results[0].entries, ...results[1].entries]; // Sort - result.sort((elementA, elementB) => QuickOpenEntry.compare(elementA, elementB, searchValue)); + result.sort((elementA, elementB) => this.sort(elementA, elementB, searchValue, this.fuzzyMatchingEnabled)); // Apply Range result.forEach((element) => { @@ -246,19 +265,19 @@ export class OpenAnythingHandler extends QuickOpenHandler { // Check if this entry is a match for the search value let targetToMatch = searchInPath ? labels.getPathLabel(entry.getResource(), this.contextService) : entry.getLabel(); - if (!filters.matchesFuzzy(searchValue, targetToMatch)) { + if (!filters.matchesFuzzy(searchValue, targetToMatch, this.fuzzyMatchingEnabled)) { continue; } // Apply highlights - const {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue); + const {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue, this.fuzzyMatchingEnabled); entry.setHighlights(labelHighlights, descriptionHighlights); results.push(entry); } // Sort - results.sort((elementA, elementB) => QuickOpenEntry.compare(elementA, elementB, searchValue)); + results.sort((elementA, elementB) => this.sort(elementA, elementB, searchValue, this.fuzzyMatchingEnabled)); // Apply Range results.forEach((element) => { @@ -270,6 +289,28 @@ export class OpenAnythingHandler extends QuickOpenHandler { return results; } + private sort(elementA: QuickOpenEntry, elementB: QuickOpenEntry, lookFor: string, enableFuzzyScoring): number { + + // Fuzzy scoring is special + if (enableFuzzyScoring) { + const labelAScore = scorer.score(elementA.getLabel(), lookFor); + const labelBScore = scorer.score(elementB.getLabel(), lookFor); + + if (labelAScore !== labelBScore) { + return labelAScore > labelBScore ? -1 : 1; + } + + const descriptionAScore = scorer.score(elementA.getDescription(), lookFor); + const descriptionBScore = scorer.score(elementB.getDescription(), lookFor); + + if (descriptionAScore !== descriptionBScore) { + return descriptionAScore > descriptionBScore ? -1 : 1; + } + } + + return QuickOpenEntry.compare(elementA, elementB, lookFor); + } + public getGroupLabel(): string { return nls.localize('fileAndTypeResults', "file and symbol results"); } diff --git a/src/vs/workbench/parts/search/browser/openFileHandler.ts b/src/vs/workbench/parts/search/browser/openFileHandler.ts index efce239a6700f26ec47b186626c9a72fa5a7d370..e89aa9a2cc8e545e8f1bb00e81de1876be09685b 100644 --- a/src/vs/workbench/parts/search/browser/openFileHandler.ts +++ b/src/vs/workbench/parts/search/browser/openFileHandler.ts @@ -89,6 +89,7 @@ export class OpenFileHandler extends QuickOpenHandler { private queryBuilder: QueryBuilder; private delayer: ThrottledDelayer; private isStandalone: boolean; + private fuzzyMatchingEnabled: boolean; constructor( @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @@ -111,6 +112,10 @@ export class OpenFileHandler extends QuickOpenHandler { this.isStandalone = standalone; } + public setFuzzyMatchingEnabled(enabled: boolean): void { + this.fuzzyMatchingEnabled = enabled; + } + public getResults(searchValue: string): TPromise { searchValue = searchValue.trim(); let promise: TPromise; @@ -133,7 +138,7 @@ export class OpenFileHandler extends QuickOpenHandler { rootResources.push(this.contextService.getWorkspace().resource); } - let query: IQueryOptions = { filePattern: searchValue, rootResources: rootResources }; + let query: IQueryOptions = { filePattern: searchValue, matchFuzzy: this.fuzzyMatchingEnabled, rootResources: rootResources }; return this.queryBuilder.file(query).then((query) => this.searchService.search(query)).then((complete) => { @@ -148,7 +153,7 @@ export class OpenFileHandler extends QuickOpenHandler { let entry = this.instantiationService.createInstance(FileEntry, label, description, fileMatch.resource); // Apply highlights - let {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue); + let {labelHighlights, descriptionHighlights} = QuickOpenEntry.highlight(entry, searchValue, this.fuzzyMatchingEnabled); entry.setHighlights(labelHighlights, descriptionHighlights); results.push(entry); diff --git a/src/vs/workbench/parts/search/browser/openSymbolHandler.ts b/src/vs/workbench/parts/search/browser/openSymbolHandler.ts index fe8dfb3f05cd229d236e5ba5f6812da6c124f649..f85fb379c5a1f8eda81700fff44d303cf76b3122 100644 --- a/src/vs/workbench/parts/search/browser/openSymbolHandler.ts +++ b/src/vs/workbench/parts/search/browser/openSymbolHandler.ts @@ -192,23 +192,19 @@ export class OpenSymbolHandler extends QuickOpenHandler { } private sort(searchValue: string, elementA: SymbolEntry, elementB: SymbolEntry): number { - let elementAName = elementA.getName().toLowerCase(); - let elementBName = elementB.getName().toLowerCase(); - - // Compare by name - let r = strings.localeCompare(elementAName, elementBName); - if (r !== 0) { - return r; - } // Sort by Type if name is identical - let elementAType = elementA.getType(); - let elementBType = elementB.getType(); - if (elementAType !== elementBType) { - return OpenSymbolHandler.SUPPORTED_OPEN_TYPES.indexOf(elementAType) < OpenSymbolHandler.SUPPORTED_OPEN_TYPES.indexOf(elementBType) ? -1 : 1; + let elementAName = elementA.getName().toLowerCase(); + let elementBName = elementB.getName().toLowerCase(); + if (elementAName === elementBName) { + let elementAType = elementA.getType(); + let elementBType = elementB.getType(); + if (elementAType !== elementBType) { + return OpenSymbolHandler.SUPPORTED_OPEN_TYPES.indexOf(elementAType) < OpenSymbolHandler.SUPPORTED_OPEN_TYPES.indexOf(elementBType) ? -1 : 1; + } } - return 0; // Keep default sorting order otherwise + return QuickOpenEntry.compare(elementA, elementB, searchValue); } public getGroupLabel(): string { diff --git a/src/vs/workbench/parts/search/browser/search.contribution.ts b/src/vs/workbench/parts/search/browser/search.contribution.ts index 8050b9ac646e048d77f5c7635d7897a0aaa04484..a30775cfa6118923a51d30e2b734860d7185fe6f 100644 --- a/src/vs/workbench/parts/search/browser/search.contribution.ts +++ b/src/vs/workbench/parts/search/browser/search.contribution.ts @@ -197,6 +197,11 @@ configurationRegistry.registerConfiguration({ } ] } + }, + 'search.fuzzyFilePicker': { + 'type': 'boolean', + 'default': false, + 'description': nls.localize('enableFuzzy', "Enable or disable fuzzy matching and sorting in the file picker.") } } }); \ No newline at end of file diff --git a/src/vs/workbench/parts/search/common/searchQuery.ts b/src/vs/workbench/parts/search/common/searchQuery.ts index 898d4b4b1b27f58f1649ce0821e82b45cf6c5392..34fcdad365016f03b7f2f81a0232d820b10b70a4 100644 --- a/src/vs/workbench/parts/search/common/searchQuery.ts +++ b/src/vs/workbench/parts/search/common/searchQuery.ts @@ -63,7 +63,8 @@ export class QueryBuilder { includePattern: options.includePattern, maxResults: options.maxResults, fileEncoding: options.fileEncoding, - contentPattern: contentPattern + contentPattern: contentPattern, + matchFuzzy: options.matchFuzzy }; }); } diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index d4dbfca86c350707a21e2e93e7bae7781aa599d3..e3b33e06612cd9fd7815a53863c651f20e1969e4 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -32,12 +32,14 @@ export class FileWalker { private resultCount: number; private isCanceled: boolean; private searchInPath: boolean; + private matchFuzzy: boolean; private walkedPaths: { [path: string]: boolean; }; constructor(config: IRawSearch) { this.config = config; this.filePattern = config.filePattern; + this.matchFuzzy = config.matchFuzzy; this.excludePattern = config.excludePattern; this.includePattern = config.includePattern; this.maxResults = config.maxResults || null; @@ -194,7 +196,7 @@ export class FileWalker { // Check for search pattern if (this.filePattern) { - const res = filters.matchesFuzzy(this.filePattern, this.searchInPath ? path : name); + const res = filters.matchesFuzzy(this.filePattern, this.matchFuzzy || this.searchInPath ? path : name, this.matchFuzzy); return !!res && res.length > 0; } diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index 35a1571bcb8e49c1d5b4c364eed592b9023f6749..6456612f3961a035a550c3da23a7b641f0d9ea87 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -19,6 +19,7 @@ import {Engine as TextSearchEngine} from 'vs/workbench/services/search/node/text export interface IRawSearch { rootPaths: string[]; filePattern?: string; + matchFuzzy?: boolean; excludePattern?: glob.IExpression; includePattern?: glob.IExpression; contentPattern?: IPatternInfo; diff --git a/src/vs/workbench/services/search/node/searchService.ts b/src/vs/workbench/services/search/node/searchService.ts index 3a84c6fb5d26c7b57686bb548ac3e817a4010b96..f275d0ee294cbdb6d027d552a668783a528a1c2f 100644 --- a/src/vs/workbench/services/search/node/searchService.ts +++ b/src/vs/workbench/services/search/node/searchService.ts @@ -223,7 +223,8 @@ class DiskSearch { filePattern: query.filePattern, excludePattern: query.excludePattern, includePattern: query.includePattern, - maxResults: query.maxResults + maxResults: query.maxResults, + matchFuzzy: query.matchFuzzy }; if (query.type === QueryType.Text) { diff --git a/src/vs/workbench/services/search/test/node/search.test.ts b/src/vs/workbench/services/search/test/node/search.test.ts index c84163ac872d9113bf66bc0f7c572cc776091b03..688d118e6f42298d5fa9fe45abedd33cba9e3d4a 100644 --- a/src/vs/workbench/services/search/test/node/search.test.ts +++ b/src/vs/workbench/services/search/test/node/search.test.ts @@ -66,6 +66,25 @@ suite('Search', () => { }); }); + test('Files: examples (fuzzy)', function(done: () => void) { + let engine = new FileSearchEngine({ + rootPaths: [require.toUrl('./fixtures')], + filePattern: 'xl', + matchFuzzy: true + }); + + let count = 0; + engine.search((result) => { + if (result) { + count++; + } + }, () => { }, (error) => { + assert.ok(!error); + assert.equal(count, 5); + done(); + }); + }); + test('Files: *.js (Files as roots)', function(done: () => void) { let engine = new FileSearchEngine({ rootPaths: [require.toUrl('./fixtures/examples/company.js'), require.toUrl('./fixtures/examples/small.js')], diff --git a/src/vs/workbench/test/browser/parts/quickOpen/quickopen.test.ts b/src/vs/workbench/test/browser/parts/quickOpen/quickopen.test.ts index d6f1a79f9a88fe90a233668f8e970896221b98ee..396dc0f4b876c75491bac6de08ba6db393e791fe 100644 --- a/src/vs/workbench/test/browser/parts/quickOpen/quickopen.test.ts +++ b/src/vs/workbench/test/browser/parts/quickOpen/quickopen.test.ts @@ -6,7 +6,7 @@ 'use strict'; import * as assert from 'assert'; -import {TestKeybindingService, TestContextService, TestStorageService, TestEventService, TestEditorService, TestQuickOpenService} from 'vs/workbench/test/browser/servicesTestUtils'; +import {TestKeybindingService, TestConfigurationService, TestContextService, TestStorageService, TestEventService, TestEditorService, TestQuickOpenService} from 'vs/workbench/test/browser/servicesTestUtils'; import {Registry} from 'vs/platform/platform'; import {EditorHistoryModel, EditorHistoryEntry} from 'vs/workbench/browser/parts/quickopen/editorHistoryModel'; import {QuickOpenHandlerDescriptor, IQuickOpenRegistry, Extensions as QuickOpenExtensions} from 'vs/workbench/browser/quickopen'; diff --git a/src/vs/workbench/test/browser/servicesTestUtils.ts b/src/vs/workbench/test/browser/servicesTestUtils.ts index c81b5136c65e252100e56fbbdd4ba64676c596a7..75c6e8324ec91b6c78bc992438e6f9519578ba40 100644 --- a/src/vs/workbench/test/browser/servicesTestUtils.ts +++ b/src/vs/workbench/test/browser/servicesTestUtils.ts @@ -27,6 +27,7 @@ import Severity from 'vs/base/common/severity'; import Arrays = require('vs/base/common/arrays'); import Errors = require('vs/base/common/errors'); import http = require('vs/base/common/http'); +import {IConfigurationService} from 'vs/platform/configuration/common/configuration'; import {IStorageService, StorageScope} from 'vs/platform/storage/common/storage'; import UntitledEditorService = require('vs/workbench/services/untitled/browser/untitledEditorService'); import WorkbenchEditorService = require('vs/workbench/services/editor/common/editorService'); @@ -71,7 +72,11 @@ export class TestContextService implements WorkspaceContextService.IWorkspaceCon constructor(workspace: any = TestWorkspace, configuration: any = TestConfiguration, options: any = null) { this.workspace = workspace; this.configuration = configuration; - this.options = options; + this.options = options || { + globalSettings: { + settings: {} + } + }; } public getWorkspace(): IWorkspace { @@ -466,7 +471,7 @@ export class TestQuickOpenService implements QuickOpenService.IQuickOpenService private callback: (prefix: string) => void; - constructor(callback: (prefix: string) => void) { + constructor(callback?: (prefix: string) => void) { this.callback = callback; } @@ -483,7 +488,7 @@ export class TestQuickOpenService implements QuickOpenService.IQuickOpenService } show(prefix?: string, quickNavigateConfiguration?: any): Promise { - this.callback(prefix); + this.callback && this.callback(prefix); return Promise.as(true); } @@ -530,4 +535,16 @@ export const TestFileService = { }; }); } +} + +export class TestConfigurationService extends EventEmitter.EventEmitter implements IConfigurationService { + public serviceId = IConfigurationService; + + public loadConfiguration(section?:string):TPromise { + return TPromise.as({}); + } + + public hasWorkspaceConfiguration():boolean { + return false; + } } \ No newline at end of file diff --git a/src/vs/workbench/workbench.main.js b/src/vs/workbench/workbench.main.js index fe1966590f6584176ccc8258dce6216b6097684b..4544520d105f5cdcca72e2502bc66dc0b853d221 100644 --- a/src/vs/workbench/workbench.main.js +++ b/src/vs/workbench/workbench.main.js @@ -32,11 +32,7 @@ define([ 'vs/workbench/browser/actions/showPerformanceBox', 'vs/workbench/browser/actions/openSettings', - 'vs/workbench/parts/quickopen/browser/gotoSymbolHandler', - 'vs/workbench/parts/quickopen/browser/commandsHandler', - 'vs/workbench/parts/quickopen/browser/gotoLineHandler', - 'vs/workbench/parts/quickopen/browser/helpHandler', - 'vs/workbench/parts/quickopen/browser/markersHandler', + 'vs/workbench/parts/quickopen/browser/quickopen.contribution', 'vs/workbench/parts/files/browser/explorerViewlet', 'vs/workbench/parts/files/browser/fileActions.contribution',