diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 061d09305f7..8df4cf8257b 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -284,6 +284,6 @@ gulp.task('upload-vscode-sourcemaps', ['minify-vscode'], () => { account: process.env.AZURE_STORAGE_ACCOUNT, key: process.env.AZURE_STORAGE_ACCESS_KEY, container: 'sourcemaps', - prefix: commit + '/core/' + prefix: commit + '/' })); }); diff --git a/extensions/css/client/src/colorDecorators.ts b/extensions/css/client/src/colorDecorators.ts index 90a0c28607d..b4135c6b5e0 100644 --- a/extensions/css/client/src/colorDecorators.ts +++ b/extensions/css/client/src/colorDecorators.ts @@ -6,6 +6,8 @@ import {window, workspace, DecorationOptions, DecorationRenderOptions, Disposable, Range, TextDocument, TextEditor} from 'vscode'; +const MAX_DECORATORS = 500; + let decorationType: DecorationRenderOptions = { before: { contentText: ' ', @@ -76,7 +78,7 @@ export function activateColorDecorations(decoratorProvider: (uri: string) => The let document = editor.document; if (supportedLanguages[document.languageId]) { decoratorProvider(document.uri.toString()).then(ranges => { - let decorations = ranges.map(range => { + let decorations = ranges.slice(0, MAX_DECORATORS).map(range => { let color = document.getText(range); return { range: range, diff --git a/extensions/git/git-commit.language-configuration.json b/extensions/git/git-commit.language-configuration.json index da6ed547150..b61fbe63d34 100644 --- a/extensions/git/git-commit.language-configuration.json +++ b/extensions/git/git-commit.language-configuration.json @@ -1,7 +1,7 @@ { "comments": { - "lineComment": "//", - "blockComment": [ "/*", "*/" ] + "lineComment": "#", + "blockComment": [ "#", " " ] }, "brackets": [ ["{", "}"], diff --git a/extensions/git/git-rebase.language-configuration.json b/extensions/git/git-rebase.language-configuration.json index da6ed547150..b61fbe63d34 100644 --- a/extensions/git/git-rebase.language-configuration.json +++ b/extensions/git/git-rebase.language-configuration.json @@ -1,7 +1,7 @@ { "comments": { - "lineComment": "//", - "blockComment": [ "/*", "*/" ] + "lineComment": "#", + "blockComment": [ "#", " " ] }, "brackets": [ ["{", "}"], diff --git a/extensions/html/package.json b/extensions/html/package.json index b126b1f8f48..29bfa7f950e 100644 --- a/extensions/html/package.json +++ b/extensions/html/package.json @@ -11,7 +11,6 @@ "mimetypes": ["text/html", "text/x-jshtm", "text/template", "text/ng-template", "application/xhtml+xml"] }], "grammars": [{ - /* "language": "html", not yet enabled*/ "scopeName": "text.html.basic", "path": "./syntaxes/HTML.plist" }] diff --git a/extensions/theme-seti/build/update-icon-theme.js b/extensions/theme-seti/build/update-icon-theme.js index c8ff7733533..091712b2957 100644 --- a/extensions/theme-seti/build/update-icon-theme.js +++ b/extensions/theme-seti/build/update-icon-theme.js @@ -54,6 +54,35 @@ function invertColor(color) { return res; } +function getLanguageMappings() { + var langToExt = { + 'csharp': ['cs', 'csx'] + }; + + var allExtensions = fs.readdirSync('..'); + for (var i= 0; i < allExtensions.length; i++) { + let dirPath = path.join('..', allExtensions[i], 'package.json'); + if (!fs.lstatSync(path.join('..', allExtensions[i])).isDirectory() || !fs.lstatSync(dirPath).isFile()) { + continue; + } + + let content = fs.readFileSync(dirPath).toString(); + let jsonContent = JSON.parse(content); + let languages = jsonContent.contributes && jsonContent.contributes.languages; + if (Array.isArray(languages)) { + for (var k = 0; k < languages.length; k++) { + var extensions = languages[k].extensions; + var languageId = languages[k].id; + if (Array.isArray(extensions) && languageId) { + langToExt[languageId] = extensions.map(function (e) { return e.substr(1); }); + } + } + } + } + + return langToExt; +} + exports.update = function () { var fontMappings = 'https://raw.githubusercontent.com/jesseweed/seti-ui/master/styles/_fonts/seti.less'; @@ -63,6 +92,7 @@ exports.update = function () { var fileName2Def = {}; var def2ColorId = {}; var colorId2Value = {}; + var lang2Def = {}; function writeFileIconContent(info) { var iconDefinitions = {}; @@ -106,14 +136,16 @@ exports.update = function () { file: "_default", fileExtensions: ext2Def, fileNames: fileName2Def, + languageIds: lang2Def, light: { file: "_default_light", fileExtensions: getInvertSet(ext2Def), + languageIds: getInvertSet(lang2Def), fileNames: getInvertSet(fileName2Def) }, version: 'https://github.com/jesseweed/seti-ui/commit/' + info.commitSha, }; - fs.writeFileSync('./icons/seti-icon-theme.json', JSON.stringify(res, null, '\t')); + fs.writeFileSync('./icons/vs-seti-icon-theme.json', JSON.stringify(res, null, '\t')); } @@ -140,6 +172,26 @@ exports.update = function () { } def2ColorId[def] = colorId; } + // replace extensions for languageId + var langToExt = getLanguageMappings(); + for (var lang in langToExt) { + var exts = langToExt[lang]; + var preferredDef = null; + // use the first file association for the preferred definition + for (var i1 = 0; i1 < exts.length && !preferredDef; i1++) { + preferredDef = ext2Def[exts[i1]]; + } + if (preferredDef) { + lang2Def[lang] = preferredDef; + for (var i1 = 0; i1 < exts.length; i1++) { + // remove the extention association, unless it is different from the preferred + if (ext2Def[exts[i1]] === preferredDef) { + delete ext2Def[exts[i1]]; + } + } + } + } + var colors = 'https://raw.githubusercontent.com/jesseweed/seti-ui/master/styles/ui-variables.less'; return download(colors).then(function (content) { var regex3 = /(@[\w-]+):\s*(#[0-9a-z]+)/g; @@ -156,7 +208,7 @@ exports.update = function () { console.error(e); } }); - }); + }); }); }, console.error); } diff --git a/extensions/theme-seti/icons/vs-seti-icon-theme.json b/extensions/theme-seti/icons/vs-seti-icon-theme.json index fbf3e22199c..58e9d244dfc 100644 --- a/extensions/theme-seti/icons/vs-seti-icon-theme.json +++ b/extensions/theme-seti/icons/vs-seti-icon-theme.json @@ -701,16 +701,9 @@ }, "file": "_default", "fileExtensions": { - "cpp": "_cpp", - "c": "_c", - "cs": "_c-sharp", - "cc": "_cpp", "cfc": "_coldfusion", "cfm": "_coldfusion", - "coffee": "_coffee", - "config": "_config", "cson": "_json", - "css": "_css", "css.map": "_css", "sss": "_css", "csv": "_csv", @@ -719,14 +712,11 @@ "elm": "_elm", "ico": "_favicon", "gitignore": "_github", - "gitconfig": "_github", "gitkeep": "_github", "gitattributes": "_github", - "go": "_go2", "slide": "_go", "article": "_go", "gradle": "_gradle", - "groovy": "_grails", "gsp": "_grails", "hh": "_hacklang", "haml": "_haml", @@ -735,57 +725,37 @@ "hjs": "_mustache", "hs": "_haskell", "lhs": "_haskell", - "html": "_html", - "jade": "_jade", - "java": "_java", "class": "_java", "classpath": "_java", - "js": "_javascript", "js.map": "_javascript", "es": "_javascript", "es5": "_javascript", - "es6": "_javascript", "es7": "_javascript", - "json": "_json", "jl": "_julia", - "less": "_less", "liquid": "_liquid", "ls": "_livescript", - "lua": "_lua", - "markdown": "_markdown", - "md": "_markdown", "mustache": "_mustache", "stache": "_mustache", "npm-debug.log": "_npm", "npmignore": "_npm", "h": "_c", - "m": "_c", "ml": "_ocaml", "mli": "_ocaml", "cmx": "_ocaml", "cmxa": "_ocaml", - "pl": "_perl", - "php": "_php", "php.inc": "_php", "pug": "_pug", "pp": "_puppet", - "py": "_python", - "jsx": "_react", "cjsx": "_react", - "tsx": "_react", - "rb": "_ruby", "erb": "_ruby", "erb.html": "_ruby", "html.erb": "_ruby", - "rs": "_rust", "sass": "_sass", - "scss": "_sass", "slim": "_slim", "smarty.tpl": "_smarty", "sbt": "_sbt", "scala": "_scala", "styl": "_stylus", - "swift": "_swift", "tf": "_terraform", "tf.json": "_terraform", "tex": "_tex", @@ -795,12 +765,9 @@ "ins": "_tex", "txt": "_default", "twig": "_twig", - "ts": "_typescript", "vala": "_vala", "vapi": "_vala", "xml": "_xml", - "yml": "_yml", - "yaml": "_yml", "ai": "_illustrator", "psd": "_photoshop", "pdf": "_pdf", @@ -814,11 +781,7 @@ "jpeg": "_image", "svg": "_svg", "svgx": "_image", - "cmd": "_shell", - "sh": "_shell", - "zsh": "_shell", "fish": "_shell", - "zshrc": "_shell", "mov": "_video", "ogv": "_video", "webm": "_video", @@ -865,19 +828,45 @@ "TODO": "_todo", "npm-debug.log": "_npm_ignored" }, + "languageIds": { + "csharp": "_c-sharp", + "bat": "_shell", + "coffeescript": "_coffee", + "c": "_c", + "cpp": "_cpp", + "css": "_css", + "go": "_go2", + "groovy": "_grails", + "html": "_html", + "ini": "_github", + "jade": "_jade", + "java": "_java", + "javascriptreact": "_react", + "javascript": "_javascript", + "json": "_json", + "less": "_less", + "lua": "_lua", + "markdown": "_markdown", + "objective-c": "_c", + "perl": "_perl", + "php": "_php", + "python": "_python", + "ruby": "_ruby", + "rust": "_rust", + "scss": "_sass", + "shellscript": "_shell", + "swift": "_swift", + "typescript": "_typescript", + "typescriptreact": "_react", + "xml": "_config", + "yaml": "_yml" + }, "light": { "file": "_default_light", "fileExtensions": { - "cpp": "_cpp_light", - "c": "_c_light", - "cs": "_c-sharp_light", - "cc": "_cpp_light", "cfc": "_coldfusion_light", "cfm": "_coldfusion_light", - "coffee": "_coffee_light", - "config": "_config_light", "cson": "_json_light", - "css": "_css_light", "css.map": "_css_light", "sss": "_css_light", "csv": "_csv_light", @@ -886,14 +875,11 @@ "elm": "_elm_light", "ico": "_favicon_light", "gitignore": "_github_light", - "gitconfig": "_github_light", "gitkeep": "_github_light", "gitattributes": "_github_light", - "go": "_go2_light", "slide": "_go_light", "article": "_go_light", "gradle": "_gradle_light", - "groovy": "_grails_light", "gsp": "_grails_light", "hh": "_hacklang_light", "haml": "_haml_light", @@ -902,57 +888,37 @@ "hjs": "_mustache_light", "hs": "_haskell_light", "lhs": "_haskell_light", - "html": "_html_light", - "jade": "_jade_light", - "java": "_java_light", "class": "_java_light", "classpath": "_java_light", - "js": "_javascript_light", "js.map": "_javascript_light", "es": "_javascript_light", "es5": "_javascript_light", - "es6": "_javascript_light", "es7": "_javascript_light", - "json": "_json_light", "jl": "_julia_light", - "less": "_less_light", "liquid": "_liquid_light", "ls": "_livescript_light", - "lua": "_lua_light", - "markdown": "_markdown_light", - "md": "_markdown_light", "mustache": "_mustache_light", "stache": "_mustache_light", "npm-debug.log": "_npm_light", "npmignore": "_npm_light", "h": "_c_light", - "m": "_c_light", "ml": "_ocaml_light", "mli": "_ocaml_light", "cmx": "_ocaml_light", "cmxa": "_ocaml_light", - "pl": "_perl_light", - "php": "_php_light", "php.inc": "_php_light", "pug": "_pug_light", "pp": "_puppet_light", - "py": "_python_light", - "jsx": "_react_light", "cjsx": "_react_light", - "tsx": "_react_light", - "rb": "_ruby_light", "erb": "_ruby_light", "erb.html": "_ruby_light", "html.erb": "_ruby_light", - "rs": "_rust_light", "sass": "_sass_light", - "scss": "_sass_light", "slim": "_slim_light", "smarty.tpl": "_smarty_light", "sbt": "_sbt_light", "scala": "_scala_light", "styl": "_stylus_light", - "swift": "_swift_light", "tf": "_terraform_light", "tf.json": "_terraform_light", "tex": "_tex_light", @@ -962,12 +928,9 @@ "ins": "_tex_light", "txt": "_default_light", "twig": "_twig_light", - "ts": "_typescript_light", "vala": "_vala_light", "vapi": "_vala_light", "xml": "_xml_light", - "yml": "_yml_light", - "yaml": "_yml_light", "ai": "_illustrator_light", "psd": "_photoshop_light", "pdf": "_pdf_light", @@ -981,11 +944,7 @@ "jpeg": "_image_light", "svg": "_svg_light", "svgx": "_image_light", - "cmd": "_shell_light", - "sh": "_shell_light", - "zsh": "_shell_light", "fish": "_shell_light", - "zshrc": "_shell_light", "mov": "_video_light", "ogv": "_video_light", "webm": "_video_light", @@ -1006,6 +965,39 @@ "tmp": "_clock_light", "DS_Store": "_ignored_light" }, + "languageIds": { + "csharp": "_c-sharp_light", + "bat": "_shell_light", + "coffeescript": "_coffee_light", + "c": "_c_light", + "cpp": "_cpp_light", + "css": "_css_light", + "go": "_go2_light", + "groovy": "_grails_light", + "html": "_html_light", + "ini": "_github_light", + "jade": "_jade_light", + "java": "_java_light", + "javascriptreact": "_react_light", + "javascript": "_javascript_light", + "json": "_json_light", + "less": "_less_light", + "lua": "_lua_light", + "markdown": "_markdown_light", + "objective-c": "_c_light", + "perl": "_perl_light", + "php": "_php_light", + "python": "_python_light", + "ruby": "_ruby_light", + "rust": "_rust_light", + "scss": "_sass_light", + "shellscript": "_shell_light", + "swift": "_swift_light", + "typescript": "_typescript_light", + "typescriptreact": "_react_light", + "xml": "_config_light", + "yaml": "_yml_light" + }, "fileNames": { "karma.conf.js": "_karma_light", "karma.conf.coffee": "_karma_light", diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index c6aba650b72..c219f231823 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -100,9 +100,11 @@ class Main { const response = JSON.parse(err.responseText); return TPromise.wrapError(response.message); } catch (e) { - return TPromise.wrapError(err); + // noop } } + + return TPromise.wrapError(err); }) .then(result => { const [extension] = result.firstPage; diff --git a/src/vs/editor/browser/standalone/simpleServices.ts b/src/vs/editor/browser/standalone/simpleServices.ts index 5c68fb3292e..567e3b097d2 100644 --- a/src/vs/editor/browser/standalone/simpleServices.ts +++ b/src/vs/editor/browser/standalone/simpleServices.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import {EventEmitter} from 'vs/base/common/eventEmitter'; import {Schemas} from 'vs/base/common/network'; import Severity from 'vs/base/common/severity'; import {TPromise} from 'vs/base/common/winjs.base'; @@ -56,13 +55,18 @@ export class SimpleEditor implements IEditor { } } -export class SimpleModel extends EventEmitter implements ITextEditorModel { +export class SimpleModel implements ITextEditorModel { private model:editorCommon.IModel; + private _onDispose: Emitter; constructor(model:editorCommon.IModel) { - super(); this.model = model; + this._onDispose = new Emitter(); + } + + public get onDispose(): Event { + return this._onDispose.event; } public load(): TPromise { @@ -72,6 +76,10 @@ export class SimpleModel extends EventEmitter implements ITextEditorModel { public get textEditorModel():editorCommon.IModel { return this.model; } + + public dispose(): void { + this._onDispose.fire(); + } } export interface IOpenEditorDelegate { diff --git a/src/vs/editor/contrib/find/common/findController.ts b/src/vs/editor/contrib/find/common/findController.ts index 8b0a5e65e53..8d0bd01fab0 100644 --- a/src/vs/editor/contrib/find/common/findController.ts +++ b/src/vs/editor/contrib/find/common/findController.ts @@ -5,6 +5,7 @@ 'use strict'; import * as nls from 'vs/nls'; +import {HistoryNavigator} from 'vs/base/common/history'; import {KeyCode, KeyMod, KeyChord} from 'vs/base/common/keyCodes'; import {Disposable} from 'vs/base/common/lifecycle'; import {ContextKeyExpr, RawContextKey, IContextKey, IContextKeyService} from 'vs/platform/contextkey/common/contextkey'; @@ -16,7 +17,7 @@ import {editorAction, commonEditorContribution, ServicesAccessor, EditorAction, import {FIND_IDS, FindModelBoundToEditorModel} from 'vs/editor/contrib/find/common/findModel'; import {FindReplaceState, FindReplaceStateChangedEvent, INewFindReplaceState} from 'vs/editor/contrib/find/common/findState'; import {DocumentHighlightProviderRegistry} from 'vs/editor/common/modes'; -import {RunOnceScheduler} from 'vs/base/common/async'; +import {RunOnceScheduler, Delayer} from 'vs/base/common/async'; import EditorContextKeys = editorCommon.EditorContextKeys; @@ -27,10 +28,10 @@ export const enum FindStartFocusAction { } export interface IFindStartOptions { - forceRevealReplace:boolean; - seedSearchStringFromSelection:boolean; - shouldFocus:FindStartFocusAction; - shouldAnimate:boolean; + forceRevealReplace: boolean; + seedSearchStringFromSelection: boolean; + shouldFocus: FindStartFocusAction; + shouldAnimate: boolean; } export const CONTEXT_FIND_WIDGET_VISIBLE = new RawContextKey('findWidgetVisible', false); @@ -43,17 +44,21 @@ export class CommonFindController extends Disposable implements editorCommon.IEd private _editor: editorCommon.ICommonCodeEditor; private _findWidgetVisible: IContextKey; protected _state: FindReplaceState; + private _currentHistoryNavigator: HistoryNavigator; + private _updateHistoryDelayer: Delayer; private _model: FindModelBoundToEditorModel; - public static get(editor:editorCommon.ICommonCodeEditor): CommonFindController { + public static get(editor: editorCommon.ICommonCodeEditor): CommonFindController { return editor.getContribution(CommonFindController.ID); } - constructor(editor:editorCommon.ICommonCodeEditor, @IContextKeyService contextKeyService: IContextKeyService) { + constructor(editor: editorCommon.ICommonCodeEditor, @IContextKeyService contextKeyService: IContextKeyService) { super(); this._editor = editor; this._findWidgetVisible = CONTEXT_FIND_WIDGET_VISIBLE.bindTo(contextKeyService); + this._updateHistoryDelayer = new Delayer(500); + this._currentHistoryNavigator = new HistoryNavigator(); this._state = this._register(new FindReplaceState()); this._register(this._state.addChangeListener((e) => this._onStateChanged(e))); @@ -95,7 +100,10 @@ export class CommonFindController extends Disposable implements editorCommon.IEd return CommonFindController.ID; } - private _onStateChanged(e:FindReplaceStateChangedEvent): void { + private _onStateChanged(e: FindReplaceStateChangedEvent): void { + if (e.updateHistory && e.searchString) { + this._delayedUpdateHistory(); + } if (e.isRevealed) { if (this._state.isRevealed) { this._findWidgetVisible.set(true); @@ -106,10 +114,24 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } } + protected _delayedUpdateHistory() { + this._updateHistoryDelayer.trigger(this._updateHistory.bind(this)); + } + + protected _updateHistory() { + if (this._state.searchString) { + this._currentHistoryNavigator.add(this._state.searchString); + } + } + public getState(): FindReplaceState { return this._state; } + public getHistory(): HistoryNavigator { + return this._currentHistoryNavigator; + } + public closeFindWidget(): void { this._state.change({ isRevealed: false, @@ -130,7 +152,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd this._state.change({ isRegex: !this._state.isRegex }, false); } - public setSearchString(searchString:string): void { + public setSearchString(searchString: string): void { this._state.change({ searchString: searchString }, false); } @@ -151,7 +173,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd return null; } - protected _start(opts:IFindStartOptions): void { + protected _start(opts: IFindStartOptions): void { this.disposeModel(); if (!this._editor.getModel()) { @@ -187,7 +209,7 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } } - public start(opts:IFindStartOptions): void { + public start(opts: IFindStartOptions): void { this._start(opts); } @@ -231,6 +253,22 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } return false; } + + public showPreviousFindTerm(): boolean { + let previousTerm = this._currentHistoryNavigator.previous(); + if (previousTerm) { + this._state.change({ searchString: previousTerm }, false, false); + } + return true; + } + + public showNextFindTerm(): boolean { + let nextTerm = this._currentHistoryNavigator.next(); + if (nextTerm) { + this._state.change({ searchString: nextTerm }, false, false); + } + return true; + } } @editorAction @@ -239,7 +277,7 @@ export class StartFindAction extends EditorAction { constructor() { super({ id: FIND_IDS.StartFindAction, - label: nls.localize('startFindAction',"Find"), + label: nls.localize('startFindAction', "Find"), alias: 'Find', precondition: null, kbOpts: { @@ -253,7 +291,7 @@ export class StartFindAction extends EditorAction { }); } - public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { let controller = CommonFindController.get(editor); if (controller) { controller.start({ @@ -267,7 +305,7 @@ export class StartFindAction extends EditorAction { } export abstract class MatchFindAction extends EditorAction { - public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { let controller = CommonFindController.get(editor); if (controller && !this._run(controller)) { controller.start({ @@ -280,7 +318,7 @@ export abstract class MatchFindAction extends EditorAction { } } - protected abstract _run(controller:CommonFindController): boolean; + protected abstract _run(controller: CommonFindController): boolean; } @editorAction @@ -300,7 +338,7 @@ export class NextMatchFindAction extends MatchFindAction { }); } - protected _run(controller:CommonFindController): boolean { + protected _run(controller: CommonFindController): boolean { return controller.moveToNextMatch(); } } @@ -322,13 +360,13 @@ export class PreviousMatchFindAction extends MatchFindAction { }); } - protected _run(controller:CommonFindController): boolean { + protected _run(controller: CommonFindController): boolean { return controller.moveToPrevMatch(); } } export abstract class SelectionMatchFindAction extends EditorAction { - public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { let controller = CommonFindController.get(editor); if (!controller) { return; @@ -348,7 +386,7 @@ export abstract class SelectionMatchFindAction extends EditorAction { } } - protected abstract _run(controller:CommonFindController): boolean; + protected abstract _run(controller: CommonFindController): boolean; } @editorAction @@ -367,7 +405,7 @@ export class NextSelectionMatchFindAction extends SelectionMatchFindAction { }); } - protected _run(controller:CommonFindController): boolean { + protected _run(controller: CommonFindController): boolean { return controller.moveToNextMatch(); } } @@ -388,7 +426,7 @@ export class PreviousSelectionMatchFindAction extends SelectionMatchFindAction { }); } - protected _run(controller:CommonFindController): boolean { + protected _run(controller: CommonFindController): boolean { return controller.moveToPrevMatch(); } } @@ -410,7 +448,7 @@ export class StartFindReplaceAction extends EditorAction { }); } - public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { if (editor.getConfiguration().readOnly) { return; } @@ -428,14 +466,14 @@ export class StartFindReplaceAction extends EditorAction { } export interface IMultiCursorFindResult { - searchText:string; - matchCase:boolean; - wholeWord:boolean; + searchText: string; + matchCase: boolean; + wholeWord: boolean; currentMatch: Selection; } -function multiCursorFind(editor:editorCommon.ICommonCodeEditor, changeFindSearchString:boolean): IMultiCursorFindResult { +function multiCursorFind(editor: editorCommon.ICommonCodeEditor, changeFindSearchString: boolean): IMultiCursorFindResult { let controller = CommonFindController.get(editor); if (!controller) { return null; @@ -489,7 +527,7 @@ function multiCursorFind(editor:editorCommon.ICommonCodeEditor, changeFindSearch } export abstract class SelectNextFindMatchAction extends EditorAction { - protected _getNextMatch(editor:editorCommon.ICommonCodeEditor): Selection { + protected _getNextMatch(editor: editorCommon.ICommonCodeEditor): Selection { let r = multiCursorFind(editor, true); if (!r) { return null; @@ -512,7 +550,7 @@ export abstract class SelectNextFindMatchAction extends EditorAction { } export abstract class SelectPreviousFindMatchAction extends EditorAction { - protected _getPreviousMatch(editor:editorCommon.ICommonCodeEditor): Selection { + protected _getPreviousMatch(editor: editorCommon.ICommonCodeEditor): Selection { let r = multiCursorFind(editor, true); if (!r) { return null; @@ -550,7 +588,7 @@ export class AddSelectionToNextFindMatchAction extends SelectNextFindMatchAction }); } - public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { let nextMatch = this._getNextMatch(editor); if (!nextMatch) { @@ -575,7 +613,7 @@ export class AddSelectionToPreviousFindMatchAction extends SelectPreviousFindMat }); } - public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { let previousMatch = this._getPreviousMatch(editor); if (!previousMatch) { @@ -604,7 +642,7 @@ export class MoveSelectionToNextFindMatchAction extends SelectNextFindMatchActio }); } - public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { let nextMatch = this._getNextMatch(editor); if (!nextMatch) { @@ -629,7 +667,7 @@ export class MoveSelectionToPreviousFindMatchAction extends SelectPreviousFindMa }); } - public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { let previousMatch = this._getPreviousMatch(editor); if (!previousMatch) { @@ -643,7 +681,7 @@ export class MoveSelectionToPreviousFindMatchAction extends SelectPreviousFindMa } export abstract class AbstractSelectHighlightsAction extends EditorAction { - public run(accessor:ServicesAccessor, editor:editorCommon.ICommonCodeEditor): void { + public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { let r = multiCursorFind(editor, true); if (!r) { return; @@ -713,7 +751,7 @@ export class SelectionHighlighter extends Disposable implements editorCommon.IEd private updateSoon: RunOnceScheduler; private lastWordUnderCursor: Range; - constructor(editor:editorCommon.ICommonCodeEditor) { + constructor(editor: editorCommon.ICommonCodeEditor) { super(); this.editor = editor; this.decorations = []; @@ -812,7 +850,7 @@ export class SelectionHighlighter extends Disposable implements editorCommon.IEd // do not overlap with selection (issue #64 and #512) let matches: Range[] = []; - for (let i = 0, j = 0, len = allMatches.length, lenJ = selections.length; i < len; ) { + for (let i = 0, j = 0, len = allMatches.length, lenJ = selections.length; i < len;) { let match = allMatches[i]; if (j >= lenJ) { @@ -943,3 +981,25 @@ CommonEditorRegistry.registerEditorCommand(new FindCommand({ primary: KeyMod.Alt | KeyCode.Enter } })); + +CommonEditorRegistry.registerEditorCommand(new FindCommand({ + id: FIND_IDS.ShowPreviousFindTermAction, + precondition: CONTEXT_FIND_WIDGET_VISIBLE, + handler: x => x.showPreviousFindTerm(), + kbOpts: { + weight: CommonEditorRegistry.commandWeight(5), + kbExpr: EditorContextKeys.Focus, + primary: KeyMod.Alt | KeyCode.UpArrow + } +})); + +CommonEditorRegistry.registerEditorCommand(new FindCommand({ + id: FIND_IDS.ShowNextFindTermAction, + precondition: CONTEXT_FIND_WIDGET_VISIBLE, + handler: x => x.showNextFindTerm(), + kbOpts: { + weight: CommonEditorRegistry.commandWeight(5), + kbExpr: EditorContextKeys.Focus, + primary: KeyMod.Alt | KeyCode.DownArrow + } +})); diff --git a/src/vs/editor/contrib/find/common/findModel.ts b/src/vs/editor/contrib/find/common/findModel.ts index c27d94d6fa1..542e7c2234e 100644 --- a/src/vs/editor/contrib/find/common/findModel.ts +++ b/src/vs/editor/contrib/find/common/findModel.ts @@ -34,7 +34,9 @@ export const FIND_IDS = { ToggleRegexCommand: 'toggleFindRegex', ReplaceOneAction: 'editor.action.replaceOne', ReplaceAllAction: 'editor.action.replaceAll', - SelectAllMatchesAction: 'editor.action.selectAllMatches' + SelectAllMatchesAction: 'editor.action.selectAllMatches', + ShowPreviousFindTermAction: 'find.history.showPrevious', + ShowNextFindTermAction: 'find.history.showNext' }; export const MATCHES_LIMIT = 999; diff --git a/src/vs/editor/contrib/find/common/findState.ts b/src/vs/editor/contrib/find/common/findState.ts index 9929e8993f5..517fc5e0352 100644 --- a/src/vs/editor/contrib/find/common/findState.ts +++ b/src/vs/editor/contrib/find/common/findState.ts @@ -10,6 +10,7 @@ import {Range} from 'vs/editor/common/core/range'; export interface FindReplaceStateChangedEvent { moveCursor: boolean; + updateHistory: boolean; searchString: boolean; replaceString: boolean; @@ -90,6 +91,7 @@ export class FindReplaceState implements IDisposable { public changeMatchInfo(matchesPosition:number, matchesCount:number, currentMatch:Range): void { let changeEvent:FindReplaceStateChangedEvent = { moveCursor: false, + updateHistory: false, searchString: false, replaceString: false, isRevealed: false, @@ -135,9 +137,10 @@ export class FindReplaceState implements IDisposable { } } - public change(newState:INewFindReplaceState, moveCursor:boolean): void { + public change(newState:INewFindReplaceState, moveCursor:boolean, updateHistory: boolean = true): void { let changeEvent:FindReplaceStateChangedEvent = { moveCursor: moveCursor, + updateHistory: updateHistory, searchString: false, replaceString: false, isRevealed: false, diff --git a/src/vs/editor/contrib/find/test/common/findController.test.ts b/src/vs/editor/contrib/find/test/common/findController.test.ts index 28bd8243d88..8ea94d729f8 100644 --- a/src/vs/editor/contrib/find/test/common/findController.test.ts +++ b/src/vs/editor/contrib/find/test/common/findController.test.ts @@ -15,10 +15,12 @@ import { NextMatchFindAction, StartFindAction, SelectHighlightsAction } from 'vs/editor/contrib/find/common/findController'; import {withMockCodeEditor} from 'vs/editor/test/common/mocks/mockCodeEditor'; +import {HistoryNavigator} from 'vs/base/common/history'; class TestFindController extends CommonFindController { public hasFocus: boolean; + public delayUpdateHistory: boolean = false; protected _start(opts:IFindStartOptions): void { super._start(opts); @@ -27,6 +29,14 @@ class TestFindController extends CommonFindController { this.hasFocus = true; } } + + protected _delayedUpdateHistory() { + if (this.delayUpdateHistory) { + super._delayedUpdateHistory(); + } else { + this._updateHistory(); + } + } } suite('FindController', () => { @@ -196,4 +206,125 @@ suite('FindController', () => { assert.equal(findController.getState().searchScope, null); }); }); + + test('find term is added to history on state change', () => { + withMockCodeEditor([ + 'var x = (3 * 5)', + 'var y = (3 * 5)', + 'var z = (3 * 5)', + ], {}, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(TestFindController); + findController.getState().change({ searchString: '1' }, false); + findController.getState().change({ searchString: '2' }, false); + findController.getState().change({ searchString: '3' }, false); + + assert.deepEqual(['1', '2', '3'], toArray(findController.getHistory())); + }); + }); + + test('find term is added with delay', (done) => { + withMockCodeEditor([ + 'var x = (3 * 5)', + 'var y = (3 * 5)', + 'var z = (3 * 5)', + ], {}, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(TestFindController); + findController.delayUpdateHistory = true; + findController.getState().change({ searchString: '1' }, false); + findController.getState().change({ searchString: '2' }, false); + findController.getState().change({ searchString: '3' }, false); + + setTimeout(function() { + assert.deepEqual(['3'], toArray(findController.getHistory())); + done(); + }, 500); + }); + }); + + test('show previous find term', () => { + withMockCodeEditor([ + 'var x = (3 * 5)', + 'var y = (3 * 5)', + 'var z = (3 * 5)', + ], {}, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(TestFindController); + findController.getState().change({ searchString: '1' }, false); + findController.getState().change({ searchString: '2' }, false); + findController.getState().change({ searchString: '3' }, false); + + findController.showPreviousFindTerm(); + assert.deepEqual('2', findController.getState().searchString); + }); + }); + + test('show previous find term do not update history', () => { + withMockCodeEditor([ + 'var x = (3 * 5)', + 'var y = (3 * 5)', + 'var z = (3 * 5)', + ], {}, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(TestFindController); + findController.getState().change({ searchString: '1' }, false); + findController.getState().change({ searchString: '2' }, false); + findController.getState().change({ searchString: '3' }, false); + + findController.showPreviousFindTerm(); + assert.deepEqual(['1', '2', '3'], toArray(findController.getHistory())); + }); + }); + + test('show next find term', () => { + withMockCodeEditor([ + 'var x = (3 * 5)', + 'var y = (3 * 5)', + 'var z = (3 * 5)', + ], {}, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(TestFindController); + findController.getState().change({ searchString: '1' }, false); + findController.getState().change({ searchString: '2' }, false); + findController.getState().change({ searchString: '3' }, false); + findController.getState().change({ searchString: '4' }, false); + + findController.showPreviousFindTerm(); + findController.showPreviousFindTerm(); + findController.showNextFindTerm(); + assert.deepEqual('3', findController.getState().searchString); + }); + }); + + test('show next find term do not update history', () => { + withMockCodeEditor([ + 'var x = (3 * 5)', + 'var y = (3 * 5)', + 'var z = (3 * 5)', + ], {}, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(TestFindController); + findController.getState().change({ searchString: '1' }, false); + findController.getState().change({ searchString: '2' }, false); + findController.getState().change({ searchString: '3' }, false); + findController.getState().change({ searchString: '4' }, false); + + findController.showPreviousFindTerm(); + findController.showPreviousFindTerm(); + findController.showNextFindTerm(); + assert.deepEqual(['1', '2', '3', '4'], toArray(findController.getHistory())); + }); + }); + + function toArray(historyNavigator: HistoryNavigator): string[] { + let result = []; + historyNavigator.first(); + if (historyNavigator.current()) { + do { + result.push(historyNavigator.current()); + } while (historyNavigator.next()); + } + return result; + } }); diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index 70d2028e556..897923795c7 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -28,6 +28,8 @@ export interface IEditorService { export interface IEditorModel { + onDispose: Event; + /** * Loads the model. */ diff --git a/src/vs/workbench/common/editor/untitledEditorInput.ts b/src/vs/workbench/common/editor/untitledEditorInput.ts index b61d85b01cf..17bf0df175b 100644 --- a/src/vs/workbench/common/editor/untitledEditorInput.ts +++ b/src/vs/workbench/common/editor/untitledEditorInput.ts @@ -9,7 +9,7 @@ import URI from 'vs/base/common/uri'; import {isUnspecific, guessMimeTypes, MIME_TEXT, suggestFilename} from 'vs/base/common/mime'; import labels = require('vs/base/common/labels'); import paths = require('vs/base/common/paths'); -import {UntitledEditorInput as AbstractUntitledEditorInput, EditorModel, EncodingMode, ConfirmResult} from 'vs/workbench/common/editor'; +import {UntitledEditorInput as AbstractUntitledEditorInput, EncodingMode, ConfirmResult} from 'vs/workbench/common/editor'; import {UntitledEditorModel} from 'vs/workbench/common/editor/untitledEditorModel'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; @@ -131,7 +131,7 @@ export class UntitledEditorInput extends AbstractUntitledEditorInput { } } - public resolve(refresh?: boolean): TPromise { + public resolve(refresh?: boolean): TPromise { // Use Cached Model if (this.cachedModel) { diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index b318df8ac13..b1bcce88bb3 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -14,7 +14,7 @@ import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/ex import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actionRegistry'; import { ExtensionTipsService } from 'vs/workbench/parts/extensions/electron-browser/extensionTipsService'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { ExtensionsWorkbenchExtension, StatusUpdater } from 'vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension'; +import { ExtensionsWorkbenchExtension } from 'vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension'; import { IOutputChannelRegistry, Extensions as OutputExtensions } from 'vs/workbench/parts/output/common/output'; import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; @@ -25,6 +25,7 @@ import { OpenExtensionsViewletAction, InstallExtensionsAction, ShowOutdatedExten import { ExtensionsInput } from './extensionsInput'; import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { ExtensionEditor } from './extensionEditor'; +import { StatusUpdater } from './extensionsViewlet'; import { IQuickOpenRegistry, Extensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index ff3e506eb8b..dbe9ed8254f 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -10,6 +10,7 @@ import { localize } from 'vs/nls'; import { ThrottledDelayer, always } from 'vs/base/common/async'; import { TPromise } from 'vs/base/common/winjs.base'; import { isPromiseCanceledError, onUnexpectedError, create as createError } from 'vs/base/common/errors'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Builder, Dimension } from 'vs/base/browser/builder'; import { assign } from 'vs/base/common/objects'; @@ -28,7 +29,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Delegate, Renderer } from './extensionsList'; -import { IExtensionsWorkbenchService, IExtension, IExtensionsViewlet, VIEWLET_ID } from './extensions'; +import { IExtensionsWorkbenchService, IExtension, IExtensionsViewlet, VIEWLET_ID, ExtensionState } from './extensions'; import { ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowInstalledExtensionsAction, ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction } from './extensionsActions'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, SortBy, SortOrder, IQueryOptions } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionsInput } from './extensionsInput'; @@ -41,6 +42,7 @@ import { IMessageService, CloseAction } from 'vs/platform/message/common/message import Severity from 'vs/base/common/severity'; import { IURLService } from 'vs/platform/url/common/url'; import URI from 'vs/base/common/uri'; +import { IActivityService, ProgressBadge, NumberBadge } from 'vs/workbench/services/activity/common/activityService'; interface SearchInputEvent extends Event { target: HTMLInputElement; @@ -358,3 +360,39 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { super.dispose(); } } + +export class StatusUpdater implements IWorkbenchContribution { + + private disposables: IDisposable[]; + + constructor( + @IActivityService private activityService: IActivityService, + @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService + ) { + extensionsWorkbenchService.onChange(this.onServiceChange, this, this.disposables); + } + + getId(): string { + return 'vs.extensions.statusupdater'; + } + + private onServiceChange(): void { + if (this.extensionsWorkbenchService.local.some(e => e.state === ExtensionState.Installing)) { + this.activityService.showActivity(VIEWLET_ID, new ProgressBadge(() => localize('extensions', 'Extensions')), 'extensions-badge progress-badge'); + return; + } + + const outdated = this.extensionsWorkbenchService.local.reduce((r, e) => r + (e.outdated ? 1 : 0), 0); + + if (outdated > 0) { + const badge = new NumberBadge(outdated, n => localize('outdatedExtensions', '{0} Outdated Extensions', n)); + this.activityService.showActivity(VIEWLET_ID, badge, 'extensions-badge count-badge'); + } else { + this.activityService.showActivity(VIEWLET_ID, null, 'extensions-badge'); + } + } + + dispose(): void { + this.disposables = dispose(this.disposables); + } +} diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts index 5555eb204d0..af6b0034bb0 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchExtension.ts @@ -6,16 +6,13 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { localize } from 'vs/nls'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IMessageService } from 'vs/platform/message/common/message'; -import { IExtensionsWorkbenchService, ExtensionState, VIEWLET_ID } from './extensions'; import Severity from 'vs/base/common/severity'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { LegacyWorkspaceContextService } from 'vs/workbench/services/workspace/common/contextService'; -import { IActivityService, ProgressBadge, NumberBadge } from 'vs/workbench/services/activity/common/activityService'; import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; import { ipcRenderer as ipc } from 'electron'; @@ -70,40 +67,4 @@ export class ExtensionsWorkbenchExtension implements IWorkbenchContribution { public getId(): string { return 'vs.extensions.workbenchextension'; } -} - -export class StatusUpdater implements IWorkbenchContribution { - - private disposables: IDisposable[]; - - constructor( - @IActivityService private activityService: IActivityService, - @IExtensionsWorkbenchService private extensionsWorkbenchService: IExtensionsWorkbenchService - ) { - extensionsWorkbenchService.onChange(this.onServiceChange, this, this.disposables); - } - - getId(): string { - return 'vs.extensions.statusupdater'; - } - - private onServiceChange(): void { - if (this.extensionsWorkbenchService.local.some(e => e.state === ExtensionState.Installing)) { - this.activityService.showActivity(VIEWLET_ID, new ProgressBadge(() => localize('extensions', 'Extensions')), 'extensions-badge progress-badge'); - return; - } - - const outdated = this.extensionsWorkbenchService.local.reduce((r, e) => r + (e.outdated ? 1 : 0), 0); - - if (outdated > 0) { - const badge = new NumberBadge(outdated, n => localize('outdatedExtensions', '{0} Outdated Extensions', n)); - this.activityService.showActivity(VIEWLET_ID, badge, 'extensions-badge count-badge'); - } else { - this.activityService.showActivity(VIEWLET_ID, null, 'extensions-badge'); - } - } - - dispose(): void { - this.disposables = dispose(this.disposables); - } -} +} \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts index d4b75641003..d45ff9f7453 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsWorkbenchService.ts @@ -467,7 +467,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { const message = err && err.message || ''; - if (/getaddrinfo ENOTFOUND|getaddrinfo ENOENT|connect EACCES/.test(message)) { + if (/getaddrinfo ENOTFOUND|getaddrinfo ENOENT|connect EACCES|connect ECONNREFUSED/.test(message)) { return; } diff --git a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts index 95da252871c..1a3f919e736 100644 --- a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts @@ -15,10 +15,9 @@ import {IEditorViewState} from 'vs/editor/common/editorCommon'; import {Action} from 'vs/base/common/actions'; import {Scope} from 'vs/workbench/common/memento'; import {IEditorOptions} from 'vs/editor/common/editorCommon'; -import {VIEWLET_ID, TEXT_FILE_EDITOR_ID} from 'vs/workbench/parts/files/common/files'; +import {VIEWLET_ID, TEXT_FILE_EDITOR_ID, ITextFileEditorModel} from 'vs/workbench/parts/files/common/files'; import {BaseTextEditor} from 'vs/workbench/browser/parts/editor/textEditor'; -import {EditorOptions, TextEditorOptions, EditorModel} from 'vs/workbench/common/editor'; -import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; +import {EditorOptions, TextEditorOptions} from 'vs/workbench/common/editor'; import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel'; import {FileEditorInput} from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import {ExplorerViewlet} from 'vs/workbench/parts/files/browser/explorerViewlet'; @@ -117,7 +116,7 @@ export class TextFileEditor extends BaseTextEditor { } // Different Input (Reload) - return this.editorService.resolveEditorModel(input, true /* Reload */).then((resolvedModel: EditorModel) => { + return this.editorService.resolveEditorModel(input, true /* Reload */).then(resolvedModel => { // There is a special case where the text editor has to handle binary file editor input: if a file with application/unknown // mime has been resolved and cached before, it maybe an actual instance of BinaryEditorModel. In this case our text @@ -126,13 +125,8 @@ export class TextFileEditor extends BaseTextEditor { return this.openAsBinary(input, options); } - // Assert Model interface - if (!(resolvedModel instanceof TextFileEditorModel)) { - return TPromise.wrapError('Invalid editor input. Text file editor requires a model instance of TextFileEditorModel.'); - } - // Check Model state - const textFileModel = resolvedModel; + const textFileModel = resolvedModel; const hasInput = !!this.getInput(); const modelDisposed = textFileModel.isDisposed(); diff --git a/src/vs/workbench/parts/files/common/editors/textFileEditorModelManager.ts b/src/vs/workbench/parts/files/common/editors/textFileEditorModelManager.ts index 5efd8ee90e0..6a91400c223 100644 --- a/src/vs/workbench/parts/files/common/editors/textFileEditorModelManager.ts +++ b/src/vs/workbench/parts/files/common/editors/textFileEditorModelManager.ts @@ -32,8 +32,8 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager { private mapResourceToDisposeListener: { [resource: string]: IDisposable; }; private mapResourceToStateChangeListener: { [resource: string]: IDisposable; }; - private mapResourceToModel: { [resource: string]: TextFileEditorModel; }; - private mapResourceToPendingModelLoaders: { [resource: string]: TPromise }; + private mapResourceToModel: { [resource: string]: ITextFileEditorModel; }; + private mapResourceToPendingModelLoaders: { [resource: string]: TPromise }; constructor( @ILifecycleService private lifecycleService: ILifecycleService, @@ -162,11 +162,11 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager { return this._onModelEncodingChanged.event; } - public get(resource: URI): TextFileEditorModel { + public get(resource: URI): ITextFileEditorModel { return this.mapResourceToModel[resource.toString()]; } - public loadOrCreate(resource: URI, encoding: string, refresh?: boolean): TPromise { + public loadOrCreate(resource: URI, encoding: string, refresh?: boolean): TPromise { // Return early if model is currently being loaded const pendingLoad = this.mapResourceToPendingModelLoaders[resource.toString()]; @@ -174,7 +174,7 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager { return pendingLoad; } - let modelPromise: TPromise; + let modelPromise: TPromise; // Model exists let model = this.get(resource); @@ -238,13 +238,13 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager { }); } - public getAll(resource?: URI): TextFileEditorModel[] { + public getAll(resource?: URI): ITextFileEditorModel[] { return Object.keys(this.mapResourceToModel) .filter(r => !resource || resource.toString() === r) .map(r => this.mapResourceToModel[r]); } - public add(resource: URI, model: TextFileEditorModel): void { + public add(resource: URI, model: ITextFileEditorModel): void { const knownModel = this.mapResourceToModel[resource.toString()]; if (knownModel === model) { return; // already cached diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index 32989913884..44ac8de74e5 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -274,6 +274,8 @@ export interface ITextFileEditorModelManager { export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport { + onDidStateChange: Event; + getResource(): URI; getLastSaveAttemptTime(): number; @@ -282,6 +284,8 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport getState(): ModelState; + updatePreferredEncoding(encoding: string): void; + save(overwriteReadonly?: boolean, overwriteEncoding?: boolean): TPromise; revert(): TPromise; diff --git a/src/vs/workbench/parts/files/common/textFileService.ts b/src/vs/workbench/parts/files/common/textFileService.ts index ac12eb92f39..3ada394c220 100644 --- a/src/vs/workbench/parts/files/common/textFileService.ts +++ b/src/vs/workbench/parts/files/common/textFileService.ts @@ -9,8 +9,7 @@ import URI from 'vs/base/common/uri'; import paths = require('vs/base/common/paths'); import errors = require('vs/base/common/errors'); import Event, {Emitter} from 'vs/base/common/event'; -import {TextFileEditorModel} from 'vs/workbench/parts/files/common/editors/textFileEditorModel'; -import {IResult, ITextFileOperationResult, ITextFileService, IRawTextContent, IAutoSaveConfiguration, AutoSaveMode, ITextFileEditorModelManager} from 'vs/workbench/parts/files/common/files'; +import {IResult, ITextFileOperationResult, ITextFileService, IRawTextContent, IAutoSaveConfiguration, AutoSaveMode, ITextFileEditorModelManager, ITextFileEditorModel} from 'vs/workbench/parts/files/common/files'; import {ConfirmResult} from 'vs/workbench/common/editor'; import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace'; @@ -329,11 +328,11 @@ export abstract class TextFileService implements ITextFileService { }); } - private getFileModels(resources?: URI[]): TextFileEditorModel[]; - private getFileModels(resource?: URI): TextFileEditorModel[]; - private getFileModels(arg1?: any): TextFileEditorModel[] { + private getFileModels(resources?: URI[]): ITextFileEditorModel[]; + private getFileModels(resource?: URI): ITextFileEditorModel[]; + private getFileModels(arg1?: any): ITextFileEditorModel[] { if (Array.isArray(arg1)) { - const models: TextFileEditorModel[] = []; + const models: ITextFileEditorModel[] = []; (arg1).forEach(resource => { models.push(...this.getFileModels(resource)); }); @@ -344,9 +343,9 @@ export abstract class TextFileService implements ITextFileService { return this._models.getAll(arg1); } - private getDirtyFileModels(resources?: URI[]): TextFileEditorModel[]; - private getDirtyFileModels(resource?: URI): TextFileEditorModel[]; - private getDirtyFileModels(arg1?: any): TextFileEditorModel[] { + private getDirtyFileModels(resources?: URI[]): ITextFileEditorModel[]; + private getDirtyFileModels(resource?: URI): ITextFileEditorModel[]; + private getDirtyFileModels(arg1?: any): ITextFileEditorModel[] { return this.getFileModels(arg1).filter(model => model.isDirty()); } @@ -381,7 +380,7 @@ export abstract class TextFileService implements ITextFileService { private doSaveAs(resource: URI, target?: URI): TPromise { // Retrieve text model from provided resource if any - let modelPromise: TPromise = TPromise.as(null); + let modelPromise: TPromise = TPromise.as(null); if (resource.scheme === 'file') { modelPromise = TPromise.as(this._models.get(resource)); } else if (resource.scheme === 'untitled') { @@ -411,11 +410,11 @@ export abstract class TextFileService implements ITextFileService { }); } - private doSaveTextFileAs(sourceModel: TextFileEditorModel | UntitledEditorModel, resource: URI, target: URI): TPromise { + private doSaveTextFileAs(sourceModel: ITextFileEditorModel | UntitledEditorModel, resource: URI, target: URI): TPromise { // create the target file empty if it does not exist already return this.fileService.resolveFile(target).then(stat => stat, () => null).then(stat => stat || this.fileService.createFile(target)).then(stat => { // resolve a model for the file (which can be binary if the file is not a text file) - return this.editorService.resolveEditorModel({ resource: target }).then((targetModel: TextFileEditorModel) => { + return this.editorService.resolveEditorModel({ resource: target }).then((targetModel: ITextFileEditorModel) => { // binary model: delete the file and run the operation again if (targetModel instanceof BinaryEditorModel) { return this.fileService.del(target).then(() => this.doSaveTextFileAs(sourceModel, resource, target)); diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index 02d8135fa9a..a0660b81c59 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -41,7 +41,7 @@ export function appendKeyBindingLabel(label: string, keyBinding: any, keyBinding export class ShowNextSearchTermAction extends Action { - public static ID = 'search.history.nextSearchTerm'; + public static ID = 'search.history.showNext'; public static LABEL = nls.localize('nextSearchTerm', "Show next search term"); constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) { @@ -57,7 +57,7 @@ export class ShowNextSearchTermAction extends Action { export class ShowPreviousSearchTermAction extends Action { - public static ID = 'search.history.previousSearchTerm'; + public static ID = 'search.history.showPrevious'; public static LABEL = nls.localize('previousSearchTerm', "Show previous search term"); constructor(id: string, label: string, @IViewletService private viewletService: IViewletService) { diff --git a/src/vs/workbench/services/themes/electron-browser/themeService.ts b/src/vs/workbench/services/themes/electron-browser/themeService.ts index 35038feb248..e188e3d24e5 100644 --- a/src/vs/workbench/services/themes/electron-browser/themeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/themeService.ts @@ -508,15 +508,19 @@ function _processIconThemeDocument(id: string, iconThemeDocumentPath: string, ic let fileExtensions = associations.fileExtensions; if (fileExtensions) { for (let fileExtension in fileExtensions) { - addSelector(`${qualifier} .${escapeCSS(fileExtension.toLowerCase())}-ext-file-icon.file-icon::before`, fileExtensions[fileExtension]); + let selectors = []; + let segments = fileExtension.toLowerCase().split('.'); + for (let i = 0; i < segments.length; i++) { + selectors.push(`.${escapeCSS(segments.slice(i).join('.'))}-ext-file-icon`); + } + addSelector(`${qualifier} ${selectors.join('')}.file-icon::before`, fileExtensions[fileExtension]); } } let fileNames = associations.fileNames; if (fileNames) { for (let fileName in fileNames) { - fileName = fileName.toLowerCase(); let selectors = []; - let segments = fileName.split('.'); + let segments = fileName.toLowerCase().split('.'); if (segments[0]) { selectors.push(`.${escapeCSS(segments[0])}-name-file-icon`); }