From a19f7c9660ab63b7bfdfdf51f5649dad72c232c7 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Thu, 4 Jul 2019 17:32:14 -0400 Subject: [PATCH 1/9] Read key remappings from .vimrc Read key remapping commands from $HOME/.vimrc, $HOME/_vimrc, or a user-specified Vim configuration file. For each, build an IKeyRemapping object and append it to the appropriate collection, _if_ doing so will not override a remapping specified in the VS Code settings. Partially addresses #463. This implementation borrows heavily from Sheepolution/vimrc-to-json. --- package-lock.json | 5 + package.json | 10 ++ src/configuration/configuration.ts | 8 ++ src/configuration/iconfiguration.ts | 11 +++ src/configuration/vimrc.ts | 96 +++++++++++++++++++ src/configuration/vimrcKeyRemappingBuilder.ts | 60 ++++++++++++ .../vimrcKeyRemappingBuilder.test.ts | 64 +++++++++++++ test/testConfiguration.ts | 4 +- 8 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 src/configuration/vimrc.ts create mode 100644 src/configuration/vimrcKeyRemappingBuilder.ts create mode 100644 test/configuration/vimrcKeyRemappingBuilder.test.ts diff --git a/package-lock.json b/package-lock.json index 963ad02c366..c2ec34eb2c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1888,6 +1888,11 @@ "map-cache": "^0.2.2" } }, + "fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" + }, "fs-mkdirp-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", diff --git a/package.json b/package.json index 830d8429b8f..1674675d45e 100644 --- a/package.json +++ b/package.json @@ -750,6 +750,15 @@ "default": "", "scope": "machine" }, + "vim.enableVimrc": { + "type": "boolean", + "description": "Use key mappings from a .vimrc file", + "default": "true" + }, + "vim.vimrcPath": { + "type": "string", + "description": "Path to a Vim configuration file. If unset, it will check for $HOME/.vimrc or $HOME/_vimrc" + }, "vim.substituteGlobalFlag": { "type": "boolean", "markdownDescription": "Automatically apply the global flag, `/g`, to substitute commands. When set to true, use `/g` to mean only first match should be replaced.", @@ -897,6 +906,7 @@ }, "dependencies": { "diff-match-patch": "1.0.4", + "fs": "0.0.1-security", "lodash.escaperegexp": "4.1.2", "neovim": "4.5.0", "untildify": "4.0.0", diff --git a/src/configuration/configuration.ts b/src/configuration/configuration.ts index 3dc417bdc7d..78d5982c694 100644 --- a/src/configuration/configuration.ts +++ b/src/configuration/configuration.ts @@ -5,6 +5,7 @@ import { ValidatorResults } from './iconfigurationValidator'; import { VsCodeContext } from '../util/vscode-context'; import { configurationValidator } from './configurationValidator'; import { decoration } from './decoration'; +import { vimrc } from './vimrc'; import { IConfiguration, IKeyRemapping, @@ -86,6 +87,10 @@ class Configuration implements IConfiguration { } } + if (this.enableVimrc) { + vimrc.load(this); + } + this.leader = Notation.NormalizeKey(this.leader, this.leaderDefault); const validatorResults = await configurationValidator.validate(configuration); @@ -303,6 +308,9 @@ class Configuration implements IConfiguration { enableNeovim = false; neovimPath = ''; + enableVimrc = true; + vimrcPath = ''; + digraphs = {}; gdefault = false; diff --git a/src/configuration/iconfiguration.ts b/src/configuration/iconfiguration.ts index 1a1c2e262f2..69e38c59d79 100644 --- a/src/configuration/iconfiguration.ts +++ b/src/configuration/iconfiguration.ts @@ -17,6 +17,11 @@ export interface IKeyRemapping { commands?: ({ command: string; args: any[] } | string)[]; } +export interface IVimrcKeyRemapping { + keyRemapping: IKeyRemapping; + keyRemappingType: string; +} + export interface IAutoSwitchInputMethod { enable: boolean; defaultIM: string; @@ -287,6 +292,12 @@ export interface IConfiguration { enableNeovim: boolean; neovimPath: string; + /** + * .vimrc + */ + enableVimrc: boolean; + vimrcPath: string; + /** * Automatically apply the `/g` flag to substitute commands. */ diff --git a/src/configuration/vimrc.ts b/src/configuration/vimrc.ts new file mode 100644 index 00000000000..9370c008eb8 --- /dev/null +++ b/src/configuration/vimrc.ts @@ -0,0 +1,96 @@ +import * as _ from 'lodash'; +import * as fs from 'fs'; +import * as path from 'path'; +import { IConfiguration, IKeyRemapping, IVimrcKeyRemapping } from './iconfiguration'; +import { vimrcKeyRemappingBuilder } from './vimrcKeyRemappingBuilder'; + +class VimrcImpl { + public load(configuration: IConfiguration) { + if (configuration.vimrcPath) { + configuration.vimrcPath = VimrcImpl.expandHome(configuration.vimrcPath); + if (!fs.existsSync(configuration.vimrcPath)) { + return; + } + } else { + configuration.vimrcPath = VimrcImpl.findDefaultVimrc(); + if (!configuration.vimrcPath) { + return; + } + } + + let vimrcContent = fs.readFileSync(configuration.vimrcPath, { encoding: 'utf8' }); + let lines = vimrcContent.split(/\r?\n/); + + for (const line of lines) { + VimrcImpl.tryKeyRemapping(configuration, line); + } + } + + private static tryKeyRemapping(configuration: IConfiguration, line: string): boolean { + let mapping: IVimrcKeyRemapping | null = vimrcKeyRemappingBuilder.build(line); + if (!mapping) { + return false; + } + + let collection: IKeyRemapping[]; + switch (mapping.keyRemappingType) { + case 'nmap': + collection = configuration.normalModeKeyBindings; + break; + case 'vmap': + collection = configuration.visualModeKeyBindings; + break; + case 'imap': + collection = configuration.insertModeKeyBindings; + break; + case 'nnoremap': + collection = configuration.normalModeKeyBindingsNonRecursive; + break; + case 'vnoremap': + collection = configuration.visualModeKeyBindingsNonRecursive; + break; + case 'inoremap': + collection = configuration.insertModeKeyBindingsNonRecursive; + break; + default: + return false; + } + + // Don't override a mapping present in settings.json; those are more specific to VSCodeVim. + if (!collection.some(r => _.isEqual(r.before, mapping!.keyRemapping.before))) { + collection.push(mapping.keyRemapping); + } + + return true; + } + + private static findDefaultVimrc(): string { + if (!process.env.HOME) { + return ''; + } + + let vimrcPath = path.join(process.env.HOME, '.vimrc'); + if (!fs.existsSync(vimrcPath)) { + vimrcPath = path.join(process.env.HOME, '_vimrc'); + if (!fs.existsSync(vimrcPath)) { + return ''; + } + } + + return vimrcPath; + } + + private static expandHome(filePath: string): string { + if (!process.env.HOME) { + return filePath; + } + + if (!filePath.startsWith('~')) { + return filePath; + } + + return path.join(process.env.HOME, filePath.slice(1)); + } +} + +export const vimrc = new VimrcImpl(); diff --git a/src/configuration/vimrcKeyRemappingBuilder.ts b/src/configuration/vimrcKeyRemappingBuilder.ts new file mode 100644 index 00000000000..caceba1e0fa --- /dev/null +++ b/src/configuration/vimrcKeyRemappingBuilder.ts @@ -0,0 +1,60 @@ +import { IKeyRemapping, IVimrcKeyRemapping } from './iconfiguration'; + +class VimrcKeyRemappingBuilderImpl { + private static readonly KEY_REMAPPING_REG_EX = /(^.*map)\s([\S]+)\s+([\S]+)$/; + private static readonly KEY_LIST_REG_EX = /(<[^>]+>|.)/g; + private static readonly COMMAND_REG_EX = /(:\w+)/; + + public build(line: string): IVimrcKeyRemapping | null { + let matches = VimrcKeyRemappingBuilderImpl.KEY_REMAPPING_REG_EX.exec(line); + if (!matches || matches.length < 4) { + return null; + } + + let type = matches[1]; + let before = matches[2]; + let after = matches[3]; + let mapping: IKeyRemapping; + + if (VimrcKeyRemappingBuilderImpl.isCommand(after)) { + mapping = { + before: VimrcKeyRemappingBuilderImpl.buildKeyList(before), + commands: [after], + }; + } else { + mapping = { + before: VimrcKeyRemappingBuilderImpl.buildKeyList(before), + after: VimrcKeyRemappingBuilderImpl.buildKeyList(after), + }; + } + + return { + keyRemapping: mapping, + keyRemappingType: type, + }; + } + + private static isCommand(commandString: string): boolean { + let matches = VimrcKeyRemappingBuilderImpl.COMMAND_REG_EX.exec(commandString); + if (matches) { + return true; + } + return false; + } + + private static buildKeyList(keyString: string): string[] { + let keyList: string[] = []; + let matches; + + do { + matches = VimrcKeyRemappingBuilderImpl.KEY_LIST_REG_EX.exec(keyString); + if (matches) { + keyList.push(matches[0]); + } + } while (matches); + + return keyList; + } +} + +export const vimrcKeyRemappingBuilder = new VimrcKeyRemappingBuilderImpl(); diff --git a/test/configuration/vimrcKeyRemappingBuilder.test.ts b/test/configuration/vimrcKeyRemappingBuilder.test.ts new file mode 100644 index 00000000000..a7f6eff2fd9 --- /dev/null +++ b/test/configuration/vimrcKeyRemappingBuilder.test.ts @@ -0,0 +1,64 @@ +import * as assert from 'assert'; +import { IKeyRemapping, IVimrcKeyRemapping } from '../../src/configuration/iconfiguration'; +import { vimrcKeyRemappingBuilder } from '../../src/configuration/vimrcKeyRemappingBuilder'; + +suite('VimrcKeyRemappingBuilder', () => { + test('Build IKeyRemapping objects from .vimrc lines', () => { + const testCases = [ + { + vimrcLine: 'nnoremap <<', + keyRemapping: { + before: [''], + after: ['<', '<'], + }, + keyRemappingType: 'nnoremap', + expectNull: false + }, + { + vimrcLine: 'imap jj ', + keyRemapping: { + before: ['j', 'j'], + after: [''], + }, + keyRemappingType: 'imap', + expectNull: false + }, + { + vimrcLine: 'vnoremap " c""P', + keyRemapping: { + before: ['', '"'], + after: ['c', '"', '"', '', 'P'], + }, + keyRemappingType: 'vnoremap', + expectNull: false + }, + { + // Mapping with a command + vimrcLine: 'nnoremap :w', + keyRemapping: { + before: [''], + commands: [':w'], + }, + keyRemappingType: 'nnoremap', + expectNull: false + }, + { + // Ignore non-mapping lines + vimrcLine: 'set scrolloff=8', + expectNull: true + }, + ]; + + for (const testCase of testCases) { + let vimrcKeyRemapping: IVimrcKeyRemapping | null = + vimrcKeyRemappingBuilder.build(testCase.vimrcLine); + + if (testCase.expectNull) { + assert.equal(vimrcKeyRemapping, null); + } else { + assert.deepEqual(vimrcKeyRemapping!.keyRemapping, testCase.keyRemapping); + assert.equal(vimrcKeyRemapping!.keyRemappingType, testCase.keyRemappingType); + } + } + }); +}); diff --git a/test/testConfiguration.ts b/test/testConfiguration.ts index ddbbf512973..675dcade28f 100644 --- a/test/testConfiguration.ts +++ b/test/testConfiguration.ts @@ -81,9 +81,11 @@ export class Configuration implements IConfiguration { foldfix = false; disableExtension = false; enableNeovim = false; - neovimPath = ''; gdefault = false; substituteGlobalFlag = false; // Deprecated in favor of gdefault + neovimPath = 'nvim'; + enableVimrc = false; + vimrcPath = ''; cursorStylePerMode: IModeSpecificStrings = { normal: 'line', insert: 'block', From b0160f9f0a8eabd941343b4c8efe74a69d2ae580 Mon Sep 17 00:00:00 2001 From: Jason Fields Date: Sat, 26 Oct 2019 01:02:27 -0400 Subject: [PATCH 2/9] Small changes from code review --- package-lock.json | 20 +++---------------- package.json | 12 +++++------ src/common/motion/position.ts | 8 ++++---- src/configuration/iconfigurationValidator.ts | 2 +- src/configuration/vimrcKeyRemappingBuilder.ts | 15 +++++++------- 5 files changed, 21 insertions(+), 36 deletions(-) diff --git a/package-lock.json b/package-lock.json index c2ec34eb2c0..5ed4602c4d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -141,20 +141,11 @@ "dev": true }, "@types/lodash": { - "version": "4.14.138", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.138.tgz", - "integrity": "sha512-A4uJgHz4hakwNBdHNPdxOTkYmXNgmUAKLbXZ7PKGslgeV0Mb8P3BlbYfPovExek1qnod4pDfRbxuzcVs3dlFLg==", + "version": "4.14.144", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz", + "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==", "dev": true }, - "@types/lodash.escaperegexp": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/lodash.escaperegexp/-/lodash.escaperegexp-4.1.6.tgz", - "integrity": "sha512-uENiqxLlqh6RzeE1cC6Z2gHqakToN9vKlTVCFkSVjAfeMeh2fY0916tHwJHeeKs28qB/hGYvKuampGYH5QDVCw==", - "dev": true, - "requires": { - "@types/lodash": "*" - } - }, "@types/mocha": { "version": "5.2.7", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", @@ -3529,11 +3520,6 @@ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", "dev": true }, - "lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=" - }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", diff --git a/package.json b/package.json index 1674675d45e..ee1c3c30456 100644 --- a/package.json +++ b/package.json @@ -750,14 +750,14 @@ "default": "", "scope": "machine" }, - "vim.enableVimrc": { + "vim.vimrc.enable": { "type": "boolean", - "description": "Use key mappings from a .vimrc file", + "description": "Use key mappings from a .vimrc file.", "default": "true" }, - "vim.vimrcPath": { + "vim.vimrc.path": { "type": "string", - "description": "Path to a Vim configuration file. If unset, it will check for $HOME/.vimrc or $HOME/_vimrc" + "description": "Path to a Vim configuration file. If unset, it will check for $HOME/.vimrc or $HOME/_vimrc." }, "vim.substituteGlobalFlag": { "type": "boolean", @@ -907,7 +907,7 @@ "dependencies": { "diff-match-patch": "1.0.4", "fs": "0.0.1-security", - "lodash.escaperegexp": "4.1.2", + "lodash": "^4.17.15", "neovim": "4.5.0", "untildify": "4.0.0", "winston": "3.2.1", @@ -917,7 +917,7 @@ "devDependencies": { "@types/diff": "4.0.2", "@types/diff-match-patch": "1.0.32", - "@types/lodash.escaperegexp": "4.1.6", + "@types/lodash": "^4.14.144", "@types/mocha": "5.2.7", "@types/node": "12.12.5", "@types/sinon": "7.5.0", diff --git a/src/common/motion/position.ts b/src/common/motion/position.ts index 6127590aa67..ed5fc92e6c3 100644 --- a/src/common/motion/position.ts +++ b/src/common/motion/position.ts @@ -4,7 +4,7 @@ import { VimState } from '../../state/vimState'; import { configuration } from './../../configuration/configuration'; import { VisualBlockMode } from './../../mode/modes'; import { TextEditor } from './../../textEditor'; -import escapeRegExp = require('lodash.escaperegexp'); +import * as _ from 'lodash'; enum PositionDiffType { Offset, @@ -874,7 +874,7 @@ export class Position extends vscode.Position { } private static makeWordRegex(characterSet: string): RegExp { - let escaped = characterSet && escapeRegExp(characterSet).replace(/-/g, '\\-'); + let escaped = characterSet && _.escapeRegExp(characterSet).replace(/-/g, '\\-'); let segments: string[] = []; segments.push(`([^\\s${escaped}]+)`); @@ -886,7 +886,7 @@ export class Position extends vscode.Position { } private static makeCamelCaseWordRegex(characterSet: string): RegExp { - const escaped = characterSet && escapeRegExp(characterSet).replace(/-/g, '\\-'); + const escaped = characterSet && _.escapeRegExp(characterSet).replace(/-/g, '\\-'); const segments: string[] = []; // old versions of VSCode before 1.31 will crash when trying to parse a regex with a lookbehind @@ -1028,7 +1028,7 @@ export class Position extends vscode.Position { // Symbols in vim.iskeyword or editor.wordSeparators // are treated as CharKind.Punctuation - const escapedKeywordChars = escapeRegExp(keywordChars).replace(/-/g, '\\-'); + const escapedKeywordChars = _.escapeRegExp(keywordChars).replace(/-/g, '\\-'); codePointRangePatterns[Number(CharKind.Punctuation)].push(escapedKeywordChars); const codePointRanges = codePointRangePatterns.map(patterns => patterns.join('')); diff --git a/src/configuration/iconfigurationValidator.ts b/src/configuration/iconfigurationValidator.ts index 73a004dba48..61b56ebd322 100644 --- a/src/configuration/iconfigurationValidator.ts +++ b/src/configuration/iconfigurationValidator.ts @@ -39,5 +39,5 @@ export class ValidatorResults { export interface IConfigurationValidator { validate(config: IConfiguration): Promise; - disable(config: IConfiguration); + disable(config: IConfiguration): void; } diff --git a/src/configuration/vimrcKeyRemappingBuilder.ts b/src/configuration/vimrcKeyRemappingBuilder.ts index caceba1e0fa..528e532a783 100644 --- a/src/configuration/vimrcKeyRemappingBuilder.ts +++ b/src/configuration/vimrcKeyRemappingBuilder.ts @@ -6,16 +6,16 @@ class VimrcKeyRemappingBuilderImpl { private static readonly COMMAND_REG_EX = /(:\w+)/; public build(line: string): IVimrcKeyRemapping | null { - let matches = VimrcKeyRemappingBuilderImpl.KEY_REMAPPING_REG_EX.exec(line); + const matches = VimrcKeyRemappingBuilderImpl.KEY_REMAPPING_REG_EX.exec(line); if (!matches || matches.length < 4) { return null; } - let type = matches[1]; - let before = matches[2]; - let after = matches[3]; - let mapping: IKeyRemapping; + const type = matches[1]; + const before = matches[2]; + const after = matches[3]; + let mapping: IKeyRemapping; if (VimrcKeyRemappingBuilderImpl.isCommand(after)) { mapping = { before: VimrcKeyRemappingBuilderImpl.buildKeyList(before), @@ -35,7 +35,7 @@ class VimrcKeyRemappingBuilderImpl { } private static isCommand(commandString: string): boolean { - let matches = VimrcKeyRemappingBuilderImpl.COMMAND_REG_EX.exec(commandString); + const matches = VimrcKeyRemappingBuilderImpl.COMMAND_REG_EX.exec(commandString); if (matches) { return true; } @@ -44,8 +44,7 @@ class VimrcKeyRemappingBuilderImpl { private static buildKeyList(keyString: string): string[] { let keyList: string[] = []; - let matches; - + let matches: RegExpMatchArray | null = null; do { matches = VimrcKeyRemappingBuilderImpl.KEY_LIST_REG_EX.exec(keyString); if (matches) { From 1fbfa0f4d7fc4c6980cf616048b6e4d489b78c24 Mon Sep 17 00:00:00 2001 From: Jason Fields Date: Sat, 2 Nov 2019 17:12:53 -0400 Subject: [PATCH 3/9] Add `editVimrc` command --- extension.ts | 5 +++++ package.json | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/extension.ts b/extension.ts index 12e818372a0..7597601d06d 100644 --- a/extension.ts +++ b/extension.ts @@ -391,6 +391,11 @@ export async function activate(context: vscode.ExtensionContext) { toggleExtension(configuration.disableExtension, compositionState); }); + registerCommand(context, 'vim.editVimrc', async () => { + const document = await vscode.workspace.openTextDocument(configuration.vimrcPath); + await vscode.window.showTextDocument(document); + }); + for (const boundKey of configuration.boundKeyCombinations) { registerCommand(context, boundKey.command, () => handleKeyEvent(`${boundKey.key}`)); } diff --git a/package.json b/package.json index ee1c3c30456..1a3145bced5 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,10 @@ { "command": "vim.showQuickpickCmdLine", "title": "Vim: Show Command Line" + }, + { + "command": "vim.editVimrc", + "title": "Vim: Edit .vimrc" } ], "keybindings": [ From 0e1157b0305efcf80bf82221999d358fc08abb92 Mon Sep 17 00:00:00 2001 From: Jason Fields Date: Sat, 2 Nov 2019 19:00:00 -0400 Subject: [PATCH 4/9] Add .vimrc validator, correct usage of new config names --- extension.ts | 3 ++- src/configuration/configuration.ts | 8 ++++--- src/configuration/configurationValidator.ts | 2 ++ src/configuration/iconfiguration.ts | 6 +++-- .../validators/vimrcValidator.ts | 22 +++++++++++++++++++ src/configuration/vimrc.ts | 12 +++++----- test/testConfiguration.ts | 6 +++-- 7 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 src/configuration/validators/vimrcValidator.ts diff --git a/extension.ts b/extension.ts index 7597601d06d..3b5b5788450 100644 --- a/extension.ts +++ b/extension.ts @@ -87,6 +87,7 @@ async function loadConfiguration() { } } } + export async function activate(context: vscode.ExtensionContext) { // before we do anything else, // we need to load the configuration first @@ -392,7 +393,7 @@ export async function activate(context: vscode.ExtensionContext) { }); registerCommand(context, 'vim.editVimrc', async () => { - const document = await vscode.workspace.openTextDocument(configuration.vimrcPath); + const document = await vscode.workspace.openTextDocument(configuration.vimrc.path); await vscode.window.showTextDocument(document); }); diff --git a/src/configuration/configuration.ts b/src/configuration/configuration.ts index 78d5982c694..eafbd8a781b 100644 --- a/src/configuration/configuration.ts +++ b/src/configuration/configuration.ts @@ -87,7 +87,7 @@ class Configuration implements IConfiguration { } } - if (this.enableVimrc) { + if (this.vimrc.enable) { vimrc.load(this); } @@ -308,8 +308,10 @@ class Configuration implements IConfiguration { enableNeovim = false; neovimPath = ''; - enableVimrc = true; - vimrcPath = ''; + vimrc = { + enable: true, + path: '', + }; digraphs = {}; diff --git a/src/configuration/configurationValidator.ts b/src/configuration/configurationValidator.ts index 6d29ddc122e..0d7e0684cf5 100644 --- a/src/configuration/configurationValidator.ts +++ b/src/configuration/configurationValidator.ts @@ -3,6 +3,7 @@ import { IConfigurationValidator, ValidatorResults } from './iconfigurationValid import { InputMethodSwitcherConfigurationValidator } from './validators/inputMethodSwitcherValidator'; import { NeovimValidator } from './validators/neovimValidator'; import { RemappingValidator } from './validators/remappingValidator'; +import { VimrcValidator } from './validators/vimrcValidator'; class ConfigurationValidator { private _validators: IConfigurationValidator[]; @@ -12,6 +13,7 @@ class ConfigurationValidator { new InputMethodSwitcherConfigurationValidator(), new NeovimValidator(), new RemappingValidator(), + new VimrcValidator(), ]; } diff --git a/src/configuration/iconfiguration.ts b/src/configuration/iconfiguration.ts index 69e38c59d79..d9be8018e5b 100644 --- a/src/configuration/iconfiguration.ts +++ b/src/configuration/iconfiguration.ts @@ -295,8 +295,10 @@ export interface IConfiguration { /** * .vimrc */ - enableVimrc: boolean; - vimrcPath: string; + vimrc: { + enable: boolean; + path: string; + }; /** * Automatically apply the `/g` flag to substitute commands. diff --git a/src/configuration/validators/vimrcValidator.ts b/src/configuration/validators/vimrcValidator.ts new file mode 100644 index 00000000000..f3f3dcf4e8e --- /dev/null +++ b/src/configuration/validators/vimrcValidator.ts @@ -0,0 +1,22 @@ +import * as fs from 'fs'; +import { IConfiguration } from "../iconfiguration"; +import { IConfigurationValidator, ValidatorResults } from "../iconfigurationValidator"; + +export class VimrcValidator implements IConfigurationValidator { + async validate(config: IConfiguration): Promise { + const result = new ValidatorResults(); + + if (config.vimrc.enable && !fs.existsSync(config.vimrc.path) ) { + result.append({ + level: 'error', + message: `.vimrc not found at ${config.vimrc.path}` + }); + } + + return result; + } + + disable(config: IConfiguration): void { + // no-op + } +} \ No newline at end of file diff --git a/src/configuration/vimrc.ts b/src/configuration/vimrc.ts index 9370c008eb8..0e1e1059a88 100644 --- a/src/configuration/vimrc.ts +++ b/src/configuration/vimrc.ts @@ -6,19 +6,19 @@ import { vimrcKeyRemappingBuilder } from './vimrcKeyRemappingBuilder'; class VimrcImpl { public load(configuration: IConfiguration) { - if (configuration.vimrcPath) { - configuration.vimrcPath = VimrcImpl.expandHome(configuration.vimrcPath); - if (!fs.existsSync(configuration.vimrcPath)) { + if (configuration.vimrc.path) { + configuration.vimrc.path = VimrcImpl.expandHome(configuration.vimrc.path); + if (!fs.existsSync(configuration.vimrc.path)) { return; } } else { - configuration.vimrcPath = VimrcImpl.findDefaultVimrc(); - if (!configuration.vimrcPath) { + configuration.vimrc.path = VimrcImpl.findDefaultVimrc(); + if (!configuration.vimrc.path) { return; } } - let vimrcContent = fs.readFileSync(configuration.vimrcPath, { encoding: 'utf8' }); + let vimrcContent = fs.readFileSync(configuration.vimrc.path, { encoding: 'utf8' }); let lines = vimrcContent.split(/\r?\n/); for (const line of lines) { diff --git a/test/testConfiguration.ts b/test/testConfiguration.ts index 675dcade28f..1208fb5930f 100644 --- a/test/testConfiguration.ts +++ b/test/testConfiguration.ts @@ -84,8 +84,10 @@ export class Configuration implements IConfiguration { gdefault = false; substituteGlobalFlag = false; // Deprecated in favor of gdefault neovimPath = 'nvim'; - enableVimrc = false; - vimrcPath = ''; + vimrc = { + enable: false, + path: '', + }; cursorStylePerMode: IModeSpecificStrings = { normal: 'line', insert: 'block', From 1420db19d49194652ea5febe8394c8872ed60b9a Mon Sep 17 00:00:00 2001 From: Jason Fields Date: Sat, 2 Nov 2019 19:04:53 -0400 Subject: [PATCH 5/9] Don't return boolean from addKeyRemapping unnecessarily --- src/configuration/vimrc.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/configuration/vimrc.ts b/src/configuration/vimrc.ts index 0e1e1059a88..ca1cb4c5529 100644 --- a/src/configuration/vimrc.ts +++ b/src/configuration/vimrc.ts @@ -22,14 +22,14 @@ class VimrcImpl { let lines = vimrcContent.split(/\r?\n/); for (const line of lines) { - VimrcImpl.tryKeyRemapping(configuration, line); + VimrcImpl.addKeyRemapping(configuration, line); } } - private static tryKeyRemapping(configuration: IConfiguration, line: string): boolean { + private static addKeyRemapping(configuration: IConfiguration, line: string): void { let mapping: IVimrcKeyRemapping | null = vimrcKeyRemappingBuilder.build(line); if (!mapping) { - return false; + return; } let collection: IKeyRemapping[]; @@ -53,15 +53,13 @@ class VimrcImpl { collection = configuration.insertModeKeyBindingsNonRecursive; break; default: - return false; + return; } // Don't override a mapping present in settings.json; those are more specific to VSCodeVim. if (!collection.some(r => _.isEqual(r.before, mapping!.keyRemapping.before))) { collection.push(mapping.keyRemapping); } - - return true; } private static findDefaultVimrc(): string { From 9d187340555275e374f939eb81ce8da35d7bf044 Mon Sep 17 00:00:00 2001 From: Jason Fields Date: Sat, 2 Nov 2019 19:09:39 -0400 Subject: [PATCH 6/9] Small refactor --- src/configuration/vimrc.ts | 21 ++++++++++--------- src/configuration/vimrcKeyRemappingBuilder.ts | 4 ++-- .../vimrcKeyRemappingBuilder.test.ts | 21 ++++++++++--------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/configuration/vimrc.ts b/src/configuration/vimrc.ts index ca1cb4c5529..adf83939cbb 100644 --- a/src/configuration/vimrc.ts +++ b/src/configuration/vimrc.ts @@ -22,18 +22,19 @@ class VimrcImpl { let lines = vimrcContent.split(/\r?\n/); for (const line of lines) { - VimrcImpl.addKeyRemapping(configuration, line); + const remap: IVimrcKeyRemapping | undefined = vimrcKeyRemappingBuilder.build(line); + if (remap) { + VimrcImpl.addRemapToConfig(configuration, remap); + } } } - private static addKeyRemapping(configuration: IConfiguration, line: string): void { - let mapping: IVimrcKeyRemapping | null = vimrcKeyRemappingBuilder.build(line); - if (!mapping) { - return; - } - + /** + * Adds a remapping from .vimrc to the given configuration + */ + private static addRemapToConfig(configuration: IConfiguration, remap: IVimrcKeyRemapping): void { let collection: IKeyRemapping[]; - switch (mapping.keyRemappingType) { + switch (remap.keyRemappingType) { case 'nmap': collection = configuration.normalModeKeyBindings; break; @@ -57,8 +58,8 @@ class VimrcImpl { } // Don't override a mapping present in settings.json; those are more specific to VSCodeVim. - if (!collection.some(r => _.isEqual(r.before, mapping!.keyRemapping.before))) { - collection.push(mapping.keyRemapping); + if (!collection.some(r => _.isEqual(r.before, remap!.keyRemapping.before))) { + collection.push(remap.keyRemapping); } } diff --git a/src/configuration/vimrcKeyRemappingBuilder.ts b/src/configuration/vimrcKeyRemappingBuilder.ts index 528e532a783..30c21dab8f9 100644 --- a/src/configuration/vimrcKeyRemappingBuilder.ts +++ b/src/configuration/vimrcKeyRemappingBuilder.ts @@ -5,10 +5,10 @@ class VimrcKeyRemappingBuilderImpl { private static readonly KEY_LIST_REG_EX = /(<[^>]+>|.)/g; private static readonly COMMAND_REG_EX = /(:\w+)/; - public build(line: string): IVimrcKeyRemapping | null { + public build(line: string): IVimrcKeyRemapping | undefined { const matches = VimrcKeyRemappingBuilderImpl.KEY_REMAPPING_REG_EX.exec(line); if (!matches || matches.length < 4) { - return null; + return undefined; } const type = matches[1]; diff --git a/test/configuration/vimrcKeyRemappingBuilder.test.ts b/test/configuration/vimrcKeyRemappingBuilder.test.ts index a7f6eff2fd9..e3e2a33629d 100644 --- a/test/configuration/vimrcKeyRemappingBuilder.test.ts +++ b/test/configuration/vimrcKeyRemappingBuilder.test.ts @@ -12,7 +12,7 @@ suite('VimrcKeyRemappingBuilder', () => { after: ['<', '<'], }, keyRemappingType: 'nnoremap', - expectNull: false + expectNull: false, }, { vimrcLine: 'imap jj ', @@ -21,7 +21,7 @@ suite('VimrcKeyRemappingBuilder', () => { after: [''], }, keyRemappingType: 'imap', - expectNull: false + expectNull: false, }, { vimrcLine: 'vnoremap " c""P', @@ -30,7 +30,7 @@ suite('VimrcKeyRemappingBuilder', () => { after: ['c', '"', '"', '', 'P'], }, keyRemappingType: 'vnoremap', - expectNull: false + expectNull: false, }, { // Mapping with a command @@ -40,24 +40,25 @@ suite('VimrcKeyRemappingBuilder', () => { commands: [':w'], }, keyRemappingType: 'nnoremap', - expectNull: false + expectNull: false, }, { // Ignore non-mapping lines vimrcLine: 'set scrolloff=8', - expectNull: true + expectNull: true, }, ]; for (const testCase of testCases) { - let vimrcKeyRemapping: IVimrcKeyRemapping | null = - vimrcKeyRemappingBuilder.build(testCase.vimrcLine); + const vimrcKeyRemapping: IVimrcKeyRemapping | undefined = vimrcKeyRemappingBuilder.build( + testCase.vimrcLine + ); if (testCase.expectNull) { - assert.equal(vimrcKeyRemapping, null); + assert.strictEqual(vimrcKeyRemapping, undefined); } else { - assert.deepEqual(vimrcKeyRemapping!.keyRemapping, testCase.keyRemapping); - assert.equal(vimrcKeyRemapping!.keyRemappingType, testCase.keyRemappingType); + assert.deepStrictEqual(vimrcKeyRemapping!.keyRemapping, testCase.keyRemapping); + assert.strictEqual(vimrcKeyRemapping!.keyRemappingType, testCase.keyRemappingType); } } }); From 0752ee871e0e7665847ce792eeba6be6423f65c0 Mon Sep 17 00:00:00 2001 From: Jason Fields Date: Sat, 2 Nov 2019 19:30:47 -0400 Subject: [PATCH 7/9] Source .vimrc automatically after saving it --- extension.ts | 12 ++++++++++++ src/configuration/vimrcKeyRemappingBuilder.ts | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/extension.ts b/extension.ts index 3b5b5788450..fe1619b60f3 100644 --- a/extension.ts +++ b/extension.ts @@ -6,6 +6,7 @@ import './src/actions/include-all'; import * as vscode from 'vscode'; +import * as path from 'path'; import { CompositionState } from './src/state/compositionState'; import { EditorIdentity } from './src/editorIdentity'; @@ -24,6 +25,7 @@ import { configuration } from './src/configuration/configuration'; import { globalState } from './src/state/globalState'; import { taskQueue } from './src/taskQueue'; import { Register } from './src/register/register'; +import { vimrc } from './src/configuration/vimrc'; let extensionContext: vscode.ExtensionContext; let previousActiveEditorId: EditorIdentity | null = null; @@ -208,6 +210,16 @@ export async function activate(context: vscode.ExtensionContext) { false ); + registerEventListener(context, vscode.workspace.onDidSaveTextDocument, async document => { + if ( + configuration.vimrc.enable && + path.relative(document.fileName, configuration.vimrc.path) === '' + ) { + await configuration.load(); + vscode.window.showInformationMessage('Sourced new .vimrc'); + } + }); + // window events registerEventListener( context, diff --git a/src/configuration/vimrcKeyRemappingBuilder.ts b/src/configuration/vimrcKeyRemappingBuilder.ts index 30c21dab8f9..17335ca3c84 100644 --- a/src/configuration/vimrcKeyRemappingBuilder.ts +++ b/src/configuration/vimrcKeyRemappingBuilder.ts @@ -5,6 +5,9 @@ class VimrcKeyRemappingBuilderImpl { private static readonly KEY_LIST_REG_EX = /(<[^>]+>|.)/g; private static readonly COMMAND_REG_EX = /(:\w+)/; + /** + * @returns A remapping if the given `line` parses to one, and `undefined` otherwise. + */ public build(line: string): IVimrcKeyRemapping | undefined { const matches = VimrcKeyRemappingBuilderImpl.KEY_REMAPPING_REG_EX.exec(line); if (!matches || matches.length < 4) { @@ -34,6 +37,9 @@ class VimrcKeyRemappingBuilderImpl { }; } + /** + * @returns `true` if this remaps a key sequence to a `:` command + */ private static isCommand(commandString: string): boolean { const matches = VimrcKeyRemappingBuilderImpl.COMMAND_REG_EX.exec(commandString); if (matches) { From 1e2bdb63a6527de6ac166148987551f193877c6a Mon Sep 17 00:00:00 2001 From: Jason Fields Date: Mon, 4 Nov 2019 01:48:12 -0500 Subject: [PATCH 8/9] Changes from code review, delete old .vimrc mappings before reading new ones when sourcing --- README.md | 8 +- src/configuration/configuration.ts | 2 +- src/configuration/iconfiguration.ts | 1 + .../validators/vimrcValidator.ts | 11 +- src/configuration/vimrc.ts | 113 ++++++++++-------- src/configuration/vimrcKeyRemappingBuilder.ts | 2 + .../vimrcKeyRemappingBuilder.test.ts | 4 + 7 files changed, 83 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 216d93950ff..a801996fadf 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,6 @@ VSCodeVim is a Vim emulator for [Visual Studio Code](https://code.visualstudio.c VSCodeVim is automatically enabled following [installation](https://marketplace.visualstudio.com/items?itemName=vscodevim.vim) and reloading of VS Code. -> :warning: Vimscript is _not_ supported; therefore, we are _not_ able to load your `.vimrc` or use `.vim` plugins. You have to replicate these using our [Settings](#settings) and [Emulated plugins](#-emulated-plugins). - ### Mac To enable key-repeating execute the following in your Terminal and restart VS Code: @@ -365,6 +363,12 @@ Configuration settings that have been copied from vim. Vim settings are loaded i | vim.whichwrap | Controls wrapping at beginning and end of line. Comma-separated set of keys that should wrap to next/previous line. Arrow keys are represented by `[` and `]` in insert mode, `<` and `>` in normal and visual mode. To wrap "everything", set this to `h,l,<,>,[,]`. | String | `` | | vim.report | Threshold for reporting number of lines changed. | Number | 2 | +## .vimrc support + +> :warning: .vimrc support is currently experimental. Only remaps are supported, and you may experience bugs. Please [report them](https://github.com/VSCodeVim/Vim/issues/new?template=bug_report.md)! + +Set `vim.vimrc.enable` to `true` and set `vim.vimrc.path` appropriately. + ## 🖱️ Multi-Cursor Mode > :warning: Multi-Cursor mode is experimental. Please report issues in our [feedback thread.](https://github.com/VSCodeVim/Vim/issues/824) diff --git a/src/configuration/configuration.ts b/src/configuration/configuration.ts index eafbd8a781b..7d0dde4261b 100644 --- a/src/configuration/configuration.ts +++ b/src/configuration/configuration.ts @@ -309,7 +309,7 @@ class Configuration implements IConfiguration { neovimPath = ''; vimrc = { - enable: true, + enable: false, path: '', }; diff --git a/src/configuration/iconfiguration.ts b/src/configuration/iconfiguration.ts index d9be8018e5b..81db1b10da8 100644 --- a/src/configuration/iconfiguration.ts +++ b/src/configuration/iconfiguration.ts @@ -15,6 +15,7 @@ export interface IKeyRemapping { before: string[]; after?: string[]; commands?: ({ command: string; args: any[] } | string)[]; + source?: 'vscode' | 'vimrc'; } export interface IVimrcKeyRemapping { diff --git a/src/configuration/validators/vimrcValidator.ts b/src/configuration/validators/vimrcValidator.ts index f3f3dcf4e8e..09498daec24 100644 --- a/src/configuration/validators/vimrcValidator.ts +++ b/src/configuration/validators/vimrcValidator.ts @@ -1,15 +1,16 @@ import * as fs from 'fs'; -import { IConfiguration } from "../iconfiguration"; -import { IConfigurationValidator, ValidatorResults } from "../iconfigurationValidator"; +import { IConfiguration } from '../iconfiguration'; +import { IConfigurationValidator, ValidatorResults } from '../iconfigurationValidator'; +import { vimrc } from '../vimrc'; export class VimrcValidator implements IConfigurationValidator { async validate(config: IConfiguration): Promise { const result = new ValidatorResults(); - if (config.vimrc.enable && !fs.existsSync(config.vimrc.path) ) { + if (config.vimrc.enable && !fs.existsSync(vimrc.vimrcPath)) { result.append({ level: 'error', - message: `.vimrc not found at ${config.vimrc.path}` + message: `.vimrc not found at ${config.vimrc.path}`, }); } @@ -19,4 +20,4 @@ export class VimrcValidator implements IConfigurationValidator { disable(config: IConfiguration): void { // no-op } -} \ No newline at end of file +} diff --git a/src/configuration/vimrc.ts b/src/configuration/vimrc.ts index adf83939cbb..2f3104d3d4c 100644 --- a/src/configuration/vimrc.ts +++ b/src/configuration/vimrc.ts @@ -1,30 +1,34 @@ import * as _ from 'lodash'; import * as fs from 'fs'; import * as path from 'path'; -import { IConfiguration, IKeyRemapping, IVimrcKeyRemapping } from './iconfiguration'; +import { IConfiguration, IVimrcKeyRemapping } from './iconfiguration'; import { vimrcKeyRemappingBuilder } from './vimrcKeyRemappingBuilder'; class VimrcImpl { - public load(configuration: IConfiguration) { - if (configuration.vimrc.path) { - configuration.vimrc.path = VimrcImpl.expandHome(configuration.vimrc.path); - if (!fs.existsSync(configuration.vimrc.path)) { - return; - } - } else { - configuration.vimrc.path = VimrcImpl.findDefaultVimrc(); - if (!configuration.vimrc.path) { - return; - } + private _vimrcPath: string; + public get vimrcPath(): string { + return this._vimrcPath; + } + + public load(config: IConfiguration) { + const _path = config.vimrc.path + ? VimrcImpl.expandHome(config.vimrc.path) + : VimrcImpl.findDefaultVimrc(); + if (!_path || !fs.existsSync(_path)) { + // TODO: we may want to offer to create the file for them + throw new Error(`Unable to find .vimrc file`); } + this._vimrcPath = _path; - let vimrcContent = fs.readFileSync(configuration.vimrc.path, { encoding: 'utf8' }); - let lines = vimrcContent.split(/\r?\n/); + // Remove all the old remappings from the .vimrc file + VimrcImpl.removeAllRemapsFromConfig(config); + // Add the new remappings + const lines = fs.readFileSync(config.vimrc.path, { encoding: 'utf8' }).split(/\r?\n/); for (const line of lines) { - const remap: IVimrcKeyRemapping | undefined = vimrcKeyRemappingBuilder.build(line); + const remap = vimrcKeyRemappingBuilder.build(line); if (remap) { - VimrcImpl.addRemapToConfig(configuration, remap); + VimrcImpl.addRemapToConfig(config, remap); } } } @@ -32,51 +36,60 @@ class VimrcImpl { /** * Adds a remapping from .vimrc to the given configuration */ - private static addRemapToConfig(configuration: IConfiguration, remap: IVimrcKeyRemapping): void { - let collection: IKeyRemapping[]; - switch (remap.keyRemappingType) { - case 'nmap': - collection = configuration.normalModeKeyBindings; - break; - case 'vmap': - collection = configuration.visualModeKeyBindings; - break; - case 'imap': - collection = configuration.insertModeKeyBindings; - break; - case 'nnoremap': - collection = configuration.normalModeKeyBindingsNonRecursive; - break; - case 'vnoremap': - collection = configuration.visualModeKeyBindingsNonRecursive; - break; - case 'inoremap': - collection = configuration.insertModeKeyBindingsNonRecursive; - break; - default: - return; - } + private static addRemapToConfig(config: IConfiguration, remap: IVimrcKeyRemapping): void { + const remaps = (() => { + switch (remap.keyRemappingType) { + case 'nmap': + return config.normalModeKeyBindings; + case 'vmap': + return config.visualModeKeyBindings; + case 'imap': + return config.insertModeKeyBindings; + case 'nnoremap': + return config.normalModeKeyBindingsNonRecursive; + case 'vnoremap': + return config.visualModeKeyBindingsNonRecursive; + case 'inoremap': + return config.insertModeKeyBindingsNonRecursive; + default: + return undefined; + } + })(); // Don't override a mapping present in settings.json; those are more specific to VSCodeVim. - if (!collection.some(r => _.isEqual(r.before, remap!.keyRemapping.before))) { - collection.push(remap.keyRemapping); + if (remaps && !remaps.some(r => _.isEqual(r.before, remap!.keyRemapping.before))) { + remaps.push(remap.keyRemapping); } } - private static findDefaultVimrc(): string { - if (!process.env.HOME) { - return ''; + private static removeAllRemapsFromConfig(config: IConfiguration): void { + const remapCollections = [ + config.normalModeKeyBindings, + config.visualModeKeyBindings, + config.insertModeKeyBindings, + config.normalModeKeyBindingsNonRecursive, + config.visualModeKeyBindingsNonRecursive, + config.insertModeKeyBindingsNonRecursive, + ]; + for (const remaps of remapCollections) { + _.remove(remaps, remap => remap.source === 'vimrc'); } + } + + private static findDefaultVimrc(): string | undefined { + if (process.env.HOME) { + let vimrcPath = path.join(process.env.HOME, '.vimrc'); + if (fs.existsSync(vimrcPath)) { + return vimrcPath; + } - let vimrcPath = path.join(process.env.HOME, '.vimrc'); - if (!fs.existsSync(vimrcPath)) { vimrcPath = path.join(process.env.HOME, '_vimrc'); - if (!fs.existsSync(vimrcPath)) { - return ''; + if (fs.existsSync(vimrcPath)) { + return vimrcPath; } } - return vimrcPath; + return undefined; } private static expandHome(filePath: string): string { diff --git a/src/configuration/vimrcKeyRemappingBuilder.ts b/src/configuration/vimrcKeyRemappingBuilder.ts index 17335ca3c84..25459b72cac 100644 --- a/src/configuration/vimrcKeyRemappingBuilder.ts +++ b/src/configuration/vimrcKeyRemappingBuilder.ts @@ -23,11 +23,13 @@ class VimrcKeyRemappingBuilderImpl { mapping = { before: VimrcKeyRemappingBuilderImpl.buildKeyList(before), commands: [after], + source: 'vimrc', }; } else { mapping = { before: VimrcKeyRemappingBuilderImpl.buildKeyList(before), after: VimrcKeyRemappingBuilderImpl.buildKeyList(after), + source: 'vimrc', }; } diff --git a/test/configuration/vimrcKeyRemappingBuilder.test.ts b/test/configuration/vimrcKeyRemappingBuilder.test.ts index e3e2a33629d..37e2e4c0377 100644 --- a/test/configuration/vimrcKeyRemappingBuilder.test.ts +++ b/test/configuration/vimrcKeyRemappingBuilder.test.ts @@ -10,6 +10,7 @@ suite('VimrcKeyRemappingBuilder', () => { keyRemapping: { before: [''], after: ['<', '<'], + source: 'vimrc', }, keyRemappingType: 'nnoremap', expectNull: false, @@ -19,6 +20,7 @@ suite('VimrcKeyRemappingBuilder', () => { keyRemapping: { before: ['j', 'j'], after: [''], + source: 'vimrc', }, keyRemappingType: 'imap', expectNull: false, @@ -28,6 +30,7 @@ suite('VimrcKeyRemappingBuilder', () => { keyRemapping: { before: ['', '"'], after: ['c', '"', '"', '', 'P'], + source: 'vimrc', }, keyRemappingType: 'vnoremap', expectNull: false, @@ -38,6 +41,7 @@ suite('VimrcKeyRemappingBuilder', () => { keyRemapping: { before: [''], commands: [':w'], + source: 'vimrc', }, keyRemappingType: 'nnoremap', expectNull: false, From ef2a8df794e7e01e8c93e68aa580dd99da4ac547 Mon Sep 17 00:00:00 2001 From: Jason Fields Date: Sat, 9 Nov 2019 23:04:58 -0500 Subject: [PATCH 9/9] forceprettier --- build/CHANGELOG.base.md | 2 +- src/cmd_line/subparsers/sort.ts | 6 +++++- test/cmd_line/command.test.ts | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/build/CHANGELOG.base.md b/build/CHANGELOG.base.md index a7f519b7875..f8556afcbb8 100644 --- a/build/CHANGELOG.base.md +++ b/build/CHANGELOG.base.md @@ -2848,4 +2848,4 @@ The first commit to this project was a little over 3 years ago, and what a journ - add gulp + tslint [\#6](https://github.com/VSCodeVim/Vim/pull/6) ([jpoon](https://github.com/jpoon)) - command line mode refactoring [\#5](https://github.com/VSCodeVim/Vim/pull/5) ([guillermooo](https://github.com/guillermooo)) - Navigation mode [\#4](https://github.com/VSCodeVim/Vim/pull/4) ([jpoon](https://github.com/jpoon)) -- Add ex mode [\#3](https://github.com/VSCodeVim/Vim/pull/3) ([guillermooo](https://github.com/guillermooo)) \ No newline at end of file +- Add ex mode [\#3](https://github.com/VSCodeVim/Vim/pull/3) ([guillermooo](https://github.com/guillermooo)) diff --git a/src/cmd_line/subparsers/sort.ts b/src/cmd_line/subparsers/sort.ts index 19a561e11e8..85afca2c8a8 100644 --- a/src/cmd_line/subparsers/sort.ts +++ b/src/cmd_line/subparsers/sort.ts @@ -6,7 +6,11 @@ export function parseSortCommandArgs(args: string): node.SortCommand { return new node.SortCommand({ reverse: false, ignoreCase: false, unique: false }); } - let scannedArgs: node.ISortCommandArguments = { reverse: false, ignoreCase: false, unique: false }; + let scannedArgs: node.ISortCommandArguments = { + reverse: false, + ignoreCase: false, + unique: false, + }; let scanner = new Scanner(args); const c = scanner.next(); scannedArgs.reverse = c === '!'; diff --git a/test/cmd_line/command.test.ts b/test/cmd_line/command.test.ts index a60463e3193..2afa91cb521 100644 --- a/test/cmd_line/command.test.ts +++ b/test/cmd_line/command.test.ts @@ -161,7 +161,7 @@ suite('cmd_line/search command', () => { await modeHandler.handleMultipleKeyEvents(['', ':', '', '']); const statusBar = StatusBar.Get().trim(); assert.equal(statusBar, ':abc|', 'Failed to insert word'); - }); + }); test(' insert right word of cursor on command line', async () => { await modeHandler.handleMultipleKeyEvents('i::abc'.split(''));