mirror of
https://github.com/jasonwilliams/vscode-helix.git
synced 2024-10-06 13:17:15 +03:00
format with prettier
This commit is contained in:
parent
14b5c79d36
commit
dab8857c6a
27
.eslintrc.cjs
Normal file
27
.eslintrc.cjs
Normal file
@ -0,0 +1,27 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
|
||||
plugins: ['@typescript-eslint'],
|
||||
ignorePatterns: ['*.cjs'],
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020,
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true,
|
||||
},
|
||||
rules: {
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'warn', // or "error"
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
||||
.DS_Store
|
||||
out
|
||||
dist/
|
||||
node_modules
|
||||
.vscode-test/
|
||||
.vsix
|
||||
|
@ -2,7 +2,7 @@
|
||||
"printWidth": 100,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"trailingComma": "all",
|
||||
"arrowParens": "always",
|
||||
"pluginSearchDirs": ["."]
|
||||
}
|
||||
|
3177
dist/index.js
vendored
3177
dist/index.js
vendored
File diff suppressed because it is too large
Load Diff
24
package-lock.json
generated
24
package-lock.json
generated
@ -13,8 +13,11 @@
|
||||
"@types/http-errors": "^1.8.0",
|
||||
"@types/node": "^16.14.2",
|
||||
"@types/vscode": "^1.69.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.42.1",
|
||||
"@typescript-eslint/parser": "^5.42.1",
|
||||
"bumpp": "^8.2.1",
|
||||
"eslint": "^8.21.0",
|
||||
"eslint": "^8.27.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"esno": "^0.16.3",
|
||||
"prettier": "^2.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
@ -1989,6 +1992,18 @@
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-prettier": {
|
||||
"version": "8.5.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
|
||||
"integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-import-resolver-node": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
|
||||
@ -7713,6 +7728,13 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-config-prettier": {
|
||||
"version": "8.5.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
|
||||
"integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"eslint-import-resolver-node": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
|
||||
|
12
package.json
12
package.json
@ -76,22 +76,24 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --external vscode",
|
||||
"dev": "npm run build --watch",
|
||||
"dev": "npm run build -- --watch",
|
||||
"pack": "vsce package --no-dependencies",
|
||||
"publish": "vsce publish --no-dependencies",
|
||||
"vscode:prepublish": "npm run build",
|
||||
"lint": "prettier --check --plugin-search-dir=. . && eslint .",
|
||||
"format": "prettier --write --plugin-search-dir=. .",
|
||||
"lint": "prettier --check --plugin-search-dir=. src && eslint src",
|
||||
"format": "prettier --write --plugin-search-dir=. src",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"release": "bumpp && nr publish"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^0.25.2",
|
||||
"@types/http-errors": "^1.8.0",
|
||||
"@types/node": "^16.14.2",
|
||||
"@types/vscode": "^1.69.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.42.1",
|
||||
"@typescript-eslint/parser": "^5.42.1",
|
||||
"bumpp": "^8.2.1",
|
||||
"eslint": "^8.21.0",
|
||||
"eslint": "^8.27.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"esno": "^0.16.3",
|
||||
"prettier": "^2.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
@ -1,10 +1,10 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { VimState } from "./vim_state_types";
|
||||
import { ParseKeysStatus } from "./parse_keys_types";
|
||||
import { VimState } from './vim_state_types'
|
||||
import { ParseKeysStatus } from './parse_keys_types'
|
||||
|
||||
export type Action = (
|
||||
vimState: VimState,
|
||||
keys: string[],
|
||||
editor: vscode.TextEditor
|
||||
) => ParseKeysStatus;
|
||||
editor: vscode.TextEditor,
|
||||
) => ParseKeysStatus
|
||||
|
@ -1,132 +1,129 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { Mode } from "../modes_types";
|
||||
import { Action } from "../action_types";
|
||||
import { parseKeysExact, parseKeysRegex } from "../parse_keys";
|
||||
import { Mode } from '../modes_types'
|
||||
import { Action } from '../action_types'
|
||||
import { parseKeysExact, parseKeysRegex } from '../parse_keys'
|
||||
import {
|
||||
enterInsertMode,
|
||||
enterVisualMode,
|
||||
enterVisualLineMode,
|
||||
enterOccurrenceMode,
|
||||
setModeCursorStyle
|
||||
} from "../modes";
|
||||
import * as positionUtils from "../position_utils";
|
||||
import { removeTypeSubscription } from "../type_subscription";
|
||||
import { VimState } from "../vim_state_types";
|
||||
import { setVisualLineSelections } from "../visual_line_utils";
|
||||
import { flashYankHighlight } from "../yank_highlight";
|
||||
import { putAfter } from "../put_utils/put_after";
|
||||
import { putBefore } from "../put_utils/put_before";
|
||||
import { yank } from "./operators";
|
||||
import KeyMap from "./keymaps";
|
||||
setModeCursorStyle,
|
||||
} from '../modes'
|
||||
import * as positionUtils from '../position_utils'
|
||||
import { removeTypeSubscription } from '../type_subscription'
|
||||
import { VimState } from '../vim_state_types'
|
||||
import { setVisualLineSelections } from '../visual_line_utils'
|
||||
import { flashYankHighlight } from '../yank_highlight'
|
||||
import { putAfter } from '../put_utils/put_after'
|
||||
import { putBefore } from '../put_utils/put_before'
|
||||
import { yank } from './operators'
|
||||
import KeyMap from './keymaps'
|
||||
|
||||
enum Direction {
|
||||
Up,
|
||||
Down
|
||||
Down,
|
||||
}
|
||||
|
||||
/* eslint @typescript-eslint/no-unused-vars: 0 */
|
||||
export const actions: Action[] = [
|
||||
parseKeysExact([":"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("workbench.action.gotoLine");
|
||||
parseKeysExact([':'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('workbench.action.gotoLine')
|
||||
}),
|
||||
|
||||
parseKeysExact(["m", "l"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("bookmarks.list");
|
||||
parseKeysExact(['m', 'l'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('bookmarks.list')
|
||||
}),
|
||||
|
||||
parseKeysExact(["m", "L"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("bookmarks.listFromAllFiles");
|
||||
parseKeysExact(['m', 'L'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('bookmarks.listFromAllFiles')
|
||||
}),
|
||||
|
||||
parseKeysExact(["m", "i"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("bookmarks.jumpToPrevious");
|
||||
parseKeysExact(['m', 'i'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('bookmarks.jumpToPrevious')
|
||||
}),
|
||||
|
||||
parseKeysExact(["m", "k"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("bookmarks.jumpToNext");
|
||||
parseKeysExact(['m', 'k'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('bookmarks.jumpToNext')
|
||||
}),
|
||||
|
||||
parseKeysExact(["m", "m"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("bookmarks.toggle");
|
||||
parseKeysExact(['m', 'm'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('bookmarks.toggle')
|
||||
}),
|
||||
|
||||
// new space actions
|
||||
parseKeysExact([" ", " "], [Mode.Normal], (vimState, editor) => {
|
||||
enterOccurrenceMode(vimState);
|
||||
vscode.commands.executeCommand("editor.action.addSelectionToNextFindMatch");
|
||||
parseKeysExact([' ', ' '], [Mode.Normal], (vimState, editor) => {
|
||||
enterOccurrenceMode(vimState)
|
||||
vscode.commands.executeCommand('editor.action.addSelectionToNextFindMatch')
|
||||
}),
|
||||
|
||||
parseKeysExact(["p"], [Mode.Occurrence], (vimState, editor) => {
|
||||
vscode.commands.executeCommand(
|
||||
"editor.action.addSelectionToPreviousFindMatch"
|
||||
);
|
||||
parseKeysExact(['p'], [Mode.Occurrence], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.addSelectionToPreviousFindMatch')
|
||||
}),
|
||||
|
||||
parseKeysExact(["n"], [Mode.Occurrence], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("editor.action.addSelectionToNextFindMatch");
|
||||
parseKeysExact(['n'], [Mode.Occurrence], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.addSelectionToNextFindMatch')
|
||||
}),
|
||||
|
||||
parseKeysExact(["a"], [Mode.Occurrence], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("editor.action.selectHighlights");
|
||||
parseKeysExact(['a'], [Mode.Occurrence], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.selectHighlights')
|
||||
}),
|
||||
|
||||
parseKeysExact([" ", "z"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("undo");
|
||||
parseKeysExact([' ', 'z'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('undo')
|
||||
}),
|
||||
|
||||
parseKeysExact([" ", "r"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("redo");
|
||||
parseKeysExact([' ', 'r'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('redo')
|
||||
}),
|
||||
|
||||
parseKeysExact([" ", "i"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("extension.simpleVim.scrollUpHalfPage");
|
||||
parseKeysExact([' ', 'i'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('extension.simpleVim.scrollUpHalfPage')
|
||||
}),
|
||||
|
||||
parseKeysExact([" ", "k"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("extension.simpleVim.scrollDownHalfPage");
|
||||
parseKeysExact([' ', 'k'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('extension.simpleVim.scrollDownHalfPage')
|
||||
}),
|
||||
|
||||
// new G actions
|
||||
parseKeysExact(["g", "l"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand(
|
||||
"workbench.action.navigateToLastEditLocation"
|
||||
);
|
||||
parseKeysExact(['g', 'l'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('workbench.action.navigateToLastEditLocation')
|
||||
}),
|
||||
|
||||
parseKeysExact(["g", "R"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("references-view.find");
|
||||
parseKeysExact(['g', 'R'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('references-view.find')
|
||||
}),
|
||||
|
||||
parseKeysExact(["g", "r"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("editor.action.referenceSearch.trigger");
|
||||
parseKeysExact(['g', 'r'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.referenceSearch.trigger')
|
||||
}),
|
||||
|
||||
parseKeysExact(["g", "d"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("editor.action.revealDefinition");
|
||||
parseKeysExact(['g', 'd'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.revealDefinition')
|
||||
}),
|
||||
|
||||
parseKeysExact(["g", "D"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("editor.action.revealDefinitionAside");
|
||||
parseKeysExact(['g', 'D'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.revealDefinitionAside')
|
||||
}),
|
||||
|
||||
parseKeysExact(["g", "p"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("editor.action.peekDefinition");
|
||||
parseKeysExact(['g', 'p'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.peekDefinition')
|
||||
}),
|
||||
|
||||
parseKeysExact(["g", "s"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("extension.dash.specific");
|
||||
parseKeysExact(['g', 's'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('extension.dash.specific')
|
||||
}),
|
||||
|
||||
parseKeysExact(["g", "h"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("editor.action.showHover");
|
||||
parseKeysExact(['g', 'h'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.showHover')
|
||||
}),
|
||||
|
||||
parseKeysExact(["g", "U"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("editor.action.transformToUppercase");
|
||||
parseKeysExact(['g', 'U'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.transformToUppercase')
|
||||
}),
|
||||
|
||||
parseKeysExact(["g", "u"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("editor.action.transformToLowercase");
|
||||
parseKeysExact(['g', 'u'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.transformToLowercase')
|
||||
}),
|
||||
|
||||
// existing
|
||||
@ -134,109 +131,89 @@ export const actions: Action[] = [
|
||||
[KeyMap.Actions.InsertMode],
|
||||
[Mode.Normal, Mode.Visual, Mode.VisualLine, Mode.Occurrence],
|
||||
(vimState, editor) => {
|
||||
enterInsertMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
removeTypeSubscription(vimState);
|
||||
}
|
||||
enterInsertMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
removeTypeSubscription(vimState)
|
||||
},
|
||||
),
|
||||
|
||||
parseKeysExact(
|
||||
[KeyMap.Actions.InsertAtLineStart],
|
||||
[Mode.Normal],
|
||||
(vimState, editor) => {
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
const character = editor.document.lineAt(selection.active.line)
|
||||
.firstNonWhitespaceCharacterIndex;
|
||||
const newPosition = selection.active.with({ character: character });
|
||||
return new vscode.Selection(newPosition, newPosition);
|
||||
});
|
||||
parseKeysExact([KeyMap.Actions.InsertAtLineStart], [Mode.Normal], (vimState, editor) => {
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
const character = editor.document.lineAt(
|
||||
selection.active.line,
|
||||
).firstNonWhitespaceCharacterIndex
|
||||
const newPosition = selection.active.with({ character: character })
|
||||
return new vscode.Selection(newPosition, newPosition)
|
||||
})
|
||||
|
||||
enterInsertMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
removeTypeSubscription(vimState);
|
||||
}
|
||||
),
|
||||
|
||||
parseKeysExact(["a"], [Mode.Normal], (vimState, editor) => {
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
const newPosition = positionUtils.right(
|
||||
editor.document,
|
||||
selection.active
|
||||
);
|
||||
return new vscode.Selection(newPosition, newPosition);
|
||||
});
|
||||
|
||||
enterInsertMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
removeTypeSubscription(vimState);
|
||||
enterInsertMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
removeTypeSubscription(vimState)
|
||||
}),
|
||||
|
||||
parseKeysExact(
|
||||
[KeyMap.Actions.InsertAtLineEnd],
|
||||
[Mode.Normal],
|
||||
(vimState, editor) => {
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
const lineLength = editor.document.lineAt(selection.active.line).text
|
||||
.length;
|
||||
const newPosition = selection.active.with({ character: lineLength });
|
||||
return new vscode.Selection(newPosition, newPosition);
|
||||
});
|
||||
parseKeysExact(['a'], [Mode.Normal], (vimState, editor) => {
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
const newPosition = positionUtils.right(editor.document, selection.active)
|
||||
return new vscode.Selection(newPosition, newPosition)
|
||||
})
|
||||
|
||||
enterInsertMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
removeTypeSubscription(vimState);
|
||||
}
|
||||
),
|
||||
enterInsertMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
removeTypeSubscription(vimState)
|
||||
}),
|
||||
|
||||
parseKeysExact(["v"], [Mode.Normal, Mode.VisualLine], (vimState, editor) => {
|
||||
parseKeysExact([KeyMap.Actions.InsertAtLineEnd], [Mode.Normal], (vimState, editor) => {
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
const lineLength = editor.document.lineAt(selection.active.line).text.length
|
||||
const newPosition = selection.active.with({ character: lineLength })
|
||||
return new vscode.Selection(newPosition, newPosition)
|
||||
})
|
||||
|
||||
enterInsertMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
removeTypeSubscription(vimState)
|
||||
}),
|
||||
|
||||
parseKeysExact(['v'], [Mode.Normal, Mode.VisualLine], (vimState, editor) => {
|
||||
if (vimState.mode === Mode.Normal) {
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
const lineLength = editor.document.lineAt(selection.active.line).text
|
||||
.length;
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
const lineLength = editor.document.lineAt(selection.active.line).text.length
|
||||
|
||||
if (lineLength === 0) return selection;
|
||||
if (lineLength === 0) return selection
|
||||
|
||||
return new vscode.Selection(
|
||||
selection.active,
|
||||
positionUtils.right(editor.document, selection.active)
|
||||
);
|
||||
});
|
||||
positionUtils.right(editor.document, selection.active),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
enterVisualMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
enterVisualMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
}),
|
||||
|
||||
parseKeysExact(["V"], [Mode.Normal, Mode.Visual], (vimState, editor) => {
|
||||
enterVisualLineMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
setVisualLineSelections(editor);
|
||||
parseKeysExact(['V'], [Mode.Normal, Mode.Visual], (vimState, editor) => {
|
||||
enterVisualLineMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
setVisualLineSelections(editor)
|
||||
}),
|
||||
|
||||
parseKeysExact(
|
||||
[KeyMap.Actions.NewLineBelow],
|
||||
[Mode.Normal],
|
||||
(vimState, editor) => {
|
||||
vscode.commands.executeCommand("editor.action.insertLineAfter");
|
||||
enterInsertMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
removeTypeSubscription(vimState);
|
||||
}
|
||||
),
|
||||
parseKeysExact([KeyMap.Actions.NewLineBelow], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.insertLineAfter')
|
||||
enterInsertMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
removeTypeSubscription(vimState)
|
||||
}),
|
||||
|
||||
parseKeysExact(
|
||||
[KeyMap.Actions.NewLineAbove],
|
||||
[Mode.Normal],
|
||||
(vimState, editor) => {
|
||||
vscode.commands.executeCommand("editor.action.insertLineBefore");
|
||||
enterInsertMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
removeTypeSubscription(vimState);
|
||||
}
|
||||
),
|
||||
parseKeysExact([KeyMap.Actions.NewLineAbove], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('editor.action.insertLineBefore')
|
||||
enterInsertMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
removeTypeSubscription(vimState)
|
||||
}),
|
||||
|
||||
parseKeysExact(["P"], [Mode.Normal, Mode.Visual, Mode.VisualLine], putAfter),
|
||||
parseKeysExact(["p"], [Mode.Normal], putBefore),
|
||||
parseKeysExact(['P'], [Mode.Normal, Mode.Visual, Mode.VisualLine], putAfter),
|
||||
parseKeysExact(['p'], [Mode.Normal], putBefore),
|
||||
|
||||
// parseKeysExact(
|
||||
// ["u"],
|
||||
@ -246,32 +223,27 @@ export const actions: Action[] = [
|
||||
// }
|
||||
// ),
|
||||
|
||||
parseKeysExact(["d", "d"], [Mode.Normal], (vimState, editor) => {
|
||||
deleteLine(vimState, editor);
|
||||
parseKeysExact(['d', 'd'], [Mode.Normal], (vimState, editor) => {
|
||||
deleteLine(vimState, editor)
|
||||
}),
|
||||
|
||||
parseKeysExact(["D"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("deleteAllRight");
|
||||
parseKeysExact(['D'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('deleteAllRight')
|
||||
}),
|
||||
|
||||
// add 1 character swap
|
||||
parseKeysRegex(
|
||||
/^x(.)$/,
|
||||
/^x$/,
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor, match) => {
|
||||
editor.edit(builder => {
|
||||
editor.selections.forEach(s => {
|
||||
let oneChar = s.with({
|
||||
end: s.active.with({
|
||||
character: s.active.character + 1
|
||||
})
|
||||
});
|
||||
builder.replace(oneChar, match[1]);
|
||||
});
|
||||
});
|
||||
}
|
||||
),
|
||||
parseKeysRegex(/^x(.)$/, /^x$/, [Mode.Normal, Mode.Visual], (vimState, editor, match) => {
|
||||
editor.edit((builder) => {
|
||||
editor.selections.forEach((s) => {
|
||||
const oneChar = s.with({
|
||||
end: s.active.with({
|
||||
character: s.active.character + 1,
|
||||
}),
|
||||
})
|
||||
builder.replace(oneChar, match[1])
|
||||
})
|
||||
})
|
||||
}),
|
||||
|
||||
// these allow you to the delete n lines above/below
|
||||
// ex. d12i = delete 12 lines up
|
||||
@ -280,12 +252,11 @@ export const actions: Action[] = [
|
||||
/^(d|d\d+)$/,
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor, match) => {
|
||||
let lineCount = parseInt(match[1]);
|
||||
let direction =
|
||||
match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down;
|
||||
const lineCount = parseInt(match[1])
|
||||
const direction = match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down
|
||||
// console.log(`delete ${lineCount} lines down`);
|
||||
deleteLines(vimState, editor, lineCount, direction);
|
||||
}
|
||||
deleteLines(vimState, editor, lineCount, direction)
|
||||
},
|
||||
),
|
||||
|
||||
// same for change command
|
||||
@ -294,16 +265,15 @@ export const actions: Action[] = [
|
||||
/^(c|c\d+)$/,
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor, match) => {
|
||||
let lineCount = parseInt(match[1]);
|
||||
let direction =
|
||||
match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down;
|
||||
const lineCount = parseInt(match[1])
|
||||
const direction = match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down
|
||||
// console.log(`delete ${lineCount} lines down`);
|
||||
deleteLines(vimState, editor, lineCount, direction);
|
||||
deleteLines(vimState, editor, lineCount, direction)
|
||||
|
||||
enterInsertMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
removeTypeSubscription(vimState);
|
||||
}
|
||||
enterInsertMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
removeTypeSubscription(vimState)
|
||||
},
|
||||
),
|
||||
|
||||
// same for selection command
|
||||
@ -312,17 +282,11 @@ export const actions: Action[] = [
|
||||
/^(s|s\d+)$/,
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor, match) => {
|
||||
let lineCount = parseInt(match[1]);
|
||||
let direction =
|
||||
match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down;
|
||||
const lineCount = parseInt(match[1])
|
||||
const direction = match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down
|
||||
// console.log(`delete ${lineCount} lines up`);
|
||||
editor.selections = makeMultiLineSelection(
|
||||
vimState,
|
||||
editor,
|
||||
lineCount,
|
||||
direction
|
||||
);
|
||||
}
|
||||
editor.selections = makeMultiLineSelection(vimState, editor, lineCount, direction)
|
||||
},
|
||||
),
|
||||
|
||||
// same for yank command
|
||||
@ -331,21 +295,15 @@ export const actions: Action[] = [
|
||||
/^(y|y\d+)$/,
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor, match) => {
|
||||
let lineCount = parseInt(match[1]);
|
||||
let direction =
|
||||
match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down;
|
||||
const lineCount = parseInt(match[1])
|
||||
const direction = match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down
|
||||
// console.log(`delete ${lineCount} lines up`);
|
||||
let selections = makeMultiLineSelection(
|
||||
vimState,
|
||||
editor,
|
||||
lineCount,
|
||||
direction
|
||||
);
|
||||
const selections = makeMultiLineSelection(vimState, editor, lineCount, direction)
|
||||
|
||||
yank(vimState, editor, selections, true);
|
||||
yank(vimState, editor, selections, true)
|
||||
|
||||
flashYankHighlight(editor, selections);
|
||||
}
|
||||
flashYankHighlight(editor, selections)
|
||||
},
|
||||
),
|
||||
|
||||
// same for rip command
|
||||
@ -354,21 +312,15 @@ export const actions: Action[] = [
|
||||
/^(r|r\d+)$/,
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor, match) => {
|
||||
let lineCount = parseInt(match[1]);
|
||||
let direction =
|
||||
match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down;
|
||||
const lineCount = parseInt(match[1])
|
||||
const direction = match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down
|
||||
// console.log(`delete ${lineCount} lines up`);
|
||||
let selections = makeMultiLineSelection(
|
||||
vimState,
|
||||
editor,
|
||||
lineCount,
|
||||
direction
|
||||
);
|
||||
const selections = makeMultiLineSelection(vimState, editor, lineCount, direction)
|
||||
|
||||
yank(vimState, editor, selections, true);
|
||||
yank(vimState, editor, selections, true)
|
||||
|
||||
deleteLines(vimState, editor, lineCount, direction);
|
||||
}
|
||||
deleteLines(vimState, editor, lineCount, direction)
|
||||
},
|
||||
),
|
||||
|
||||
// same for duplicate command
|
||||
@ -377,283 +329,253 @@ export const actions: Action[] = [
|
||||
/^(q|q\d+)$/,
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor, match) => {
|
||||
let lineCount = parseInt(match[1]);
|
||||
let direction =
|
||||
match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down;
|
||||
const lineCount = parseInt(match[1])
|
||||
const direction = match[2] == KeyMap.Motions.MoveUp ? Direction.Up : Direction.Down
|
||||
// console.log(`delete ${lineCount} lines up`);
|
||||
editor.selections = makeMultiLineSelection(
|
||||
vimState,
|
||||
editor,
|
||||
lineCount,
|
||||
direction
|
||||
);
|
||||
vscode.commands.executeCommand("editor.action.copyLinesDownAction");
|
||||
}
|
||||
editor.selections = makeMultiLineSelection(vimState, editor, lineCount, direction)
|
||||
vscode.commands.executeCommand('editor.action.copyLinesDownAction')
|
||||
},
|
||||
),
|
||||
|
||||
parseKeysExact(["c", "c"], [Mode.Normal], (vimState, editor) => {
|
||||
editor.edit(editBuilder => {
|
||||
editor.selections.forEach(selection => {
|
||||
const line = editor.document.lineAt(selection.active.line);
|
||||
parseKeysExact(['c', 'c'], [Mode.Normal], (vimState, editor) => {
|
||||
editor.edit((editBuilder) => {
|
||||
editor.selections.forEach((selection) => {
|
||||
const line = editor.document.lineAt(selection.active.line)
|
||||
editBuilder.delete(
|
||||
new vscode.Range(
|
||||
selection.active.with({
|
||||
character: line.firstNonWhitespaceCharacterIndex
|
||||
character: line.firstNonWhitespaceCharacterIndex,
|
||||
}),
|
||||
selection.active.with({ character: line.text.length })
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
selection.active.with({ character: line.text.length }),
|
||||
),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
enterInsertMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
removeTypeSubscription(vimState);
|
||||
enterInsertMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
removeTypeSubscription(vimState)
|
||||
}),
|
||||
|
||||
parseKeysExact(["C"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("deleteAllRight");
|
||||
enterInsertMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
removeTypeSubscription(vimState);
|
||||
parseKeysExact(['C'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('deleteAllRight')
|
||||
enterInsertMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
removeTypeSubscription(vimState)
|
||||
}),
|
||||
|
||||
parseKeysExact(["y", "y"], [Mode.Normal], (vimState, editor) => {
|
||||
yankLine(vimState, editor);
|
||||
parseKeysExact(['y', 'y'], [Mode.Normal], (vimState, editor) => {
|
||||
yankLine(vimState, editor)
|
||||
|
||||
// Yank highlight
|
||||
const highlightRanges = editor.selections.map(selection => {
|
||||
const lineLength = editor.document.lineAt(selection.active.line).text
|
||||
.length;
|
||||
const highlightRanges = editor.selections.map((selection) => {
|
||||
const lineLength = editor.document.lineAt(selection.active.line).text.length
|
||||
return new vscode.Range(
|
||||
selection.active.with({ character: 0 }),
|
||||
selection.active.with({ character: lineLength })
|
||||
);
|
||||
});
|
||||
flashYankHighlight(editor, highlightRanges);
|
||||
selection.active.with({ character: lineLength }),
|
||||
)
|
||||
})
|
||||
flashYankHighlight(editor, highlightRanges)
|
||||
}),
|
||||
|
||||
parseKeysExact(["Y"], [Mode.Normal], (vimState, editor) => {
|
||||
yankToEndOfLine(vimState, editor);
|
||||
parseKeysExact(['Y'], [Mode.Normal], (vimState, editor) => {
|
||||
yankToEndOfLine(vimState, editor)
|
||||
|
||||
// Yank highlight
|
||||
const highlightRanges = editor.selections.map(selection => {
|
||||
const lineLength = editor.document.lineAt(selection.active.line).text
|
||||
.length;
|
||||
return new vscode.Range(
|
||||
selection.active,
|
||||
selection.active.with({ character: lineLength })
|
||||
);
|
||||
});
|
||||
flashYankHighlight(editor, highlightRanges);
|
||||
const highlightRanges = editor.selections.map((selection) => {
|
||||
const lineLength = editor.document.lineAt(selection.active.line).text.length
|
||||
return new vscode.Range(selection.active, selection.active.with({ character: lineLength }))
|
||||
})
|
||||
flashYankHighlight(editor, highlightRanges)
|
||||
}),
|
||||
|
||||
parseKeysExact(["q", "q"], [Mode.Normal, Mode.Visual], () => {
|
||||
vscode.commands.executeCommand("editor.action.copyLinesDownAction");
|
||||
parseKeysExact(['q', 'q'], [Mode.Normal, Mode.Visual], () => {
|
||||
vscode.commands.executeCommand('editor.action.copyLinesDownAction')
|
||||
}),
|
||||
|
||||
parseKeysExact(["Q", "Q"], [Mode.Normal, Mode.Visual], () => {
|
||||
vscode.commands.executeCommand("editor.action.copyLinesUpAction");
|
||||
parseKeysExact(['Q', 'Q'], [Mode.Normal, Mode.Visual], () => {
|
||||
vscode.commands.executeCommand('editor.action.copyLinesUpAction')
|
||||
}),
|
||||
|
||||
parseKeysExact(["r", "r"], [Mode.Normal], (vimState, editor) => {
|
||||
yankLine(vimState, editor);
|
||||
deleteLine(vimState, editor);
|
||||
parseKeysExact(['r', 'r'], [Mode.Normal], (vimState, editor) => {
|
||||
yankLine(vimState, editor)
|
||||
deleteLine(vimState, editor)
|
||||
}),
|
||||
|
||||
parseKeysExact(["R"], [Mode.Normal], (vimState, editor) => {
|
||||
yankToEndOfLine(vimState, editor);
|
||||
vscode.commands.executeCommand("deleteAllRight");
|
||||
parseKeysExact(['R'], [Mode.Normal], (vimState, editor) => {
|
||||
yankToEndOfLine(vimState, editor)
|
||||
vscode.commands.executeCommand('deleteAllRight')
|
||||
}),
|
||||
|
||||
parseKeysExact(["s", "s"], [Mode.Normal], (vimState, editor) => {
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
parseKeysExact(['s', 's'], [Mode.Normal], (vimState, editor) => {
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
return new vscode.Selection(
|
||||
selection.active.with({ character: 0 }),
|
||||
positionUtils.lineEnd(editor.document, selection.active)
|
||||
);
|
||||
});
|
||||
positionUtils.lineEnd(editor.document, selection.active),
|
||||
)
|
||||
})
|
||||
|
||||
enterVisualLineMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
enterVisualLineMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
}),
|
||||
|
||||
parseKeysExact(["S"], [Mode.Normal], (vimState, editor) => {
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
parseKeysExact(['S'], [Mode.Normal], (vimState, editor) => {
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
return new vscode.Selection(
|
||||
selection.active,
|
||||
positionUtils.lineEnd(editor.document, selection.active)
|
||||
);
|
||||
});
|
||||
positionUtils.lineEnd(editor.document, selection.active),
|
||||
)
|
||||
})
|
||||
|
||||
enterVisualMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
enterVisualMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
}),
|
||||
|
||||
parseKeysExact(["h"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("deleteLeft");
|
||||
parseKeysExact(['h'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('deleteLeft')
|
||||
}),
|
||||
|
||||
parseKeysExact(["n"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("deleteRight");
|
||||
parseKeysExact(['n'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('deleteRight')
|
||||
}),
|
||||
|
||||
parseKeysExact(
|
||||
["z", KeyMap.Motions.MoveUp],
|
||||
[Mode.Normal],
|
||||
(vimState, editor) => {
|
||||
vscode.commands.executeCommand("revealLine", {
|
||||
lineNumber: editor.selection.active.line,
|
||||
at: "top"
|
||||
});
|
||||
}
|
||||
),
|
||||
|
||||
parseKeysExact(["z", "z"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("revealLine", {
|
||||
parseKeysExact(['z', KeyMap.Motions.MoveUp], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('revealLine', {
|
||||
lineNumber: editor.selection.active.line,
|
||||
at: "center"
|
||||
});
|
||||
at: 'top',
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact(
|
||||
["z", KeyMap.Motions.MoveDown],
|
||||
[Mode.Normal],
|
||||
(vimState, editor) => {
|
||||
vscode.commands.executeCommand("revealLine", {
|
||||
lineNumber: editor.selection.active.line,
|
||||
at: "bottom"
|
||||
});
|
||||
}
|
||||
),
|
||||
|
||||
parseKeysExact([";"], [Mode.Normal], (vimState, editor) => {
|
||||
vimState.semicolonAction(vimState, editor);
|
||||
parseKeysExact(['z', 'z'], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('revealLine', {
|
||||
lineNumber: editor.selection.active.line,
|
||||
at: 'center',
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact([","], [Mode.Normal], (vimState, editor) => {
|
||||
vimState.commaAction(vimState, editor);
|
||||
})
|
||||
];
|
||||
parseKeysExact(['z', KeyMap.Motions.MoveDown], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand('revealLine', {
|
||||
lineNumber: editor.selection.active.line,
|
||||
at: 'bottom',
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact([';'], [Mode.Normal], (vimState, editor) => {
|
||||
vimState.semicolonAction(vimState, editor)
|
||||
}),
|
||||
|
||||
parseKeysExact([','], [Mode.Normal], (vimState, editor) => {
|
||||
vimState.commaAction(vimState, editor)
|
||||
}),
|
||||
]
|
||||
|
||||
function makeMultiLineSelection(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
lineCount: number,
|
||||
direction: Direction
|
||||
direction: Direction,
|
||||
): vscode.Selection[] {
|
||||
return editor.selections.map(selection => {
|
||||
return editor.selections.map((selection) => {
|
||||
if (direction == Direction.Up) {
|
||||
let endLine = selection.active.line - lineCount + 1;
|
||||
const startPos = positionUtils.lineEnd(editor.document, selection.active);
|
||||
const endPos =
|
||||
endLine >= 0
|
||||
? new vscode.Position(endLine, 0)
|
||||
: new vscode.Position(0, 0);
|
||||
return new vscode.Selection(startPos, endPos);
|
||||
const endLine = selection.active.line - lineCount + 1
|
||||
const startPos = positionUtils.lineEnd(editor.document, selection.active)
|
||||
const endPos = endLine >= 0 ? new vscode.Position(endLine, 0) : new vscode.Position(0, 0)
|
||||
return new vscode.Selection(startPos, endPos)
|
||||
} else {
|
||||
const endLine = selection.active.line + lineCount - 1;
|
||||
const startPos = new vscode.Position(selection.active.line, 0);
|
||||
const endLine = selection.active.line + lineCount - 1
|
||||
const startPos = new vscode.Position(selection.active.line, 0)
|
||||
const endPos =
|
||||
endLine < editor.document.lineCount
|
||||
? new vscode.Position(
|
||||
endLine,
|
||||
editor.document.lineAt(endLine).text.length
|
||||
)
|
||||
: positionUtils.lastChar(editor.document);
|
||||
? new vscode.Position(endLine, editor.document.lineAt(endLine).text.length)
|
||||
: positionUtils.lastChar(editor.document)
|
||||
|
||||
return new vscode.Selection(startPos, endPos);
|
||||
return new vscode.Selection(startPos, endPos)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function deleteLines(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
lineCount: number,
|
||||
direction: Direction = Direction.Down
|
||||
direction: Direction = Direction.Down,
|
||||
): void {
|
||||
let selections = editor.selections.map(selection => {
|
||||
const selections = editor.selections.map((selection) => {
|
||||
if (direction == Direction.Up) {
|
||||
let endLine = selection.active.line - lineCount;
|
||||
const endLine = selection.active.line - lineCount
|
||||
if (endLine >= 0) {
|
||||
const startPos = positionUtils.lineEnd(
|
||||
editor.document,
|
||||
selection.active
|
||||
);
|
||||
const endPos = new vscode.Position(
|
||||
endLine,
|
||||
editor.document.lineAt(endLine).text.length
|
||||
);
|
||||
return new vscode.Selection(startPos, endPos);
|
||||
const startPos = positionUtils.lineEnd(editor.document, selection.active)
|
||||
const endPos = new vscode.Position(endLine, editor.document.lineAt(endLine).text.length)
|
||||
return new vscode.Selection(startPos, endPos)
|
||||
} else {
|
||||
const startPos =
|
||||
selection.active.line + 1 <= editor.document.lineCount
|
||||
? new vscode.Position(selection.active.line + 1, 0)
|
||||
: positionUtils.lineEnd(editor.document, selection.active);
|
||||
: positionUtils.lineEnd(editor.document, selection.active)
|
||||
|
||||
const endPos = new vscode.Position(0, 0);
|
||||
return new vscode.Selection(startPos, endPos);
|
||||
const endPos = new vscode.Position(0, 0)
|
||||
return new vscode.Selection(startPos, endPos)
|
||||
}
|
||||
} else {
|
||||
let endLine = selection.active.line + lineCount;
|
||||
const endLine = selection.active.line + lineCount
|
||||
if (endLine <= editor.document.lineCount - 1) {
|
||||
const startPos = new vscode.Position(selection.active.line, 0);
|
||||
const endPos = new vscode.Position(endLine, 0);
|
||||
return new vscode.Selection(startPos, endPos);
|
||||
const startPos = new vscode.Position(selection.active.line, 0)
|
||||
const endPos = new vscode.Position(endLine, 0)
|
||||
return new vscode.Selection(startPos, endPos)
|
||||
} else {
|
||||
const startPos =
|
||||
selection.active.line - 1 >= 0
|
||||
? new vscode.Position(
|
||||
selection.active.line - 1,
|
||||
editor.document.lineAt(selection.active.line - 1).text.length
|
||||
editor.document.lineAt(selection.active.line - 1).text.length,
|
||||
)
|
||||
: new vscode.Position(selection.active.line, 0);
|
||||
: new vscode.Position(selection.active.line, 0)
|
||||
|
||||
const endPos = positionUtils.lastChar(editor.document);
|
||||
return new vscode.Selection(startPos, endPos);
|
||||
const endPos = positionUtils.lastChar(editor.document)
|
||||
return new vscode.Selection(startPos, endPos)
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
editor
|
||||
.edit(builder => {
|
||||
selections.forEach(sel => builder.replace(sel, ""));
|
||||
.edit((builder) => {
|
||||
selections.forEach((sel) => builder.replace(sel, ''))
|
||||
})
|
||||
.then(() => {
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
const character = editor.document.lineAt(selection.active.line)
|
||||
.firstNonWhitespaceCharacterIndex;
|
||||
const newPosition = selection.active.with({ character: character });
|
||||
return new vscode.Selection(newPosition, newPosition);
|
||||
});
|
||||
});
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
const character = editor.document.lineAt(
|
||||
selection.active.line,
|
||||
).firstNonWhitespaceCharacterIndex
|
||||
const newPosition = selection.active.with({ character: character })
|
||||
return new vscode.Selection(newPosition, newPosition)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function deleteLine(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
direction: Direction = Direction.Down
|
||||
direction: Direction = Direction.Down,
|
||||
): void {
|
||||
deleteLines(vimState, editor, 1, direction);
|
||||
deleteLines(vimState, editor, 1, direction)
|
||||
}
|
||||
|
||||
function yankLine(vimState: VimState, editor: vscode.TextEditor): void {
|
||||
vimState.registers = {
|
||||
contentsList: editor.selections.map(selection => {
|
||||
return editor.document.lineAt(selection.active.line).text;
|
||||
contentsList: editor.selections.map((selection) => {
|
||||
return editor.document.lineAt(selection.active.line).text
|
||||
}),
|
||||
linewise: true
|
||||
};
|
||||
linewise: true,
|
||||
}
|
||||
}
|
||||
|
||||
function yankToEndOfLine(vimState: VimState, editor: vscode.TextEditor): void {
|
||||
vimState.registers = {
|
||||
contentsList: editor.selections.map(selection => {
|
||||
contentsList: editor.selections.map((selection) => {
|
||||
return editor.document
|
||||
.lineAt(selection.active.line)
|
||||
.text.substring(selection.active.character);
|
||||
.text.substring(selection.active.character)
|
||||
}),
|
||||
linewise: false
|
||||
};
|
||||
linewise: false,
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Action } from "../action_types";
|
||||
import { actions as subActions } from "./actions";
|
||||
import { operators } from "./operators";
|
||||
import { motions } from "./motions";
|
||||
import { Action } from '../action_types'
|
||||
import { actions as subActions } from './actions'
|
||||
import { operators } from './operators'
|
||||
import { motions } from './motions'
|
||||
|
||||
export const actions: Action[] = subActions.concat(operators, motions);
|
||||
export const actions: Action[] = subActions.concat(operators, motions)
|
||||
|
@ -1,17 +1,17 @@
|
||||
export default {
|
||||
Motions: {
|
||||
MoveLeft: "j",
|
||||
MoveRight: "l",
|
||||
MoveDown: "k",
|
||||
MoveUp: "i",
|
||||
MoveLineEnd: "o",
|
||||
MoveLineStart: "u",
|
||||
MoveLeft: 'j',
|
||||
MoveRight: 'l',
|
||||
MoveDown: 'k',
|
||||
MoveUp: 'i',
|
||||
MoveLineEnd: 'o',
|
||||
MoveLineStart: 'u',
|
||||
},
|
||||
Actions: {
|
||||
InsertMode: "h",
|
||||
InsertAtLineStart: "U",
|
||||
InsertAtLineEnd: "O",
|
||||
NewLineAbove: "I",
|
||||
NewLineBelow: "K",
|
||||
InsertMode: 'h',
|
||||
InsertAtLineStart: 'U',
|
||||
InsertAtLineEnd: 'O',
|
||||
NewLineAbove: 'I',
|
||||
NewLineBelow: 'K',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -1,270 +1,184 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { Mode } from "../modes_types";
|
||||
import { Action } from "../action_types";
|
||||
import { parseKeysExact, parseKeysRegex } from "../parse_keys";
|
||||
import { Mode } from '../modes_types'
|
||||
import { Action } from '../action_types'
|
||||
import { parseKeysExact, parseKeysRegex } from '../parse_keys'
|
||||
import {
|
||||
vscodeToVimVisualSelection,
|
||||
vimToVscodeVisualLineSelection,
|
||||
vimToVscodeVisualSelection,
|
||||
vscodeToVimVisualLineSelection
|
||||
} from "../selection_utils";
|
||||
import * as positionUtils from "../position_utils";
|
||||
import { VimState } from "../vim_state_types";
|
||||
import { wordRanges, whitespaceWordRanges } from "../word_utils";
|
||||
import { searchForward, searchBackward } from "../search_utils";
|
||||
import { paragraphForward, paragraphBackward } from "../paragraph_utils";
|
||||
import { setVisualLineSelections } from "../visual_line_utils";
|
||||
import { setVisualSelections } from "../visual_utils";
|
||||
import KeyMap from "./keymaps";
|
||||
vscodeToVimVisualLineSelection,
|
||||
} from '../selection_utils'
|
||||
import * as positionUtils from '../position_utils'
|
||||
import { VimState } from '../vim_state_types'
|
||||
import { wordRanges, whitespaceWordRanges } from '../word_utils'
|
||||
import { searchForward, searchBackward } from '../search_utils'
|
||||
import { paragraphForward, paragraphBackward } from '../paragraph_utils'
|
||||
import { setVisualLineSelections } from '../visual_line_utils'
|
||||
import { setVisualSelections } from '../visual_utils'
|
||||
import KeyMap from './keymaps'
|
||||
|
||||
export const motions: Action[] = [
|
||||
parseKeysExact(
|
||||
[KeyMap.Motions.MoveRight],
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
return positionUtils.rightNormal(document, position);
|
||||
});
|
||||
}
|
||||
),
|
||||
parseKeysExact([KeyMap.Motions.MoveRight], [Mode.Normal, Mode.Visual], (vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
return positionUtils.rightNormal(document, position)
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact(
|
||||
[KeyMap.Motions.MoveLeft],
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
return positionUtils.left(position);
|
||||
});
|
||||
}
|
||||
),
|
||||
parseKeysExact([KeyMap.Motions.MoveLeft], [Mode.Normal, Mode.Visual], (vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ position }) => {
|
||||
return positionUtils.left(position)
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact([KeyMap.Motions.MoveUp], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("cursorMove", {
|
||||
to: "up",
|
||||
by: "wrappedLine"
|
||||
});
|
||||
parseKeysExact([KeyMap.Motions.MoveUp], [Mode.Normal], (_vimState, _editor) => {
|
||||
vscode.commands.executeCommand('cursorMove', {
|
||||
to: 'up',
|
||||
by: 'wrappedLine',
|
||||
})
|
||||
}),
|
||||
parseKeysExact([KeyMap.Motions.MoveUp], [Mode.Visual], (vimState, editor) => {
|
||||
const originalSelections = editor.selections;
|
||||
const originalSelections = editor.selections
|
||||
|
||||
vscode.commands
|
||||
.executeCommand("cursorMove", {
|
||||
to: "up",
|
||||
by: "wrappedLine",
|
||||
select: true
|
||||
.executeCommand('cursorMove', {
|
||||
to: 'up',
|
||||
by: 'wrappedLine',
|
||||
select: true,
|
||||
})
|
||||
.then(() => {
|
||||
setVisualSelections(editor, originalSelections);
|
||||
});
|
||||
setVisualSelections(editor, originalSelections)
|
||||
})
|
||||
}),
|
||||
parseKeysExact([KeyMap.Motions.MoveUp], [Mode.VisualLine], (vimState, editor) => {
|
||||
vscode.commands
|
||||
.executeCommand('cursorMove', { to: 'up', by: 'line', select: true })
|
||||
.then(() => {
|
||||
setVisualLineSelections(editor)
|
||||
})
|
||||
}),
|
||||
parseKeysExact(
|
||||
[KeyMap.Motions.MoveUp],
|
||||
[Mode.VisualLine],
|
||||
(vimState, editor) => {
|
||||
vscode.commands
|
||||
.executeCommand("cursorMove", { to: "up", by: "line", select: true })
|
||||
.then(() => {
|
||||
setVisualLineSelections(editor);
|
||||
});
|
||||
}
|
||||
),
|
||||
|
||||
parseKeysExact(
|
||||
[KeyMap.Motions.MoveDown],
|
||||
[Mode.Normal],
|
||||
(vimState, editor) => {
|
||||
vscode.commands.executeCommand("cursorMove", {
|
||||
to: "down",
|
||||
by: "wrappedLine"
|
||||
});
|
||||
}
|
||||
),
|
||||
parseKeysExact(
|
||||
[KeyMap.Motions.MoveDown],
|
||||
[Mode.Visual],
|
||||
(vimState, editor) => {
|
||||
const originalSelections = editor.selections;
|
||||
parseKeysExact([KeyMap.Motions.MoveDown], [Mode.Normal], (_vimState, _editor) => {
|
||||
vscode.commands.executeCommand('cursorMove', {
|
||||
to: 'down',
|
||||
by: 'wrappedLine',
|
||||
})
|
||||
}),
|
||||
parseKeysExact([KeyMap.Motions.MoveDown], [Mode.Visual], (vimState, editor) => {
|
||||
const originalSelections = editor.selections
|
||||
|
||||
vscode.commands
|
||||
.executeCommand("cursorMove", {
|
||||
to: "down",
|
||||
by: "wrappedLine",
|
||||
select: true
|
||||
})
|
||||
.then(() => {
|
||||
setVisualSelections(editor, originalSelections);
|
||||
});
|
||||
}
|
||||
),
|
||||
parseKeysExact(
|
||||
[KeyMap.Motions.MoveDown],
|
||||
[Mode.VisualLine],
|
||||
(vimState, editor) => {
|
||||
vscode.commands
|
||||
.executeCommand("cursorMove", { to: "down", by: "line", select: true })
|
||||
.then(() => {
|
||||
setVisualLineSelections(editor);
|
||||
});
|
||||
}
|
||||
),
|
||||
vscode.commands
|
||||
.executeCommand('cursorMove', {
|
||||
to: 'down',
|
||||
by: 'wrappedLine',
|
||||
select: true,
|
||||
})
|
||||
.then(() => {
|
||||
setVisualSelections(editor, originalSelections)
|
||||
})
|
||||
}),
|
||||
parseKeysExact([KeyMap.Motions.MoveDown], [Mode.VisualLine], (vimState, editor) => {
|
||||
vscode.commands
|
||||
.executeCommand('cursorMove', { to: 'down', by: 'line', select: true })
|
||||
.then(() => {
|
||||
setVisualLineSelections(editor)
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact(['w'], [Mode.Normal, Mode.Visual], createWordForwardHandler(wordRanges)),
|
||||
parseKeysExact(['W'], [Mode.Normal, Mode.Visual], createWordForwardHandler(whitespaceWordRanges)),
|
||||
|
||||
parseKeysExact(['b'], [Mode.Normal, Mode.Visual], createWordBackwardHandler(wordRanges)),
|
||||
parseKeysExact(
|
||||
["w"],
|
||||
['B'],
|
||||
[Mode.Normal, Mode.Visual],
|
||||
createWordForwardHandler(wordRanges)
|
||||
),
|
||||
parseKeysExact(
|
||||
["W"],
|
||||
[Mode.Normal, Mode.Visual],
|
||||
createWordForwardHandler(whitespaceWordRanges)
|
||||
createWordBackwardHandler(whitespaceWordRanges),
|
||||
),
|
||||
|
||||
parseKeysExact(
|
||||
["b"],
|
||||
[Mode.Normal, Mode.Visual],
|
||||
createWordBackwardHandler(wordRanges)
|
||||
),
|
||||
parseKeysExact(
|
||||
["B"],
|
||||
[Mode.Normal, Mode.Visual],
|
||||
createWordBackwardHandler(whitespaceWordRanges)
|
||||
),
|
||||
parseKeysExact(['e'], [Mode.Normal, Mode.Visual], createWordEndHandler(wordRanges)),
|
||||
parseKeysExact(['E'], [Mode.Normal, Mode.Visual], createWordEndHandler(whitespaceWordRanges)),
|
||||
|
||||
parseKeysExact(
|
||||
["e"],
|
||||
[Mode.Normal, Mode.Visual],
|
||||
createWordEndHandler(wordRanges)
|
||||
),
|
||||
parseKeysExact(
|
||||
["E"],
|
||||
[Mode.Normal, Mode.Visual],
|
||||
createWordEndHandler(whitespaceWordRanges)
|
||||
),
|
||||
parseKeysRegex(/^f(..)$/, /^(f|f.)$/, [Mode.Normal, Mode.Visual], (vimState, editor, match) => {
|
||||
findForward(vimState, editor, match)
|
||||
|
||||
parseKeysRegex(
|
||||
/^f(..)$/,
|
||||
/^(f|f.)$/,
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor, match) => {
|
||||
findForward(vimState, editor, match);
|
||||
|
||||
vimState.semicolonAction = (innerVimState, innerEditor) => {
|
||||
findForward(innerVimState, innerEditor, match);
|
||||
};
|
||||
|
||||
vimState.commaAction = (innerVimState, innerEditor) => {
|
||||
findBackward(innerVimState, innerEditor, match);
|
||||
};
|
||||
vimState.semicolonAction = (innerVimState, innerEditor) => {
|
||||
findForward(innerVimState, innerEditor, match)
|
||||
}
|
||||
),
|
||||
|
||||
parseKeysRegex(
|
||||
/^F(..)$/,
|
||||
/^(F|F.)$/,
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor, match) => {
|
||||
findBackward(vimState, editor, match);
|
||||
|
||||
vimState.semicolonAction = (innerVimState, innerEditor) => {
|
||||
findBackward(innerVimState, innerEditor, match);
|
||||
};
|
||||
|
||||
vimState.commaAction = (innerVimState, innerEditor) => {
|
||||
findForward(innerVimState, innerEditor, match);
|
||||
};
|
||||
vimState.commaAction = (innerVimState, innerEditor) => {
|
||||
findBackward(innerVimState, innerEditor, match)
|
||||
}
|
||||
),
|
||||
}),
|
||||
|
||||
parseKeysRegex(
|
||||
/^t(.)$/,
|
||||
/^t$/,
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor, match) => {
|
||||
tillForward(vimState, editor, match);
|
||||
parseKeysRegex(/^F(..)$/, /^(F|F.)$/, [Mode.Normal, Mode.Visual], (vimState, editor, match) => {
|
||||
findBackward(vimState, editor, match)
|
||||
|
||||
vimState.semicolonAction = (innerVimState, innerEditor) => {
|
||||
tillForward(innerVimState, innerEditor, match);
|
||||
};
|
||||
|
||||
vimState.commaAction = (innerVimState, innerEditor) => {
|
||||
tillBackward(innerVimState, innerEditor, match);
|
||||
};
|
||||
vimState.semicolonAction = (innerVimState, innerEditor) => {
|
||||
findBackward(innerVimState, innerEditor, match)
|
||||
}
|
||||
),
|
||||
|
||||
parseKeysRegex(
|
||||
/^T(.)$/,
|
||||
/^T$/,
|
||||
[Mode.Normal, Mode.Visual],
|
||||
(vimState, editor, match) => {
|
||||
tillBackward(vimState, editor, match);
|
||||
|
||||
vimState.semicolonAction = (innerVimState, innerEditor) => {
|
||||
tillBackward(innerVimState, innerEditor, match);
|
||||
};
|
||||
|
||||
vimState.commaAction = (innerVimState, innerEditor) => {
|
||||
tillForward(innerVimState, innerEditor, match);
|
||||
};
|
||||
vimState.commaAction = (innerVimState, innerEditor) => {
|
||||
findForward(innerVimState, innerEditor, match)
|
||||
}
|
||||
),
|
||||
}),
|
||||
|
||||
parseKeysExact(
|
||||
["g", "g"],
|
||||
[Mode.Normal, Mode.Visual, Mode.VisualLine],
|
||||
(vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
return new vscode.Position(0, 0);
|
||||
});
|
||||
}
|
||||
),
|
||||
parseKeysRegex(/^t(.)$/, /^t$/, [Mode.Normal, Mode.Visual], (vimState, editor, match) => {
|
||||
tillForward(vimState, editor, match)
|
||||
|
||||
parseKeysExact(
|
||||
["G"],
|
||||
[Mode.Normal, Mode.Visual, Mode.VisualLine],
|
||||
(vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
return new vscode.Position(document.lineCount - 1, 0);
|
||||
});
|
||||
vimState.semicolonAction = (innerVimState, innerEditor) => {
|
||||
tillForward(innerVimState, innerEditor, match)
|
||||
}
|
||||
),
|
||||
|
||||
parseKeysExact(
|
||||
["}"],
|
||||
[Mode.Normal, Mode.Visual, Mode.VisualLine],
|
||||
(vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
return new vscode.Position(
|
||||
paragraphForward(document, position.line),
|
||||
0
|
||||
);
|
||||
});
|
||||
vimState.commaAction = (innerVimState, innerEditor) => {
|
||||
tillBackward(innerVimState, innerEditor, match)
|
||||
}
|
||||
),
|
||||
}),
|
||||
|
||||
parseKeysExact(
|
||||
["{"],
|
||||
[Mode.Normal, Mode.Visual, Mode.VisualLine],
|
||||
(vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
return new vscode.Position(
|
||||
paragraphBackward(document, position.line),
|
||||
0
|
||||
);
|
||||
});
|
||||
parseKeysRegex(/^T(.)$/, /^T$/, [Mode.Normal, Mode.Visual], (vimState, editor, match) => {
|
||||
tillBackward(vimState, editor, match)
|
||||
|
||||
vimState.semicolonAction = (innerVimState, innerEditor) => {
|
||||
tillBackward(innerVimState, innerEditor, match)
|
||||
}
|
||||
),
|
||||
|
||||
vimState.commaAction = (innerVimState, innerEditor) => {
|
||||
tillForward(innerVimState, innerEditor, match)
|
||||
}
|
||||
}),
|
||||
|
||||
parseKeysExact(['g', 'g'], [Mode.Normal, Mode.Visual, Mode.VisualLine], (vimState, editor) => {
|
||||
execMotion(vimState, editor, () => {
|
||||
return new vscode.Position(0, 0)
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact(['G'], [Mode.Normal, Mode.Visual, Mode.VisualLine], (vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document }) => {
|
||||
return new vscode.Position(document.lineCount - 1, 0)
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact(['}'], [Mode.Normal, Mode.Visual, Mode.VisualLine], (vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
return new vscode.Position(paragraphForward(document, position.line), 0)
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact(['{'], [Mode.Normal, Mode.Visual, Mode.VisualLine], (vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
return new vscode.Position(paragraphBackward(document, position.line), 0)
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact(
|
||||
[KeyMap.Motions.MoveLineEnd],
|
||||
[Mode.Normal, Mode.Visual, Mode.VisualLine],
|
||||
(vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
const lineLength = document.lineAt(position.line).text.length;
|
||||
return position.with({ character: Math.max(lineLength - 1, 0) });
|
||||
});
|
||||
}
|
||||
const lineLength = document.lineAt(position.line).text.length
|
||||
return position.with({ character: Math.max(lineLength - 1, 0) })
|
||||
})
|
||||
},
|
||||
),
|
||||
|
||||
parseKeysExact(
|
||||
@ -272,143 +186,143 @@ export const motions: Action[] = [
|
||||
[Mode.Normal, Mode.Visual, Mode.VisualLine],
|
||||
(vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
const line = document.lineAt(position.line);
|
||||
const line = document.lineAt(position.line)
|
||||
return position.with({
|
||||
character: line.firstNonWhitespaceCharacterIndex
|
||||
});
|
||||
});
|
||||
}
|
||||
character: line.firstNonWhitespaceCharacterIndex,
|
||||
})
|
||||
})
|
||||
},
|
||||
),
|
||||
|
||||
parseKeysExact(["H"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("cursorMove", {
|
||||
to: "viewPortTop",
|
||||
by: "line"
|
||||
});
|
||||
parseKeysExact(['H'], [Mode.Normal], (_vimState, _editor) => {
|
||||
vscode.commands.executeCommand('cursorMove', {
|
||||
to: 'viewPortTop',
|
||||
by: 'line',
|
||||
})
|
||||
}),
|
||||
parseKeysExact(["H"], [Mode.Visual], (vimState, editor) => {
|
||||
const originalSelections = editor.selections;
|
||||
parseKeysExact(['H'], [Mode.Visual], (vimState, editor) => {
|
||||
const originalSelections = editor.selections
|
||||
|
||||
vscode.commands
|
||||
.executeCommand("cursorMove", {
|
||||
to: "viewPortTop",
|
||||
by: "line",
|
||||
select: true
|
||||
.executeCommand('cursorMove', {
|
||||
to: 'viewPortTop',
|
||||
by: 'line',
|
||||
select: true,
|
||||
})
|
||||
.then(() => {
|
||||
setVisualSelections(editor, originalSelections);
|
||||
});
|
||||
setVisualSelections(editor, originalSelections)
|
||||
})
|
||||
}),
|
||||
parseKeysExact(["H"], [Mode.VisualLine], (vimState, editor) => {
|
||||
parseKeysExact(['H'], [Mode.VisualLine], (vimState, editor) => {
|
||||
vscode.commands
|
||||
.executeCommand("cursorMove", {
|
||||
to: "viewPortTop",
|
||||
by: "line",
|
||||
select: true
|
||||
.executeCommand('cursorMove', {
|
||||
to: 'viewPortTop',
|
||||
by: 'line',
|
||||
select: true,
|
||||
})
|
||||
.then(() => {
|
||||
setVisualLineSelections(editor);
|
||||
});
|
||||
setVisualLineSelections(editor)
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact(["M"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("cursorMove", {
|
||||
to: "viewPortCenter",
|
||||
by: "line"
|
||||
});
|
||||
parseKeysExact(['M'], [Mode.Normal], (_vimState, _editor) => {
|
||||
vscode.commands.executeCommand('cursorMove', {
|
||||
to: 'viewPortCenter',
|
||||
by: 'line',
|
||||
})
|
||||
}),
|
||||
parseKeysExact(["M"], [Mode.Visual], (vimState, editor) => {
|
||||
const originalSelections = editor.selections;
|
||||
parseKeysExact(['M'], [Mode.Visual], (vimState, editor) => {
|
||||
const originalSelections = editor.selections
|
||||
|
||||
vscode.commands
|
||||
.executeCommand("cursorMove", {
|
||||
to: "viewPortCenter",
|
||||
by: "line",
|
||||
select: true
|
||||
.executeCommand('cursorMove', {
|
||||
to: 'viewPortCenter',
|
||||
by: 'line',
|
||||
select: true,
|
||||
})
|
||||
.then(() => {
|
||||
setVisualSelections(editor, originalSelections);
|
||||
});
|
||||
setVisualSelections(editor, originalSelections)
|
||||
})
|
||||
}),
|
||||
parseKeysExact(["M"], [Mode.VisualLine], (vimState, editor) => {
|
||||
parseKeysExact(['M'], [Mode.VisualLine], (vimState, editor) => {
|
||||
vscode.commands
|
||||
.executeCommand("cursorMove", {
|
||||
to: "viewPortCenter",
|
||||
by: "line",
|
||||
select: true
|
||||
.executeCommand('cursorMove', {
|
||||
to: 'viewPortCenter',
|
||||
by: 'line',
|
||||
select: true,
|
||||
})
|
||||
.then(() => {
|
||||
setVisualLineSelections(editor);
|
||||
});
|
||||
setVisualLineSelections(editor)
|
||||
})
|
||||
}),
|
||||
|
||||
parseKeysExact(["L"], [Mode.Normal], (vimState, editor) => {
|
||||
vscode.commands.executeCommand("cursorMove", {
|
||||
to: "viewPortBottom",
|
||||
by: "line"
|
||||
});
|
||||
parseKeysExact(['L'], [Mode.Normal], (_vimState, _editor) => {
|
||||
vscode.commands.executeCommand('cursorMove', {
|
||||
to: 'viewPortBottom',
|
||||
by: 'line',
|
||||
})
|
||||
}),
|
||||
parseKeysExact(["L"], [Mode.Visual], (vimState, editor) => {
|
||||
const originalSelections = editor.selections;
|
||||
parseKeysExact(['L'], [Mode.Visual], (vimState, editor) => {
|
||||
const originalSelections = editor.selections
|
||||
|
||||
vscode.commands
|
||||
.executeCommand("cursorMove", {
|
||||
to: "viewPortBottom",
|
||||
by: "line",
|
||||
select: true
|
||||
.executeCommand('cursorMove', {
|
||||
to: 'viewPortBottom',
|
||||
by: 'line',
|
||||
select: true,
|
||||
})
|
||||
.then(() => {
|
||||
setVisualSelections(editor, originalSelections);
|
||||
});
|
||||
setVisualSelections(editor, originalSelections)
|
||||
})
|
||||
}),
|
||||
parseKeysExact(["L"], [Mode.VisualLine], (vimState, editor) => {
|
||||
parseKeysExact(['L'], [Mode.VisualLine], (vimState, editor) => {
|
||||
vscode.commands
|
||||
.executeCommand("cursorMove", {
|
||||
to: "viewPortBottom",
|
||||
by: "line",
|
||||
select: true
|
||||
.executeCommand('cursorMove', {
|
||||
to: 'viewPortBottom',
|
||||
by: 'line',
|
||||
select: true,
|
||||
})
|
||||
.then(() => {
|
||||
setVisualLineSelections(editor);
|
||||
});
|
||||
})
|
||||
];
|
||||
setVisualLineSelections(editor)
|
||||
})
|
||||
}),
|
||||
]
|
||||
|
||||
type MotionArgs = {
|
||||
document: vscode.TextDocument;
|
||||
position: vscode.Position;
|
||||
selectionIndex: number;
|
||||
vimState: VimState;
|
||||
};
|
||||
document: vscode.TextDocument
|
||||
position: vscode.Position
|
||||
selectionIndex: number
|
||||
vimState: VimState
|
||||
}
|
||||
|
||||
type RegexMotionArgs = {
|
||||
document: vscode.TextDocument;
|
||||
position: vscode.Position;
|
||||
selectionIndex: number;
|
||||
vimState: VimState;
|
||||
match: RegExpMatchArray;
|
||||
};
|
||||
document: vscode.TextDocument
|
||||
position: vscode.Position
|
||||
selectionIndex: number
|
||||
vimState: VimState
|
||||
match: RegExpMatchArray
|
||||
}
|
||||
|
||||
function execRegexMotion(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
match: RegExpMatchArray,
|
||||
regexMotion: (args: RegexMotionArgs) => vscode.Position
|
||||
regexMotion: (args: RegexMotionArgs) => vscode.Position,
|
||||
) {
|
||||
return execMotion(vimState, editor, motionArgs => {
|
||||
return execMotion(vimState, editor, (motionArgs) => {
|
||||
return regexMotion({
|
||||
...motionArgs,
|
||||
match: match
|
||||
});
|
||||
});
|
||||
match: match,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function execMotion(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
motion: (args: MotionArgs) => vscode.Position
|
||||
motion: (args: MotionArgs) => vscode.Position,
|
||||
) {
|
||||
const document = editor.document;
|
||||
const document = editor.document
|
||||
|
||||
const newSelections = editor.selections.map((selection, i) => {
|
||||
if (vimState.mode === Mode.Normal) {
|
||||
@ -416,205 +330,185 @@ function execMotion(
|
||||
document: document,
|
||||
position: selection.active,
|
||||
selectionIndex: i,
|
||||
vimState: vimState
|
||||
});
|
||||
return new vscode.Selection(newPosition, newPosition);
|
||||
vimState: vimState,
|
||||
})
|
||||
return new vscode.Selection(newPosition, newPosition)
|
||||
} else if (vimState.mode === Mode.Visual) {
|
||||
const vimSelection = vscodeToVimVisualSelection(document, selection);
|
||||
const vimSelection = vscodeToVimVisualSelection(document, selection)
|
||||
const motionPosition = motion({
|
||||
document: document,
|
||||
position: vimSelection.active,
|
||||
selectionIndex: i,
|
||||
vimState: vimState
|
||||
});
|
||||
vimState: vimState,
|
||||
})
|
||||
|
||||
return vimToVscodeVisualSelection(
|
||||
document,
|
||||
new vscode.Selection(vimSelection.anchor, motionPosition)
|
||||
);
|
||||
new vscode.Selection(vimSelection.anchor, motionPosition),
|
||||
)
|
||||
} else if (vimState.mode === Mode.VisualLine) {
|
||||
const vimSelection = vscodeToVimVisualLineSelection(document, selection);
|
||||
const vimSelection = vscodeToVimVisualLineSelection(document, selection)
|
||||
const motionPosition = motion({
|
||||
document: document,
|
||||
position: vimSelection.active,
|
||||
selectionIndex: i,
|
||||
vimState: vimState
|
||||
});
|
||||
vimState: vimState,
|
||||
})
|
||||
|
||||
return vimToVscodeVisualLineSelection(
|
||||
document,
|
||||
new vscode.Selection(vimSelection.anchor, motionPosition)
|
||||
);
|
||||
new vscode.Selection(vimSelection.anchor, motionPosition),
|
||||
)
|
||||
} else {
|
||||
return selection;
|
||||
return selection
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
editor.selections = newSelections;
|
||||
editor.selections = newSelections
|
||||
|
||||
editor.revealRange(
|
||||
new vscode.Range(newSelections[0].active, newSelections[0].active),
|
||||
vscode.TextEditorRevealType.InCenterIfOutsideViewport
|
||||
);
|
||||
vscode.TextEditorRevealType.InCenterIfOutsideViewport,
|
||||
)
|
||||
}
|
||||
|
||||
function findForward(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
outerMatch: RegExpMatchArray
|
||||
outerMatch: RegExpMatchArray,
|
||||
): void {
|
||||
execRegexMotion(
|
||||
vimState,
|
||||
editor,
|
||||
outerMatch,
|
||||
({ document, position, match }) => {
|
||||
const fromPosition = position.with({ character: position.character + 1 });
|
||||
const result = searchForward(document, match[1], fromPosition);
|
||||
execRegexMotion(vimState, editor, outerMatch, ({ document, position, match }) => {
|
||||
const fromPosition = position.with({ character: position.character + 1 })
|
||||
const result = searchForward(document, match[1], fromPosition)
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
} else {
|
||||
return position;
|
||||
}
|
||||
if (result) {
|
||||
return result
|
||||
} else {
|
||||
return position
|
||||
}
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
function findBackward(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
outerMatch: RegExpMatchArray
|
||||
outerMatch: RegExpMatchArray,
|
||||
): void {
|
||||
execRegexMotion(
|
||||
vimState,
|
||||
editor,
|
||||
outerMatch,
|
||||
({ document, position, match }) => {
|
||||
const fromPosition = positionLeftWrap(document, position);
|
||||
const result = searchBackward(document, match[1], fromPosition);
|
||||
execRegexMotion(vimState, editor, outerMatch, ({ document, position, match }) => {
|
||||
const fromPosition = positionLeftWrap(document, position)
|
||||
const result = searchBackward(document, match[1], fromPosition)
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
} else {
|
||||
return position;
|
||||
}
|
||||
if (result) {
|
||||
return result
|
||||
} else {
|
||||
return position
|
||||
}
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
function tillForward(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
outerMatch: RegExpMatchArray
|
||||
outerMatch: RegExpMatchArray,
|
||||
): void {
|
||||
execRegexMotion(
|
||||
vimState,
|
||||
editor,
|
||||
outerMatch,
|
||||
({ document, position, match }) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const result = lineText.indexOf(match[1], position.character + 1);
|
||||
execRegexMotion(vimState, editor, outerMatch, ({ document, position, match }) => {
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const result = lineText.indexOf(match[1], position.character + 1)
|
||||
|
||||
if (result >= 0) {
|
||||
return position.with({ character: result });
|
||||
} else {
|
||||
return position;
|
||||
}
|
||||
if (result >= 0) {
|
||||
return position.with({ character: result })
|
||||
} else {
|
||||
return position
|
||||
}
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
function tillBackward(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
outerMatch: RegExpMatchArray
|
||||
outerMatch: RegExpMatchArray,
|
||||
): void {
|
||||
execRegexMotion(
|
||||
vimState,
|
||||
editor,
|
||||
outerMatch,
|
||||
({ document, position, match }) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const result = lineText.lastIndexOf(match[1], position.character - 1);
|
||||
execRegexMotion(vimState, editor, outerMatch, ({ document, position, match }) => {
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const result = lineText.lastIndexOf(match[1], position.character - 1)
|
||||
|
||||
if (result >= 0) {
|
||||
return position.with({ character: result });
|
||||
} else {
|
||||
return position;
|
||||
}
|
||||
if (result >= 0) {
|
||||
return position.with({ character: result })
|
||||
} else {
|
||||
return position
|
||||
}
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
function positionLeftWrap(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
): vscode.Position {
|
||||
if (position.character === 0) {
|
||||
if (position.line === 0) {
|
||||
return position;
|
||||
return position
|
||||
} else {
|
||||
const lineLength = document.lineAt(position.line - 1).text.length;
|
||||
return new vscode.Position(position.line - 1, lineLength);
|
||||
const lineLength = document.lineAt(position.line - 1).text.length
|
||||
return new vscode.Position(position.line - 1, lineLength)
|
||||
}
|
||||
} else {
|
||||
return position.with({ character: position.character - 1 });
|
||||
return position.with({ character: position.character - 1 })
|
||||
}
|
||||
}
|
||||
|
||||
function createWordForwardHandler(
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[]
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[],
|
||||
): (vimState: VimState, editor: vscode.TextEditor) => void {
|
||||
return (vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const ranges = wordRangesFunction(lineText);
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const ranges = wordRangesFunction(lineText)
|
||||
|
||||
const result = ranges.find(x => x.start > position.character);
|
||||
const result = ranges.find((x) => x.start > position.character)
|
||||
|
||||
if (result) {
|
||||
return position.with({ character: result.start });
|
||||
return position.with({ character: result.start })
|
||||
} else {
|
||||
return position;
|
||||
return position
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function createWordBackwardHandler(
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[]
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[],
|
||||
): (vimState: VimState, editor: vscode.TextEditor) => void {
|
||||
return (vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const ranges = wordRangesFunction(lineText);
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const ranges = wordRangesFunction(lineText)
|
||||
|
||||
const result = ranges.reverse().find(x => x.start < position.character);
|
||||
const result = ranges.reverse().find((x) => x.start < position.character)
|
||||
|
||||
if (result) {
|
||||
return position.with({ character: result.start });
|
||||
return position.with({ character: result.start })
|
||||
} else {
|
||||
return position;
|
||||
return position
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function createWordEndHandler(
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[]
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[],
|
||||
): (vimState: VimState, editor: vscode.TextEditor) => void {
|
||||
return (vimState, editor) => {
|
||||
execMotion(vimState, editor, ({ document, position }) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const ranges = wordRangesFunction(lineText);
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const ranges = wordRangesFunction(lineText)
|
||||
|
||||
const result = ranges.find(x => x.end > position.character);
|
||||
const result = ranges.find((x) => x.end > position.character)
|
||||
|
||||
if (result) {
|
||||
return position.with({ character: result.end });
|
||||
return position.with({ character: result.end })
|
||||
} else {
|
||||
return position;
|
||||
return position
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,27 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import {
|
||||
createOperatorRangeExactKeys,
|
||||
createOperatorRangeRegex,
|
||||
} from "../parse_keys";
|
||||
import { OperatorRange } from "../parse_keys_types";
|
||||
import { createOperatorRangeExactKeys, createOperatorRangeRegex } from '../parse_keys'
|
||||
import { OperatorRange } from '../parse_keys_types'
|
||||
import {
|
||||
searchForward,
|
||||
searchBackward,
|
||||
searchBackwardBracket,
|
||||
searchForwardBracket,
|
||||
} from "../search_utils";
|
||||
import * as positionUtils from "../position_utils";
|
||||
import { wordRanges, whitespaceWordRanges } from "../word_utils";
|
||||
} from '../search_utils'
|
||||
import * as positionUtils from '../position_utils'
|
||||
import { wordRanges, whitespaceWordRanges } from '../word_utils'
|
||||
import {
|
||||
paragraphForward,
|
||||
paragraphBackward,
|
||||
paragraphRangeOuter,
|
||||
paragraphRangeInner,
|
||||
} from "../paragraph_utils";
|
||||
import { VimState } from "../vim_state_types";
|
||||
import { quoteRanges, findQuoteRange } from "../quote_utils";
|
||||
import { indentLevelRange } from "../indent_utils";
|
||||
import { blockRange } from "../block_utils";
|
||||
import { getTags } from "../tag_utils";
|
||||
import { arrayFindLast } from "../array_utils";
|
||||
} from '../paragraph_utils'
|
||||
import { VimState } from '../vim_state_types'
|
||||
import { quoteRanges, findQuoteRange } from '../quote_utils'
|
||||
import { indentLevelRange } from '../indent_utils'
|
||||
import { blockRange } from '../block_utils'
|
||||
import { getTags } from '../tag_utils'
|
||||
import { arrayFindLast } from '../array_utils'
|
||||
// import KeyMap from "./keymap";
|
||||
|
||||
export const operatorRanges: OperatorRange[] = [
|
||||
@ -93,647 +90,476 @@ export const operatorRanges: OperatorRange[] = [
|
||||
// }
|
||||
// ),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["w"],
|
||||
false,
|
||||
createWordForwardHandler(wordRanges)
|
||||
),
|
||||
createOperatorRangeExactKeys(
|
||||
["W"],
|
||||
false,
|
||||
createWordForwardHandler(whitespaceWordRanges)
|
||||
),
|
||||
createOperatorRangeExactKeys(['w'], false, createWordForwardHandler(wordRanges)),
|
||||
createOperatorRangeExactKeys(['W'], false, createWordForwardHandler(whitespaceWordRanges)),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["b"],
|
||||
false,
|
||||
createWordBackwardHandler(wordRanges)
|
||||
),
|
||||
createOperatorRangeExactKeys(
|
||||
["B"],
|
||||
false,
|
||||
createWordBackwardHandler(whitespaceWordRanges)
|
||||
),
|
||||
createOperatorRangeExactKeys(['b'], false, createWordBackwardHandler(wordRanges)),
|
||||
createOperatorRangeExactKeys(['B'], false, createWordBackwardHandler(whitespaceWordRanges)),
|
||||
|
||||
createOperatorRangeExactKeys(["e"], false, createWordEndHandler(wordRanges)),
|
||||
createOperatorRangeExactKeys(
|
||||
["E"],
|
||||
false,
|
||||
createWordEndHandler(whitespaceWordRanges)
|
||||
),
|
||||
createOperatorRangeExactKeys(['e'], false, createWordEndHandler(wordRanges)),
|
||||
createOperatorRangeExactKeys(['E'], false, createWordEndHandler(whitespaceWordRanges)),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["i", "w"],
|
||||
false,
|
||||
createInnerWordHandler(wordRanges)
|
||||
),
|
||||
createOperatorRangeExactKeys(
|
||||
["i", "W"],
|
||||
false,
|
||||
createInnerWordHandler(whitespaceWordRanges)
|
||||
),
|
||||
createOperatorRangeExactKeys(['i', 'w'], false, createInnerWordHandler(wordRanges)),
|
||||
createOperatorRangeExactKeys(['i', 'W'], false, createInnerWordHandler(whitespaceWordRanges)),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["a", "w"],
|
||||
false,
|
||||
createOuterWordHandler(wordRanges)
|
||||
),
|
||||
createOperatorRangeExactKeys(
|
||||
["a", "W"],
|
||||
false,
|
||||
createOuterWordHandler(whitespaceWordRanges)
|
||||
),
|
||||
createOperatorRangeExactKeys(['a', 'w'], false, createOuterWordHandler(wordRanges)),
|
||||
createOperatorRangeExactKeys(['a', 'W'], false, createOuterWordHandler(whitespaceWordRanges)),
|
||||
|
||||
createOperatorRangeRegex(
|
||||
/^f(..)$/,
|
||||
/^(f|f.)$/,
|
||||
false,
|
||||
(vimState, document, position, match) => {
|
||||
const fromPosition = position.with({ character: position.character + 1 });
|
||||
const result = searchForward(document, match[1], fromPosition);
|
||||
createOperatorRangeRegex(/^f(..)$/, /^(f|f.)$/, false, (vimState, document, position, match) => {
|
||||
const fromPosition = position.with({ character: position.character + 1 })
|
||||
const result = searchForward(document, match[1], fromPosition)
|
||||
|
||||
if (result) {
|
||||
return new vscode.Range(position, result);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
if (result) {
|
||||
return new vscode.Range(position, result)
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
),
|
||||
}),
|
||||
|
||||
createOperatorRangeRegex(
|
||||
/^F(..)$/,
|
||||
/^(F|F.)$/,
|
||||
false,
|
||||
(vimState, document, position, match) => {
|
||||
const fromPosition = position.with({ character: position.character - 1 });
|
||||
const result = searchBackward(document, match[1], fromPosition);
|
||||
createOperatorRangeRegex(/^F(..)$/, /^(F|F.)$/, false, (vimState, document, position, match) => {
|
||||
const fromPosition = position.with({ character: position.character - 1 })
|
||||
const result = searchBackward(document, match[1], fromPosition)
|
||||
|
||||
if (result) {
|
||||
return new vscode.Range(position, result);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
if (result) {
|
||||
return new vscode.Range(position, result)
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
),
|
||||
}),
|
||||
|
||||
createOperatorRangeRegex(
|
||||
/^t(.)$/,
|
||||
/^t$/,
|
||||
false,
|
||||
(vimState, document, position, match) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const result = lineText.indexOf(match[1], position.character + 1);
|
||||
createOperatorRangeRegex(/^t(.)$/, /^t$/, false, (vimState, document, position, match) => {
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const result = lineText.indexOf(match[1], position.character + 1)
|
||||
|
||||
if (result >= 0) {
|
||||
return new vscode.Range(position, position.with({ character: result }));
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
if (result >= 0) {
|
||||
return new vscode.Range(position, position.with({ character: result }))
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
),
|
||||
}),
|
||||
|
||||
createOperatorRangeRegex(
|
||||
/^T(.)$/,
|
||||
/^T$/,
|
||||
false,
|
||||
(vimState, document, position, match) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const result = lineText.lastIndexOf(match[1], position.character - 1);
|
||||
createOperatorRangeRegex(/^T(.)$/, /^T$/, false, (vimState, document, position, match) => {
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const result = lineText.lastIndexOf(match[1], position.character - 1)
|
||||
|
||||
if (result >= 0) {
|
||||
const newPosition = positionUtils.right(
|
||||
document,
|
||||
position.with({ character: result })
|
||||
);
|
||||
return new vscode.Range(newPosition, position);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
if (result >= 0) {
|
||||
const newPosition = positionUtils.right(document, position.with({ character: result }))
|
||||
return new vscode.Range(newPosition, position)
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
),
|
||||
}),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["g", "g"],
|
||||
true,
|
||||
(vimState, document, position) => {
|
||||
const lineLength = document.lineAt(position.line).text.length;
|
||||
createOperatorRangeExactKeys(['g', 'g'], true, (vimState, document, position) => {
|
||||
const lineLength = document.lineAt(position.line).text.length
|
||||
|
||||
return new vscode.Range(
|
||||
new vscode.Position(0, 0),
|
||||
position.with({ character: lineLength })
|
||||
);
|
||||
}
|
||||
),
|
||||
return new vscode.Range(new vscode.Position(0, 0), position.with({ character: lineLength }))
|
||||
}),
|
||||
|
||||
createOperatorRangeExactKeys(["G"], true, (vimState, document, position) => {
|
||||
const lineLength = document.lineAt(document.lineCount - 1).text.length;
|
||||
createOperatorRangeExactKeys(['G'], true, (vimState, document, position) => {
|
||||
const lineLength = document.lineAt(document.lineCount - 1).text.length
|
||||
|
||||
return new vscode.Range(
|
||||
position.with({ character: 0 }),
|
||||
new vscode.Position(document.lineCount - 1, lineLength)
|
||||
);
|
||||
new vscode.Position(document.lineCount - 1, lineLength),
|
||||
)
|
||||
}),
|
||||
|
||||
// TODO: return undefined?
|
||||
createOperatorRangeExactKeys(["}"], true, (vimState, document, position) => {
|
||||
createOperatorRangeExactKeys(['}'], true, (vimState, document, position) => {
|
||||
return new vscode.Range(
|
||||
position.with({ character: 0 }),
|
||||
new vscode.Position(paragraphForward(document, position.line), 0)
|
||||
);
|
||||
new vscode.Position(paragraphForward(document, position.line), 0),
|
||||
)
|
||||
}),
|
||||
|
||||
// TODO: return undefined?
|
||||
createOperatorRangeExactKeys(["{"], true, (vimState, document, position) => {
|
||||
createOperatorRangeExactKeys(['{'], true, (vimState, document, position) => {
|
||||
return new vscode.Range(
|
||||
new vscode.Position(paragraphBackward(document, position.line), 0),
|
||||
position.with({ character: 0 })
|
||||
);
|
||||
position.with({ character: 0 }),
|
||||
)
|
||||
}),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["i", "p"],
|
||||
true,
|
||||
(vimState, document, position) => {
|
||||
const result = paragraphRangeInner(document, position.line);
|
||||
createOperatorRangeExactKeys(['i', 'p'], true, (vimState, document, position) => {
|
||||
const result = paragraphRangeInner(document, position.line)
|
||||
|
||||
if (result) {
|
||||
if (result) {
|
||||
return new vscode.Range(
|
||||
new vscode.Position(result.start, 0),
|
||||
new vscode.Position(result.end, document.lineAt(result.end).text.length),
|
||||
)
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}),
|
||||
|
||||
createOperatorRangeExactKeys(['a', 'p'], true, (vimState, document, position) => {
|
||||
const result = paragraphRangeOuter(document, position.line)
|
||||
|
||||
if (result) {
|
||||
return new vscode.Range(
|
||||
new vscode.Position(result.start, 0),
|
||||
new vscode.Position(result.end, document.lineAt(result.end).text.length),
|
||||
)
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}),
|
||||
|
||||
createOperatorRangeExactKeys(['i', "'"], false, createInnerQuoteHandler("'")),
|
||||
createOperatorRangeExactKeys(['a', "'"], false, createOuterQuoteHandler("'")),
|
||||
|
||||
createOperatorRangeExactKeys(['i', '"'], false, createInnerQuoteHandler('"')),
|
||||
createOperatorRangeExactKeys(['a', '"'], false, createOuterQuoteHandler('"')),
|
||||
|
||||
createOperatorRangeExactKeys(['i', '`'], false, createInnerQuoteHandler('`')),
|
||||
createOperatorRangeExactKeys(['a', '`'], false, createOuterQuoteHandler('`')),
|
||||
|
||||
createOperatorRangeExactKeys(['i', '('], false, createInnerBracketHandler('(', ')')),
|
||||
createOperatorRangeExactKeys(['a', '('], false, createOuterBracketHandler('(', ')')),
|
||||
|
||||
createOperatorRangeExactKeys(['i', '{'], false, createInnerBracketHandler('{', '}')),
|
||||
createOperatorRangeExactKeys(['a', '{'], false, createOuterBracketHandler('{', '}')),
|
||||
|
||||
createOperatorRangeExactKeys(['i', '['], false, createInnerBracketHandler('[', ']')),
|
||||
createOperatorRangeExactKeys(['a', '['], false, createOuterBracketHandler('[', ']')),
|
||||
|
||||
createOperatorRangeExactKeys(['i', '<'], false, createInnerBracketHandler('<', '>')),
|
||||
createOperatorRangeExactKeys(['a', '<'], false, createOuterBracketHandler('<', '>')),
|
||||
|
||||
createOperatorRangeExactKeys(['i', 't'], false, (vimState, document, position) => {
|
||||
const tags = getTags(document)
|
||||
|
||||
const closestTag = arrayFindLast(tags, (tag) => {
|
||||
if (tag.closing) {
|
||||
return (
|
||||
position.isAfterOrEqual(tag.opening.start) && position.isBeforeOrEqual(tag.closing.end)
|
||||
)
|
||||
} else {
|
||||
// Self-closing tags have no inside
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
if (closestTag) {
|
||||
if (closestTag.closing) {
|
||||
return new vscode.Range(
|
||||
new vscode.Position(result.start, 0),
|
||||
new vscode.Position(
|
||||
result.end,
|
||||
document.lineAt(result.end).text.length
|
||||
)
|
||||
);
|
||||
closestTag.opening.end.with({
|
||||
character: closestTag.opening.end.character + 1,
|
||||
}),
|
||||
closestTag.closing.start,
|
||||
)
|
||||
} else {
|
||||
return undefined;
|
||||
throw new Error('We should have already filtered out self-closing tags above')
|
||||
}
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
),
|
||||
}),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["a", "p"],
|
||||
true,
|
||||
(vimState, document, position) => {
|
||||
const result = paragraphRangeOuter(document, position.line);
|
||||
createOperatorRangeExactKeys(['a', 't'], false, (vimState, document, position) => {
|
||||
const tags = getTags(document)
|
||||
|
||||
if (result) {
|
||||
const closestTag = arrayFindLast(tags, (tag) => {
|
||||
const afterStart = position.isAfterOrEqual(tag.opening.start)
|
||||
|
||||
if (tag.closing) {
|
||||
return afterStart && position.isBeforeOrEqual(tag.closing.end)
|
||||
} else {
|
||||
return afterStart && position.isBeforeOrEqual(tag.opening.end)
|
||||
}
|
||||
})
|
||||
|
||||
if (closestTag) {
|
||||
if (closestTag.closing) {
|
||||
return new vscode.Range(
|
||||
new vscode.Position(result.start, 0),
|
||||
new vscode.Position(
|
||||
result.end,
|
||||
document.lineAt(result.end).text.length
|
||||
)
|
||||
);
|
||||
closestTag.opening.start,
|
||||
closestTag.closing.end.with({
|
||||
character: closestTag.closing.end.character + 1,
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
return undefined;
|
||||
return new vscode.Range(
|
||||
closestTag.opening.start,
|
||||
closestTag.opening.end.with({
|
||||
character: closestTag.opening.end.character + 1,
|
||||
}),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
),
|
||||
|
||||
createOperatorRangeExactKeys(["i", "'"], false, createInnerQuoteHandler("'")),
|
||||
createOperatorRangeExactKeys(["a", "'"], false, createOuterQuoteHandler("'")),
|
||||
|
||||
createOperatorRangeExactKeys(["i", '"'], false, createInnerQuoteHandler('"')),
|
||||
createOperatorRangeExactKeys(["a", '"'], false, createOuterQuoteHandler('"')),
|
||||
|
||||
createOperatorRangeExactKeys(["i", "`"], false, createInnerQuoteHandler("`")),
|
||||
createOperatorRangeExactKeys(["a", "`"], false, createOuterQuoteHandler("`")),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["i", "("],
|
||||
false,
|
||||
createInnerBracketHandler("(", ")")
|
||||
),
|
||||
createOperatorRangeExactKeys(
|
||||
["a", "("],
|
||||
false,
|
||||
createOuterBracketHandler("(", ")")
|
||||
),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["i", "{"],
|
||||
false,
|
||||
createInnerBracketHandler("{", "}")
|
||||
),
|
||||
createOperatorRangeExactKeys(
|
||||
["a", "{"],
|
||||
false,
|
||||
createOuterBracketHandler("{", "}")
|
||||
),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["i", "["],
|
||||
false,
|
||||
createInnerBracketHandler("[", "]")
|
||||
),
|
||||
createOperatorRangeExactKeys(
|
||||
["a", "["],
|
||||
false,
|
||||
createOuterBracketHandler("[", "]")
|
||||
),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["i", "<"],
|
||||
false,
|
||||
createInnerBracketHandler("<", ">")
|
||||
),
|
||||
createOperatorRangeExactKeys(
|
||||
["a", "<"],
|
||||
false,
|
||||
createOuterBracketHandler("<", ">")
|
||||
),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["i", "t"],
|
||||
false,
|
||||
(vimState, document, position) => {
|
||||
const tags = getTags(document);
|
||||
|
||||
const closestTag = arrayFindLast(tags, (tag) => {
|
||||
if (tag.closing) {
|
||||
return (
|
||||
position.isAfterOrEqual(tag.opening.start) &&
|
||||
position.isBeforeOrEqual(tag.closing.end)
|
||||
);
|
||||
} else {
|
||||
// Self-closing tags have no inside
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (closestTag) {
|
||||
if (closestTag.closing) {
|
||||
return new vscode.Range(
|
||||
closestTag.opening.end.with({
|
||||
character: closestTag.opening.end.character + 1,
|
||||
}),
|
||||
closestTag.closing.start
|
||||
);
|
||||
} else {
|
||||
throw new Error(
|
||||
"We should have already filtered out self-closing tags above"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["a", "t"],
|
||||
false,
|
||||
(vimState, document, position) => {
|
||||
const tags = getTags(document);
|
||||
|
||||
const closestTag = arrayFindLast(tags, (tag) => {
|
||||
const afterStart = position.isAfterOrEqual(tag.opening.start);
|
||||
|
||||
if (tag.closing) {
|
||||
return afterStart && position.isBeforeOrEqual(tag.closing.end);
|
||||
} else {
|
||||
return afterStart && position.isBeforeOrEqual(tag.opening.end);
|
||||
}
|
||||
});
|
||||
|
||||
if (closestTag) {
|
||||
if (closestTag.closing) {
|
||||
return new vscode.Range(
|
||||
closestTag.opening.start,
|
||||
closestTag.closing.end.with({
|
||||
character: closestTag.closing.end.character + 1,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
return new vscode.Range(
|
||||
closestTag.opening.start,
|
||||
closestTag.opening.end.with({
|
||||
character: closestTag.opening.end.character + 1,
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
),
|
||||
}),
|
||||
|
||||
// TODO: return undefined?
|
||||
createOperatorRangeExactKeys(
|
||||
["i", "i"],
|
||||
true,
|
||||
(vimState, document, position) => {
|
||||
const simpleRange = indentLevelRange(document, position.line);
|
||||
createOperatorRangeExactKeys(['i', 'i'], true, (vimState, document, position) => {
|
||||
const simpleRange = indentLevelRange(document, position.line)
|
||||
|
||||
return new vscode.Range(
|
||||
new vscode.Position(simpleRange.start, 0),
|
||||
new vscode.Position(
|
||||
simpleRange.end,
|
||||
document.lineAt(simpleRange.end).text.length
|
||||
)
|
||||
);
|
||||
}
|
||||
),
|
||||
return new vscode.Range(
|
||||
new vscode.Position(simpleRange.start, 0),
|
||||
new vscode.Position(simpleRange.end, document.lineAt(simpleRange.end).text.length),
|
||||
)
|
||||
}),
|
||||
|
||||
createOperatorRangeExactKeys(
|
||||
["a", "b"],
|
||||
true,
|
||||
(vimState, document, position) => {
|
||||
const range = blockRange(document, position);
|
||||
createOperatorRangeExactKeys(['a', 'b'], true, (vimState, document, position) => {
|
||||
const range = blockRange(document, position)
|
||||
|
||||
return range;
|
||||
}
|
||||
),
|
||||
];
|
||||
return range
|
||||
}),
|
||||
]
|
||||
|
||||
function createInnerBracketHandler(
|
||||
openingChar: string,
|
||||
closingChar: string
|
||||
closingChar: string,
|
||||
): (
|
||||
vimState: VimState,
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
) => vscode.Range | undefined {
|
||||
return (vimState, document, position) => {
|
||||
const bracketRange = getBracketRange(
|
||||
document,
|
||||
position,
|
||||
openingChar,
|
||||
closingChar
|
||||
);
|
||||
const bracketRange = getBracketRange(document, position, openingChar, closingChar)
|
||||
|
||||
if (bracketRange) {
|
||||
return new vscode.Range(
|
||||
bracketRange.start.with({
|
||||
character: bracketRange.start.character + 1,
|
||||
}),
|
||||
bracketRange.end
|
||||
);
|
||||
bracketRange.end,
|
||||
)
|
||||
} else {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createOuterBracketHandler(
|
||||
openingChar: string,
|
||||
closingChar: string
|
||||
closingChar: string,
|
||||
): (
|
||||
vimState: VimState,
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
) => vscode.Range | undefined {
|
||||
return (vimState, document, position) => {
|
||||
const bracketRange = getBracketRange(
|
||||
document,
|
||||
position,
|
||||
openingChar,
|
||||
closingChar
|
||||
);
|
||||
const bracketRange = getBracketRange(document, position, openingChar, closingChar)
|
||||
|
||||
if (bracketRange) {
|
||||
return new vscode.Range(
|
||||
bracketRange.start,
|
||||
bracketRange.end.with({ character: bracketRange.end.character + 1 })
|
||||
);
|
||||
bracketRange.end.with({ character: bracketRange.end.character + 1 }),
|
||||
)
|
||||
} else {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function getBracketRange(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position,
|
||||
openingChar: string,
|
||||
closingChar: string
|
||||
closingChar: string,
|
||||
): vscode.Range | undefined {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const currentChar = lineText[position.character];
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const currentChar = lineText[position.character]
|
||||
|
||||
let start;
|
||||
let end;
|
||||
let start
|
||||
let end
|
||||
if (currentChar === openingChar) {
|
||||
start = position;
|
||||
start = position
|
||||
end = searchForwardBracket(
|
||||
document,
|
||||
openingChar,
|
||||
closingChar,
|
||||
positionUtils.rightWrap(document, position)
|
||||
);
|
||||
positionUtils.rightWrap(document, position),
|
||||
)
|
||||
} else if (currentChar === closingChar) {
|
||||
start = searchBackwardBracket(
|
||||
document,
|
||||
openingChar,
|
||||
closingChar,
|
||||
positionUtils.leftWrap(document, position)
|
||||
);
|
||||
end = position;
|
||||
positionUtils.leftWrap(document, position),
|
||||
)
|
||||
end = position
|
||||
} else {
|
||||
start = searchBackwardBracket(document, openingChar, closingChar, position);
|
||||
end = searchForwardBracket(document, openingChar, closingChar, position);
|
||||
start = searchBackwardBracket(document, openingChar, closingChar, position)
|
||||
end = searchForwardBracket(document, openingChar, closingChar, position)
|
||||
}
|
||||
|
||||
if (start && end) {
|
||||
return new vscode.Range(start, end);
|
||||
return new vscode.Range(start, end)
|
||||
} else {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
function createInnerQuoteHandler(
|
||||
quoteChar: string
|
||||
quoteChar: string,
|
||||
): (
|
||||
vimState: VimState,
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
) => vscode.Range | undefined {
|
||||
return (vimState, document, position) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const ranges = quoteRanges(quoteChar, lineText);
|
||||
const result = findQuoteRange(ranges, position);
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const ranges = quoteRanges(quoteChar, lineText)
|
||||
const result = findQuoteRange(ranges, position)
|
||||
|
||||
if (result) {
|
||||
return new vscode.Range(
|
||||
position.with({ character: result.start + 1 }),
|
||||
position.with({ character: result.end })
|
||||
);
|
||||
position.with({ character: result.end }),
|
||||
)
|
||||
} else {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createOuterQuoteHandler(
|
||||
quoteChar: string
|
||||
quoteChar: string,
|
||||
): (
|
||||
vimState: VimState,
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
) => vscode.Range | undefined {
|
||||
return (vimState, document, position) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const ranges = quoteRanges(quoteChar, lineText);
|
||||
const result = findQuoteRange(ranges, position);
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const ranges = quoteRanges(quoteChar, lineText)
|
||||
const result = findQuoteRange(ranges, position)
|
||||
|
||||
if (result) {
|
||||
return new vscode.Range(
|
||||
position.with({ character: result.start }),
|
||||
position.with({ character: result.end + 1 })
|
||||
);
|
||||
position.with({ character: result.end + 1 }),
|
||||
)
|
||||
} else {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createWordForwardHandler(
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[]
|
||||
): (
|
||||
vimState: VimState,
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
) => vscode.Range {
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[],
|
||||
): (vimState: VimState, document: vscode.TextDocument, position: vscode.Position) => vscode.Range {
|
||||
return (vimState, document, position) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const ranges = wordRangesFunction(lineText);
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const ranges = wordRangesFunction(lineText)
|
||||
|
||||
const result = ranges.find((x) => x.start > position.character);
|
||||
const result = ranges.find((x) => x.start > position.character)
|
||||
|
||||
if (result) {
|
||||
return new vscode.Range(
|
||||
position,
|
||||
position.with({ character: result.start })
|
||||
);
|
||||
return new vscode.Range(position, position.with({ character: result.start }))
|
||||
} else {
|
||||
return new vscode.Range(
|
||||
position,
|
||||
position.with({ character: lineText.length })
|
||||
);
|
||||
return new vscode.Range(position, position.with({ character: lineText.length }))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createWordBackwardHandler(
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[]
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[],
|
||||
): (
|
||||
vimState: VimState,
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
) => vscode.Range | undefined {
|
||||
return (vimState, document, position) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const ranges = wordRangesFunction(lineText);
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const ranges = wordRangesFunction(lineText)
|
||||
|
||||
const result = ranges.reverse().find((x) => x.start < position.character);
|
||||
const result = ranges.reverse().find((x) => x.start < position.character)
|
||||
|
||||
if (result) {
|
||||
return new vscode.Range(
|
||||
position.with({ character: result.start }),
|
||||
position
|
||||
);
|
||||
return new vscode.Range(position.with({ character: result.start }), position)
|
||||
} else {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createWordEndHandler(
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[]
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[],
|
||||
): (
|
||||
vimState: VimState,
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
) => vscode.Range | undefined {
|
||||
return (vimState, document, position) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const ranges = wordRangesFunction(lineText);
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const ranges = wordRangesFunction(lineText)
|
||||
|
||||
const result = ranges.find((x) => x.end > position.character);
|
||||
const result = ranges.find((x) => x.end > position.character)
|
||||
|
||||
if (result) {
|
||||
return new vscode.Range(
|
||||
position,
|
||||
positionUtils.right(document, position.with({ character: result.end }))
|
||||
);
|
||||
positionUtils.right(document, position.with({ character: result.end })),
|
||||
)
|
||||
} else {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createInnerWordHandler(
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[]
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[],
|
||||
): (
|
||||
vimState: VimState,
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
) => vscode.Range | undefined {
|
||||
return (vimState, document, position) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const ranges = wordRangesFunction(lineText);
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const ranges = wordRangesFunction(lineText)
|
||||
|
||||
const result = ranges.find(
|
||||
(x) => x.start <= position.character && position.character <= x.end
|
||||
);
|
||||
const result = ranges.find((x) => x.start <= position.character && position.character <= x.end)
|
||||
|
||||
if (result) {
|
||||
return new vscode.Range(
|
||||
position.with({ character: result.start }),
|
||||
positionUtils.right(document, position.with({ character: result.end }))
|
||||
);
|
||||
positionUtils.right(document, position.with({ character: result.end })),
|
||||
)
|
||||
} else {
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createOuterWordHandler(
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[]
|
||||
wordRangesFunction: (text: string) => { start: number; end: number }[],
|
||||
): (
|
||||
vimState: VimState,
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
) => vscode.Range | undefined {
|
||||
return (vimState, document, position) => {
|
||||
const lineText = document.lineAt(position.line).text;
|
||||
const ranges = wordRangesFunction(lineText);
|
||||
const lineText = document.lineAt(position.line).text
|
||||
const ranges = wordRangesFunction(lineText)
|
||||
|
||||
for (let i = 0; i < ranges.length; ++i) {
|
||||
const range = ranges[i];
|
||||
const range = ranges[i]
|
||||
|
||||
if (
|
||||
range.start <= position.character &&
|
||||
position.character <= range.end
|
||||
) {
|
||||
if (range.start <= position.character && position.character <= range.end) {
|
||||
if (i < ranges.length - 1) {
|
||||
return new vscode.Range(
|
||||
position.with({ character: range.start }),
|
||||
position.with({ character: ranges[i + 1].start })
|
||||
);
|
||||
position.with({ character: ranges[i + 1].start }),
|
||||
)
|
||||
} else if (i > 0) {
|
||||
return new vscode.Range(
|
||||
positionUtils.right(
|
||||
document,
|
||||
position.with({ character: ranges[i - 1].end })
|
||||
),
|
||||
positionUtils.right(
|
||||
document,
|
||||
position.with({ character: range.end })
|
||||
)
|
||||
);
|
||||
positionUtils.right(document, position.with({ character: ranges[i - 1].end })),
|
||||
positionUtils.right(document, position.with({ character: range.end })),
|
||||
)
|
||||
} else {
|
||||
return new vscode.Range(
|
||||
position.with({ character: range.start }),
|
||||
positionUtils.right(
|
||||
document,
|
||||
position.with({ character: range.end })
|
||||
)
|
||||
);
|
||||
positionUtils.right(document, position.with({ character: range.end })),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
@ -1,244 +1,214 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { Action } from "../action_types";
|
||||
import { operatorRanges } from "./operator_ranges";
|
||||
import { parseKeysOperator } from "../parse_keys";
|
||||
import { Action } from '../action_types'
|
||||
import { operatorRanges } from './operator_ranges'
|
||||
import { parseKeysOperator } from '../parse_keys'
|
||||
import {
|
||||
enterInsertMode,
|
||||
enterNormalMode,
|
||||
setModeCursorStyle,
|
||||
enterVisualLineMode,
|
||||
enterVisualMode
|
||||
} from "../modes";
|
||||
import { removeTypeSubscription } from "../type_subscription";
|
||||
import { VimState } from "../vim_state_types";
|
||||
import { Mode } from "../modes_types";
|
||||
import { flashYankHighlight } from "../yank_highlight";
|
||||
enterVisualMode,
|
||||
} from '../modes'
|
||||
import { removeTypeSubscription } from '../type_subscription'
|
||||
import { VimState } from '../vim_state_types'
|
||||
import { Mode } from '../modes_types'
|
||||
import { flashYankHighlight } from '../yank_highlight'
|
||||
|
||||
export const operators: Action[] = [
|
||||
parseKeysOperator(
|
||||
["d"],
|
||||
operatorRanges,
|
||||
(vimState, editor, ranges, linewise) => {
|
||||
if (ranges.every(x => x === undefined)) return;
|
||||
parseKeysOperator(['d'], operatorRanges, (vimState, editor, ranges, linewise) => {
|
||||
if (ranges.every((x) => x === undefined)) return
|
||||
|
||||
cursorsToRangesStart(editor, ranges);
|
||||
cursorsToRangesStart(editor, ranges)
|
||||
|
||||
delete_(editor, ranges, linewise);
|
||||
delete_(editor, ranges, linewise)
|
||||
|
||||
if (vimState.mode === Mode.Visual || vimState.mode === Mode.VisualLine) {
|
||||
enterNormalMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
}
|
||||
if (vimState.mode === Mode.Visual || vimState.mode === Mode.VisualLine) {
|
||||
enterNormalMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
}
|
||||
),
|
||||
parseKeysOperator(
|
||||
["c"],
|
||||
operatorRanges,
|
||||
(vimState, editor, ranges, linewise) => {
|
||||
if (ranges.every(x => x === undefined)) return;
|
||||
}),
|
||||
parseKeysOperator(['c'], operatorRanges, (vimState, editor, ranges, _linewise) => {
|
||||
if (ranges.every((x) => x === undefined)) return
|
||||
|
||||
cursorsToRangesStart(editor, ranges);
|
||||
cursorsToRangesStart(editor, ranges)
|
||||
|
||||
editor.edit(editBuilder => {
|
||||
ranges.forEach(range => {
|
||||
if (!range) return;
|
||||
editBuilder.delete(range);
|
||||
});
|
||||
});
|
||||
editor.edit((editBuilder) => {
|
||||
ranges.forEach((range) => {
|
||||
if (!range) return
|
||||
editBuilder.delete(range)
|
||||
})
|
||||
})
|
||||
|
||||
enterInsertMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
removeTypeSubscription(vimState);
|
||||
}
|
||||
),
|
||||
parseKeysOperator(
|
||||
["y"],
|
||||
operatorRanges,
|
||||
(vimState, editor, ranges, linewise) => {
|
||||
if (ranges.every(x => x === undefined)) return;
|
||||
enterInsertMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
removeTypeSubscription(vimState)
|
||||
}),
|
||||
parseKeysOperator(['y'], operatorRanges, (vimState, editor, ranges, linewise) => {
|
||||
if (ranges.every((x) => x === undefined)) return
|
||||
|
||||
yank(vimState, editor, ranges, linewise);
|
||||
yank(vimState, editor, ranges, linewise)
|
||||
|
||||
if (vimState.mode === Mode.Visual || vimState.mode === Mode.VisualLine) {
|
||||
// Move cursor to start of yanked text
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
return new vscode.Selection(selection.start, selection.start);
|
||||
});
|
||||
if (vimState.mode === Mode.Visual || vimState.mode === Mode.VisualLine) {
|
||||
// Move cursor to start of yanked text
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
return new vscode.Selection(selection.start, selection.start)
|
||||
})
|
||||
|
||||
enterNormalMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
} else {
|
||||
// Yank highlight
|
||||
const highlightRanges: vscode.Range[] = [];
|
||||
ranges.forEach(range => {
|
||||
if (range) {
|
||||
highlightRanges.push(new vscode.Range(range.start, range.end));
|
||||
}
|
||||
});
|
||||
flashYankHighlight(editor, highlightRanges);
|
||||
}
|
||||
}
|
||||
),
|
||||
parseKeysOperator(
|
||||
["r"],
|
||||
operatorRanges,
|
||||
(vimState, editor, ranges, linewise) => {
|
||||
if (ranges.every(x => x === undefined)) return;
|
||||
|
||||
cursorsToRangesStart(editor, ranges);
|
||||
|
||||
yank(vimState, editor, ranges, linewise);
|
||||
delete_(editor, ranges, linewise);
|
||||
|
||||
if (vimState.mode === Mode.Visual || vimState.mode === Mode.VisualLine) {
|
||||
enterNormalMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
}
|
||||
}
|
||||
),
|
||||
parseKeysOperator(
|
||||
["s"],
|
||||
operatorRanges,
|
||||
(vimState, editor, ranges, linewise) => {
|
||||
if (
|
||||
ranges.every(x => x === undefined) ||
|
||||
vimState.mode === Mode.Visual ||
|
||||
vimState.mode === Mode.VisualLine
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
editor.selections = ranges.map((range, i) => {
|
||||
enterNormalMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
} else {
|
||||
// Yank highlight
|
||||
const highlightRanges: vscode.Range[] = []
|
||||
ranges.forEach((range) => {
|
||||
if (range) {
|
||||
const start = range.start;
|
||||
const end = range.end;
|
||||
return new vscode.Selection(start, end);
|
||||
} else {
|
||||
return editor.selections[i];
|
||||
highlightRanges.push(new vscode.Range(range.start, range.end))
|
||||
}
|
||||
});
|
||||
})
|
||||
flashYankHighlight(editor, highlightRanges)
|
||||
}
|
||||
}),
|
||||
parseKeysOperator(['r'], operatorRanges, (vimState, editor, ranges, linewise) => {
|
||||
if (ranges.every((x) => x === undefined)) return
|
||||
|
||||
if (linewise) {
|
||||
enterVisualLineMode(vimState);
|
||||
cursorsToRangesStart(editor, ranges)
|
||||
|
||||
yank(vimState, editor, ranges, linewise)
|
||||
delete_(editor, ranges, linewise)
|
||||
|
||||
if (vimState.mode === Mode.Visual || vimState.mode === Mode.VisualLine) {
|
||||
enterNormalMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
}
|
||||
}),
|
||||
parseKeysOperator(['s'], operatorRanges, (vimState, editor, ranges, linewise) => {
|
||||
if (
|
||||
ranges.every((x) => x === undefined) ||
|
||||
vimState.mode === Mode.Visual ||
|
||||
vimState.mode === Mode.VisualLine
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
editor.selections = ranges.map((range, i) => {
|
||||
if (range) {
|
||||
const start = range.start
|
||||
const end = range.end
|
||||
return new vscode.Selection(start, end)
|
||||
} else {
|
||||
enterVisualMode(vimState);
|
||||
return editor.selections[i]
|
||||
}
|
||||
})
|
||||
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
if (linewise) {
|
||||
enterVisualLineMode(vimState)
|
||||
} else {
|
||||
enterVisualMode(vimState)
|
||||
}
|
||||
),
|
||||
parseKeysOperator(
|
||||
["q"],
|
||||
operatorRanges,
|
||||
(vimState, editor, ranges, linewise) => {
|
||||
if (
|
||||
ranges.every(x => x === undefined) ||
|
||||
vimState.mode === Mode.Visual ||
|
||||
vimState.mode === Mode.VisualLine
|
||||
) {
|
||||
return;
|
||||
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
}),
|
||||
parseKeysOperator(['q'], operatorRanges, (vimState, editor, ranges, _linewise) => {
|
||||
if (
|
||||
ranges.every((x) => x === undefined) ||
|
||||
vimState.mode === Mode.Visual ||
|
||||
vimState.mode === Mode.VisualLine
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
editor.selections = ranges.map((range, i) => {
|
||||
if (range) {
|
||||
const start = range.start
|
||||
const end = range.end
|
||||
return new vscode.Selection(start, end)
|
||||
} else {
|
||||
return editor.selections[i]
|
||||
}
|
||||
})
|
||||
|
||||
editor.selections = ranges.map((range, i) => {
|
||||
if (range) {
|
||||
const start = range.start;
|
||||
const end = range.end;
|
||||
return new vscode.Selection(start, end);
|
||||
} else {
|
||||
return editor.selections[i];
|
||||
}
|
||||
});
|
||||
vscode.commands.executeCommand('editor.action.copyLinesDownAction')
|
||||
}),
|
||||
]
|
||||
|
||||
vscode.commands.executeCommand("editor.action.copyLinesDownAction");
|
||||
}
|
||||
)
|
||||
];
|
||||
|
||||
function cursorsToRangesStart(
|
||||
editor: vscode.TextEditor,
|
||||
ranges: (vscode.Range | undefined)[]
|
||||
) {
|
||||
function cursorsToRangesStart(editor: vscode.TextEditor, ranges: (vscode.Range | undefined)[]) {
|
||||
editor.selections = editor.selections.map((selection, i) => {
|
||||
const range = ranges[i];
|
||||
const range = ranges[i]
|
||||
|
||||
if (range) {
|
||||
const newPosition = range.start;
|
||||
return new vscode.Selection(newPosition, newPosition);
|
||||
const newPosition = range.start
|
||||
return new vscode.Selection(newPosition, newPosition)
|
||||
} else {
|
||||
return selection;
|
||||
return selection
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function delete_(
|
||||
editor: vscode.TextEditor,
|
||||
ranges: (vscode.Range | undefined)[],
|
||||
linewise: boolean
|
||||
linewise: boolean,
|
||||
) {
|
||||
editor
|
||||
.edit(editBuilder => {
|
||||
ranges.forEach(range => {
|
||||
if (!range) return;
|
||||
.edit((editBuilder) => {
|
||||
ranges.forEach((range) => {
|
||||
if (!range) return
|
||||
|
||||
let deleteRange = range;
|
||||
let deleteRange = range
|
||||
|
||||
if (linewise) {
|
||||
const start = range.start;
|
||||
const end = range.end;
|
||||
const start = range.start
|
||||
const end = range.end
|
||||
|
||||
if (end.line === editor.document.lineCount - 1) {
|
||||
if (start.line === 0) {
|
||||
deleteRange = new vscode.Range(start.with({ character: 0 }), end);
|
||||
deleteRange = new vscode.Range(start.with({ character: 0 }), end)
|
||||
} else {
|
||||
deleteRange = new vscode.Range(
|
||||
new vscode.Position(
|
||||
start.line - 1,
|
||||
editor.document.lineAt(start.line - 1).text.length
|
||||
editor.document.lineAt(start.line - 1).text.length,
|
||||
),
|
||||
end
|
||||
);
|
||||
end,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
deleteRange = new vscode.Range(
|
||||
range.start,
|
||||
new vscode.Position(end.line + 1, 0)
|
||||
);
|
||||
deleteRange = new vscode.Range(range.start, new vscode.Position(end.line + 1, 0))
|
||||
}
|
||||
}
|
||||
|
||||
editBuilder.delete(deleteRange);
|
||||
});
|
||||
editBuilder.delete(deleteRange)
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
// For linewise deletions, make sure cursor is at beginning of line
|
||||
editor.selections = editor.selections.map((selection, i) => {
|
||||
const range = ranges[i];
|
||||
const range = ranges[i]
|
||||
|
||||
if (range && linewise) {
|
||||
const newPosition = selection.start.with({ character: 0 });
|
||||
return new vscode.Selection(newPosition, newPosition);
|
||||
const newPosition = selection.start.with({ character: 0 })
|
||||
return new vscode.Selection(newPosition, newPosition)
|
||||
} else {
|
||||
return selection;
|
||||
return selection
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function yank(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
ranges: (vscode.Range | undefined)[],
|
||||
linewise: boolean
|
||||
linewise: boolean,
|
||||
) {
|
||||
vimState.registers = {
|
||||
contentsList: ranges.map((range, i) => {
|
||||
if (range) {
|
||||
return editor.document.getText(range);
|
||||
return editor.document.getText(range)
|
||||
} else {
|
||||
return vimState.registers.contentsList[i];
|
||||
return vimState.registers.contentsList[i]
|
||||
}
|
||||
}),
|
||||
linewise: linewise
|
||||
};
|
||||
linewise: linewise,
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
export function arrayFindLast<T>(xs: T[], p: (x: T) => boolean): T | undefined {
|
||||
const filtered = xs.filter(p);
|
||||
const filtered = xs.filter(p)
|
||||
|
||||
if (filtered.length === 0) {
|
||||
return undefined;
|
||||
return undefined
|
||||
} else {
|
||||
return filtered[filtered.length - 1];
|
||||
return filtered[filtered.length - 1]
|
||||
}
|
||||
}
|
||||
|
@ -1,137 +1,129 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
enum MatchType {
|
||||
start = "start",
|
||||
end = "end",
|
||||
start = 'start',
|
||||
end = 'end',
|
||||
}
|
||||
|
||||
interface BlockMatch {
|
||||
type: MatchType;
|
||||
match: RegExpMatchArray;
|
||||
type: MatchType
|
||||
match: RegExpMatchArray
|
||||
}
|
||||
|
||||
const startRegex = (startWords: string[]) =>
|
||||
RegExp(`(^|\\s)(${startWords.join("|")})($|\\s)`, "g");
|
||||
const startRegex = (startWords: string[]) => RegExp(`(^|\\s)(${startWords.join('|')})($|\\s)`, 'g')
|
||||
|
||||
const endRegex = (endWords: string[]) =>
|
||||
RegExp(`(^|\\s)(${endWords.join("|")})($|\\W)`, "g");
|
||||
const endRegex = (endWords: string[]) => RegExp(`(^|\\s)(${endWords.join('|')})($|\\W)`, 'g')
|
||||
|
||||
export function blockRange(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
): vscode.Range {
|
||||
let startWords: string[] = [];
|
||||
let endWords: string[] = [];
|
||||
export function blockRange(document: vscode.TextDocument, position: vscode.Position): vscode.Range {
|
||||
let startWords: string[] = []
|
||||
let endWords: string[] = []
|
||||
|
||||
console.log(`LanguageID=${document.languageId}`);
|
||||
if (document.languageId === "elixir") {
|
||||
startWords = ["case", "cond", "fn", "def"];
|
||||
endWords = ["end"];
|
||||
console.log(`LanguageID=${document.languageId}`)
|
||||
if (document.languageId === 'elixir') {
|
||||
startWords = ['case', 'cond', 'fn', 'def']
|
||||
endWords = ['end']
|
||||
} else {
|
||||
console.log(`Unsupported language: ${document.languageId}`);
|
||||
return new vscode.Range(position, position);
|
||||
console.log(`Unsupported language: ${document.languageId}`)
|
||||
return new vscode.Range(position, position)
|
||||
}
|
||||
|
||||
const start = findBlockStart(document, position, startWords, endWords);
|
||||
const end = findBlockEnd(document, position, startWords, endWords);
|
||||
const start = findBlockStart(document, position, startWords, endWords)
|
||||
const end = findBlockEnd(document, position, startWords, endWords)
|
||||
|
||||
if (start && end) {
|
||||
return new vscode.Range(start, end);
|
||||
return new vscode.Range(start, end)
|
||||
}
|
||||
return new vscode.Range(position, position);
|
||||
return new vscode.Range(position, position)
|
||||
}
|
||||
|
||||
function findBlockStart(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position,
|
||||
startWords: string[],
|
||||
endWords: string[]
|
||||
endWords: string[],
|
||||
): vscode.Position | undefined {
|
||||
let closedBlocks: boolean[] = [];
|
||||
const closedBlocks: boolean[] = []
|
||||
|
||||
for (let i = position.line; i >= 0; --i) {
|
||||
let lineText =
|
||||
const lineText =
|
||||
i === position.line
|
||||
? document.lineAt(i).text.substr(position.character)
|
||||
: document.lineAt(i).text;
|
||||
: document.lineAt(i).text
|
||||
|
||||
let blockMatches: BlockMatch[] = [];
|
||||
let blockMatches: BlockMatch[] = []
|
||||
for (const m of lineText.matchAll(startRegex(startWords))) {
|
||||
blockMatches.push({ type: MatchType.start, match: m });
|
||||
blockMatches.push({ type: MatchType.start, match: m })
|
||||
}
|
||||
|
||||
for (const m of lineText.matchAll(endRegex(endWords))) {
|
||||
blockMatches.push({ type: MatchType.end, match: m });
|
||||
blockMatches.push({ type: MatchType.end, match: m })
|
||||
}
|
||||
|
||||
blockMatches = blockMatches.sort((a, b) =>
|
||||
(a.match.index as number) > (b.match.index as number) ? 1 : -1
|
||||
);
|
||||
(a.match.index as number) > (b.match.index as number) ? 1 : -1,
|
||||
)
|
||||
|
||||
for (let idx = 0; idx < blockMatches.length; idx++) {
|
||||
const blockMatch = blockMatches[idx];
|
||||
const blockMatch = blockMatches[idx]
|
||||
if (blockMatch.type === MatchType.end) {
|
||||
closedBlocks.push(true);
|
||||
closedBlocks.push(true)
|
||||
} else if (blockMatch.type === MatchType.start) {
|
||||
if (closedBlocks.length === 0) {
|
||||
const [fullText, , matchText] = blockMatch.match;
|
||||
const offset = fullText.indexOf(matchText);
|
||||
return new vscode.Position(
|
||||
i,
|
||||
(blockMatch.match.index as number) + offset
|
||||
);
|
||||
const [fullText, , matchText] = blockMatch.match
|
||||
const offset = fullText.indexOf(matchText)
|
||||
return new vscode.Position(i, (blockMatch.match.index as number) + offset)
|
||||
} else {
|
||||
closedBlocks.pop();
|
||||
closedBlocks.pop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
||||
function findBlockEnd(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position,
|
||||
startWords: string[],
|
||||
endWords: string[]
|
||||
endWords: string[],
|
||||
): vscode.Position | undefined {
|
||||
let openedBlocks: boolean[] = [true];
|
||||
const openedBlocks: boolean[] = [true]
|
||||
|
||||
for (let i = position.line; i < document.lineCount; ++i) {
|
||||
let lineText =
|
||||
const lineText =
|
||||
i === position.line
|
||||
? document.lineAt(i).text.substr(position.character)
|
||||
: document.lineAt(i).text;
|
||||
: document.lineAt(i).text
|
||||
|
||||
let blockMatches: BlockMatch[] = [];
|
||||
let blockMatches: BlockMatch[] = []
|
||||
for (const m of lineText.matchAll(startRegex(startWords))) {
|
||||
blockMatches.push({ type: MatchType.start, match: m });
|
||||
blockMatches.push({ type: MatchType.start, match: m })
|
||||
}
|
||||
|
||||
for (const m of lineText.matchAll(endRegex(endWords))) {
|
||||
blockMatches.push({ type: MatchType.end, match: m });
|
||||
blockMatches.push({ type: MatchType.end, match: m })
|
||||
}
|
||||
|
||||
blockMatches = blockMatches.sort((a, b) =>
|
||||
(a.match.index as number) > (b.match.index as number) ? 1 : -1
|
||||
);
|
||||
(a.match.index as number) > (b.match.index as number) ? 1 : -1,
|
||||
)
|
||||
|
||||
for (let idx = 0; idx < blockMatches.length; idx++) {
|
||||
const blockMatch = blockMatches[idx];
|
||||
const blockMatch = blockMatches[idx]
|
||||
if (blockMatch.type === MatchType.start) {
|
||||
openedBlocks.push(true);
|
||||
openedBlocks.push(true)
|
||||
} else if (blockMatch.type === MatchType.end) {
|
||||
openedBlocks.pop();
|
||||
openedBlocks.pop()
|
||||
if (openedBlocks.length === 0) {
|
||||
const [fullText, , matchText] = blockMatch.match;
|
||||
const offset = fullText.indexOf(matchText);
|
||||
const [fullText, , matchText] = blockMatch.match
|
||||
const offset = fullText.indexOf(matchText)
|
||||
return new vscode.Position(
|
||||
i,
|
||||
(blockMatch.match.index as number) + offset + matchText.length
|
||||
);
|
||||
(blockMatch.match.index as number) + offset + matchText.length,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
@ -1,53 +1,53 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { VimState } from "./vim_state_types";
|
||||
import { enterNormalMode, setModeCursorStyle } from "./modes";
|
||||
import { addTypeSubscription } from "./type_subscription";
|
||||
import { typeHandler } from "./type_handler";
|
||||
import * as positionUtils from "./position_utils";
|
||||
import { Mode } from "./modes_types";
|
||||
import { VimState } from './vim_state_types'
|
||||
import { enterNormalMode, setModeCursorStyle } from './modes'
|
||||
import { addTypeSubscription } from './type_subscription'
|
||||
import { typeHandler } from './type_handler'
|
||||
import * as positionUtils from './position_utils'
|
||||
import { Mode } from './modes_types'
|
||||
|
||||
export function escapeHandler(vimState: VimState): void {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
const editor = vscode.window.activeTextEditor
|
||||
|
||||
if (!editor) return;
|
||||
if (!editor) return
|
||||
|
||||
if (vimState.mode === Mode.Insert || vimState.mode === Mode.Occurrence) {
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
const newPosition = positionUtils.left(selection.active);
|
||||
return new vscode.Selection(newPosition, newPosition);
|
||||
});
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
const newPosition = positionUtils.left(selection.active)
|
||||
return new vscode.Selection(newPosition, newPosition)
|
||||
})
|
||||
|
||||
enterNormalMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
addTypeSubscription(vimState, typeHandler);
|
||||
enterNormalMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
addTypeSubscription(vimState, typeHandler)
|
||||
} else if (vimState.mode === Mode.Normal) {
|
||||
// Clear multiple cursors
|
||||
if (editor.selections.length > 1) {
|
||||
editor.selections = [editor.selections[0]];
|
||||
editor.selections = [editor.selections[0]]
|
||||
}
|
||||
} else if (vimState.mode === Mode.Visual) {
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
const newPosition = new vscode.Position(
|
||||
selection.active.line,
|
||||
Math.max(selection.active.character - 1, 0)
|
||||
);
|
||||
return new vscode.Selection(newPosition, newPosition);
|
||||
});
|
||||
Math.max(selection.active.character - 1, 0),
|
||||
)
|
||||
return new vscode.Selection(newPosition, newPosition)
|
||||
})
|
||||
|
||||
enterNormalMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
enterNormalMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
} else if (vimState.mode === Mode.VisualLine) {
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
const newPosition = selection.active.with({
|
||||
character: Math.max(selection.active.character - 1, 0)
|
||||
});
|
||||
return new vscode.Selection(newPosition, newPosition);
|
||||
});
|
||||
character: Math.max(selection.active.character - 1, 0),
|
||||
})
|
||||
return new vscode.Selection(newPosition, newPosition)
|
||||
})
|
||||
|
||||
enterNormalMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
enterNormalMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
}
|
||||
|
||||
vimState.keysPressed = [];
|
||||
vimState.keysPressed = []
|
||||
}
|
||||
|
@ -1,196 +1,179 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { SimpleRange } from "./simple_range_types";
|
||||
import { SimpleRange } from './simple_range_types'
|
||||
|
||||
export function indentLevelRange(
|
||||
document: vscode.TextDocument,
|
||||
lineNumber: number
|
||||
): SimpleRange {
|
||||
const indentLevel = findIndentLevel(document, lineNumber);
|
||||
const rangeStart = indentLevelRangeBefore(document, lineNumber, indentLevel);
|
||||
const rangeEnd = indentLevelRangeAfter(document, lineNumber + 1, indentLevel);
|
||||
export function indentLevelRange(document: vscode.TextDocument, lineNumber: number): SimpleRange {
|
||||
const indentLevel = findIndentLevel(document, lineNumber)
|
||||
const rangeStart = indentLevelRangeBefore(document, lineNumber, indentLevel)
|
||||
const rangeEnd = indentLevelRangeAfter(document, lineNumber + 1, indentLevel)
|
||||
|
||||
if (rangeStart && rangeEnd) {
|
||||
return { start: rangeStart.start, end: rangeEnd.end };
|
||||
return { start: rangeStart.start, end: rangeEnd.end }
|
||||
} else if (rangeStart) {
|
||||
return rangeStart;
|
||||
return rangeStart
|
||||
} else if (rangeEnd) {
|
||||
return rangeEnd;
|
||||
return rangeEnd
|
||||
} else {
|
||||
// This will never happen but the typechecker can't know that
|
||||
return { start: lineNumber, end: lineNumber };
|
||||
return { start: lineNumber, end: lineNumber }
|
||||
}
|
||||
}
|
||||
|
||||
export function aroundIndentLevelRange(
|
||||
document: vscode.TextDocument,
|
||||
lineNumber: number
|
||||
lineNumber: number,
|
||||
): SimpleRange {
|
||||
const indentLevel = findIndentLevel(document, lineNumber);
|
||||
const rangeStart = aroundIndentLevelRangeBefore(
|
||||
document,
|
||||
lineNumber,
|
||||
indentLevel
|
||||
);
|
||||
const rangeEnd = aroundIndentLevelRangeAfter(
|
||||
document,
|
||||
lineNumber + 1,
|
||||
indentLevel
|
||||
);
|
||||
const indentLevel = findIndentLevel(document, lineNumber)
|
||||
const rangeStart = aroundIndentLevelRangeBefore(document, lineNumber, indentLevel)
|
||||
const rangeEnd = aroundIndentLevelRangeAfter(document, lineNumber + 1, indentLevel)
|
||||
|
||||
if (rangeStart && rangeEnd) {
|
||||
return { start: rangeStart.start, end: rangeEnd.end };
|
||||
return { start: rangeStart.start, end: rangeEnd.end }
|
||||
} else if (rangeStart) {
|
||||
return rangeStart;
|
||||
return rangeStart
|
||||
} else if (rangeEnd) {
|
||||
return rangeEnd;
|
||||
return rangeEnd
|
||||
} else {
|
||||
// This will never happen but the typechecker can't know that
|
||||
return { start: lineNumber, end: lineNumber };
|
||||
return { start: lineNumber, end: lineNumber }
|
||||
}
|
||||
}
|
||||
|
||||
function aroundIndentLevelRangeBefore(
|
||||
document: vscode.TextDocument,
|
||||
lineNumber: number,
|
||||
indentLevel: number
|
||||
indentLevel: number,
|
||||
): SimpleRange | undefined {
|
||||
let result;
|
||||
const insideRange = indentLevelRangeBefore(document, lineNumber, indentLevel);
|
||||
if (typeof insideRange !== "undefined") {
|
||||
result = insideRange;
|
||||
let result
|
||||
const insideRange = indentLevelRangeBefore(document, lineNumber, indentLevel)
|
||||
if (typeof insideRange !== 'undefined') {
|
||||
result = insideRange
|
||||
for (let i = Math.max(0, insideRange.start - 1); i >= 0; --i) {
|
||||
const line = document.lineAt(i);
|
||||
const line = document.lineAt(i)
|
||||
|
||||
if (!line.isEmptyOrWhitespace) {
|
||||
result.start = i;
|
||||
result.start = i
|
||||
} else {
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
function indentLevelRangeBefore(
|
||||
document: vscode.TextDocument,
|
||||
lineNumber: number,
|
||||
indentLevel: number
|
||||
indentLevel: number,
|
||||
): SimpleRange | undefined {
|
||||
let result;
|
||||
let result
|
||||
|
||||
for (let i = lineNumber; i >= 0; --i) {
|
||||
const line = document.lineAt(i);
|
||||
const line = document.lineAt(i)
|
||||
|
||||
if (line.firstNonWhitespaceCharacterIndex >= indentLevel) {
|
||||
// if (!line.isEmptyOrWhitespace) {
|
||||
if (result) {
|
||||
result.start = i;
|
||||
result.start = i
|
||||
} else {
|
||||
result = { start: i, end: i };
|
||||
result = { start: i, end: i }
|
||||
}
|
||||
// }
|
||||
} else {
|
||||
if (!line.isEmptyOrWhitespace) {
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
function aroundIndentLevelRangeAfter(
|
||||
document: vscode.TextDocument,
|
||||
lineNumber: number,
|
||||
indentLevel: number
|
||||
indentLevel: number,
|
||||
): SimpleRange | undefined {
|
||||
let result;
|
||||
const insideRange = indentLevelRangeAfter(document, lineNumber, indentLevel);
|
||||
if (typeof insideRange !== "undefined") {
|
||||
result = insideRange;
|
||||
let result
|
||||
const insideRange = indentLevelRangeAfter(document, lineNumber, indentLevel)
|
||||
if (typeof insideRange !== 'undefined') {
|
||||
result = insideRange
|
||||
for (let i = insideRange.end + 1; i < document.lineCount; ++i) {
|
||||
const line = document.lineAt(i);
|
||||
const line = document.lineAt(i)
|
||||
|
||||
if (!line.isEmptyOrWhitespace) {
|
||||
result.end = i;
|
||||
result.end = i
|
||||
} else {
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
function indentLevelRangeAfter(
|
||||
document: vscode.TextDocument,
|
||||
lineNumber: number,
|
||||
indentLevel: number
|
||||
indentLevel: number,
|
||||
): SimpleRange | undefined {
|
||||
let result;
|
||||
let result
|
||||
|
||||
for (let i = lineNumber; i < document.lineCount; ++i) {
|
||||
const line = document.lineAt(i);
|
||||
const line = document.lineAt(i)
|
||||
|
||||
if (line.firstNonWhitespaceCharacterIndex >= indentLevel) {
|
||||
// if (!line.isEmptyOrWhitespace) {
|
||||
if (result) {
|
||||
result.end = i;
|
||||
result.end = i
|
||||
} else {
|
||||
result = { start: i, end: i };
|
||||
result = { start: i, end: i }
|
||||
}
|
||||
// }
|
||||
} else {
|
||||
if (!line.isEmptyOrWhitespace) {
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
function findIndentLevel(document: vscode.TextDocument, lineNumber: number) {
|
||||
const line = document.lineAt(lineNumber);
|
||||
const line = document.lineAt(lineNumber)
|
||||
|
||||
if (!line.isEmptyOrWhitespace) {
|
||||
return line.firstNonWhitespaceCharacterIndex;
|
||||
return line.firstNonWhitespaceCharacterIndex
|
||||
}
|
||||
|
||||
return Math.max(
|
||||
findIndentLevelForward(document, lineNumber + 1),
|
||||
findIndentLevelBackward(document, lineNumber - 1)
|
||||
);
|
||||
findIndentLevelBackward(document, lineNumber - 1),
|
||||
)
|
||||
}
|
||||
|
||||
function findIndentLevelForward(
|
||||
document: vscode.TextDocument,
|
||||
lineNumber: number
|
||||
): number {
|
||||
function findIndentLevelForward(document: vscode.TextDocument, lineNumber: number): number {
|
||||
for (let i = lineNumber; i < document.lineCount; ++i) {
|
||||
const line = document.lineAt(i);
|
||||
const line = document.lineAt(i)
|
||||
|
||||
if (!line.isEmptyOrWhitespace) {
|
||||
return line.firstNonWhitespaceCharacterIndex;
|
||||
return line.firstNonWhitespaceCharacterIndex
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
function findIndentLevelBackward(
|
||||
document: vscode.TextDocument,
|
||||
lineNumber: number
|
||||
): number {
|
||||
function findIndentLevelBackward(document: vscode.TextDocument, lineNumber: number): number {
|
||||
for (let i = lineNumber; i >= 0; --i) {
|
||||
const line = document.lineAt(i);
|
||||
const line = document.lineAt(i)
|
||||
|
||||
if (!line.isEmptyOrWhitespace) {
|
||||
return line.firstNonWhitespaceCharacterIndex;
|
||||
return line.firstNonWhitespaceCharacterIndex
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
101
src/index.ts
101
src/index.ts
@ -1,15 +1,12 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { Mode } from "./modes_types";
|
||||
import * as scrollCommands from "./scroll_commands";
|
||||
import { enterNormalMode, enterVisualMode, setModeCursorStyle } from "./modes";
|
||||
import { typeHandler } from "./type_handler";
|
||||
import {
|
||||
addTypeSubscription,
|
||||
removeTypeSubscription
|
||||
} from "./type_subscription";
|
||||
import { VimState } from "./vim_state_types";
|
||||
import { escapeHandler } from "./escape_handler";
|
||||
import { Mode } from './modes_types'
|
||||
import * as scrollCommands from './scroll_commands'
|
||||
import { enterNormalMode, enterVisualMode, setModeCursorStyle } from './modes'
|
||||
import { typeHandler } from './type_handler'
|
||||
import { addTypeSubscription, removeTypeSubscription } from './type_subscription'
|
||||
import { VimState } from './vim_state_types'
|
||||
import { escapeHandler } from './escape_handler'
|
||||
|
||||
const globalVimState: VimState = {
|
||||
typeSubscription: undefined,
|
||||
@ -17,23 +14,20 @@ const globalVimState: VimState = {
|
||||
keysPressed: [],
|
||||
registers: {
|
||||
contentsList: [],
|
||||
linewise: true
|
||||
linewise: true,
|
||||
},
|
||||
semicolonAction: () => undefined,
|
||||
commaAction: () => undefined,
|
||||
lastPutRanges: {
|
||||
ranges: [],
|
||||
linewise: true
|
||||
}
|
||||
};
|
||||
linewise: true,
|
||||
},
|
||||
}
|
||||
|
||||
function onSelectionChange(
|
||||
vimState: VimState,
|
||||
e: vscode.TextEditorSelectionChangeEvent
|
||||
): void {
|
||||
if (vimState.mode === Mode.Insert) return;
|
||||
function onSelectionChange(vimState: VimState, e: vscode.TextEditorSelectionChangeEvent): void {
|
||||
if (vimState.mode === Mode.Insert) return
|
||||
|
||||
if (e.selections.every(selection => selection.isEmpty)) {
|
||||
if (e.selections.every((selection) => selection.isEmpty)) {
|
||||
// It would be nice if we could always go from visual to normal mode when all selections are empty
|
||||
// but visual mode on an empty line will yield an empty selection and there's no good way of
|
||||
// distinguishing that case from the rest. So we only do it for mouse events.
|
||||
@ -41,75 +35,70 @@ function onSelectionChange(
|
||||
(vimState.mode === Mode.Visual || vimState.mode === Mode.VisualLine) &&
|
||||
e.kind === vscode.TextEditorSelectionChangeKind.Mouse
|
||||
) {
|
||||
enterNormalMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, e.textEditor);
|
||||
enterNormalMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, e.textEditor)
|
||||
}
|
||||
} else {
|
||||
if (vimState.mode === Mode.Normal) {
|
||||
enterVisualMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, e.textEditor);
|
||||
enterVisualMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, e.textEditor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onDidChangeActiveTextEditor(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor | undefined
|
||||
) {
|
||||
if (!editor) return;
|
||||
function onDidChangeActiveTextEditor(vimState: VimState, editor: vscode.TextEditor | undefined) {
|
||||
if (!editor) return
|
||||
|
||||
if (editor.selections.every(selection => selection.isEmpty)) {
|
||||
if (editor.selections.every((selection) => selection.isEmpty)) {
|
||||
if (vimState.mode === Mode.Visual || vimState.mode === Mode.VisualLine) {
|
||||
enterNormalMode(vimState);
|
||||
enterNormalMode(vimState)
|
||||
}
|
||||
} else {
|
||||
if (vimState.mode === Mode.Normal) {
|
||||
enterVisualMode(vimState);
|
||||
enterVisualMode(vimState)
|
||||
}
|
||||
}
|
||||
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
|
||||
vimState.keysPressed = [];
|
||||
vimState.keysPressed = []
|
||||
}
|
||||
|
||||
export function activate(context: vscode.ExtensionContext): void {
|
||||
context.subscriptions.push(
|
||||
vscode.window.onDidChangeActiveTextEditor(editor =>
|
||||
onDidChangeActiveTextEditor(globalVimState, editor)
|
||||
vscode.window.onDidChangeActiveTextEditor((editor) =>
|
||||
onDidChangeActiveTextEditor(globalVimState, editor),
|
||||
),
|
||||
vscode.window.onDidChangeTextEditorSelection(e =>
|
||||
onSelectionChange(globalVimState, e)
|
||||
),
|
||||
vscode.commands.registerCommand("extension.simpleVim.escapeKey", () =>
|
||||
escapeHandler(globalVimState)
|
||||
vscode.window.onDidChangeTextEditorSelection((e) => onSelectionChange(globalVimState, e)),
|
||||
vscode.commands.registerCommand('extension.simpleVim.escapeKey', () =>
|
||||
escapeHandler(globalVimState),
|
||||
),
|
||||
vscode.commands.registerCommand(
|
||||
"extension.simpleVim.scrollDownHalfPage",
|
||||
scrollCommands.scrollDownHalfPage
|
||||
'extension.simpleVim.scrollDownHalfPage',
|
||||
scrollCommands.scrollDownHalfPage,
|
||||
),
|
||||
vscode.commands.registerCommand(
|
||||
"extension.simpleVim.scrollUpHalfPage",
|
||||
scrollCommands.scrollUpHalfPage
|
||||
'extension.simpleVim.scrollUpHalfPage',
|
||||
scrollCommands.scrollUpHalfPage,
|
||||
),
|
||||
vscode.commands.registerCommand(
|
||||
"extension.simpleVim.scrollDownPage",
|
||||
scrollCommands.scrollDownPage
|
||||
'extension.simpleVim.scrollDownPage',
|
||||
scrollCommands.scrollDownPage,
|
||||
),
|
||||
vscode.commands.registerCommand(
|
||||
"extension.simpleVim.scrollUpPage",
|
||||
scrollCommands.scrollUpPage
|
||||
)
|
||||
);
|
||||
'extension.simpleVim.scrollUpPage',
|
||||
scrollCommands.scrollUpPage,
|
||||
),
|
||||
)
|
||||
|
||||
enterNormalMode(globalVimState);
|
||||
addTypeSubscription(globalVimState, typeHandler);
|
||||
enterNormalMode(globalVimState)
|
||||
addTypeSubscription(globalVimState, typeHandler)
|
||||
|
||||
if (vscode.window.activeTextEditor) {
|
||||
onDidChangeActiveTextEditor(globalVimState, vscode.window.activeTextEditor);
|
||||
onDidChangeActiveTextEditor(globalVimState, vscode.window.activeTextEditor)
|
||||
}
|
||||
}
|
||||
|
||||
export function deactivate(): void {
|
||||
removeTypeSubscription(globalVimState);
|
||||
removeTypeSubscription(globalVimState)
|
||||
}
|
||||
|
55
src/modes.ts
55
src/modes.ts
@ -1,56 +1,53 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { Mode } from "./modes_types";
|
||||
import { VimState } from "./vim_state_types";
|
||||
import { Mode } from './modes_types'
|
||||
import { VimState } from './vim_state_types'
|
||||
|
||||
export function enterInsertMode(vimState: VimState): void {
|
||||
vimState.mode = Mode.Insert;
|
||||
setModeContext("extension.simpleVim.insertMode");
|
||||
vimState.mode = Mode.Insert
|
||||
setModeContext('extension.simpleVim.insertMode')
|
||||
}
|
||||
|
||||
export function enterNormalMode(vimState: VimState): void {
|
||||
vimState.mode = Mode.Normal;
|
||||
setModeContext("extension.simpleVim.normalMode");
|
||||
vimState.mode = Mode.Normal
|
||||
setModeContext('extension.simpleVim.normalMode')
|
||||
}
|
||||
|
||||
export function enterVisualMode(vimState: VimState): void {
|
||||
vimState.mode = Mode.Visual;
|
||||
setModeContext("extension.simpleVim.visualMode");
|
||||
vimState.mode = Mode.Visual
|
||||
setModeContext('extension.simpleVim.visualMode')
|
||||
}
|
||||
|
||||
export function enterVisualLineMode(vimState: VimState): void {
|
||||
vimState.mode = Mode.VisualLine;
|
||||
setModeContext("extension.simpleVim.visualLineMode");
|
||||
vimState.mode = Mode.VisualLine
|
||||
setModeContext('extension.simpleVim.visualLineMode')
|
||||
}
|
||||
|
||||
export function enterOccurrenceMode(vimState: VimState): void {
|
||||
vimState.mode = Mode.Occurrence;
|
||||
setModeContext("extension.simpleVim.occurrenceMode");
|
||||
vimState.mode = Mode.Occurrence
|
||||
setModeContext('extension.simpleVim.occurrenceMode')
|
||||
}
|
||||
|
||||
function setModeContext(key: string) {
|
||||
const modeKeys = [
|
||||
"extension.simpleVim.insertMode",
|
||||
"extension.simpleVim.normalMode",
|
||||
"extension.simpleVim.visualMode",
|
||||
"extension.simpleVim.visualLineMode",
|
||||
"extension.simpleVim.occurrenceMode"
|
||||
];
|
||||
'extension.simpleVim.insertMode',
|
||||
'extension.simpleVim.normalMode',
|
||||
'extension.simpleVim.visualMode',
|
||||
'extension.simpleVim.visualLineMode',
|
||||
'extension.simpleVim.occurrenceMode',
|
||||
]
|
||||
|
||||
modeKeys.forEach(modeKey => {
|
||||
vscode.commands.executeCommand("setContext", modeKey, key === modeKey);
|
||||
});
|
||||
modeKeys.forEach((modeKey) => {
|
||||
vscode.commands.executeCommand('setContext', modeKey, key === modeKey)
|
||||
})
|
||||
}
|
||||
|
||||
export function setModeCursorStyle(
|
||||
mode: Mode,
|
||||
editor: vscode.TextEditor
|
||||
): void {
|
||||
export function setModeCursorStyle(mode: Mode, editor: vscode.TextEditor): void {
|
||||
if (mode === Mode.Insert || mode === Mode.Occurrence) {
|
||||
editor.options.cursorStyle = vscode.TextEditorCursorStyle.Line;
|
||||
editor.options.cursorStyle = vscode.TextEditorCursorStyle.Line
|
||||
} else if (mode === Mode.Normal) {
|
||||
editor.options.cursorStyle = vscode.TextEditorCursorStyle.Block;
|
||||
editor.options.cursorStyle = vscode.TextEditorCursorStyle.Block
|
||||
} else if (mode === Mode.Visual || mode === Mode.VisualLine) {
|
||||
editor.options.cursorStyle = vscode.TextEditorCursorStyle.Block;
|
||||
editor.options.cursorStyle = vscode.TextEditorCursorStyle.Block
|
||||
}
|
||||
}
|
||||
|
@ -3,5 +3,5 @@ export enum Mode {
|
||||
Normal,
|
||||
Visual,
|
||||
VisualLine,
|
||||
Occurrence
|
||||
Occurrence,
|
||||
}
|
||||
|
@ -1,111 +1,96 @@
|
||||
import * as vscode from "vscode";
|
||||
import { SimpleRange } from "./simple_range_types";
|
||||
import * as vscode from 'vscode'
|
||||
import { SimpleRange } from './simple_range_types'
|
||||
|
||||
export function paragraphForward(
|
||||
document: vscode.TextDocument,
|
||||
line: number
|
||||
): number {
|
||||
let visitedNonEmptyLine = false;
|
||||
export function paragraphForward(document: vscode.TextDocument, line: number): number {
|
||||
let visitedNonEmptyLine = false
|
||||
|
||||
for (let i = line; i < document.lineCount; ++i) {
|
||||
if (visitedNonEmptyLine) {
|
||||
if (document.lineAt(i).isEmptyOrWhitespace) {
|
||||
return i;
|
||||
return i
|
||||
}
|
||||
} else {
|
||||
if (!document.lineAt(i).isEmptyOrWhitespace) {
|
||||
visitedNonEmptyLine = true;
|
||||
visitedNonEmptyLine = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return document.lineCount - 1;
|
||||
return document.lineCount - 1
|
||||
}
|
||||
|
||||
export function paragraphBackward(
|
||||
document: vscode.TextDocument,
|
||||
line: number
|
||||
): number {
|
||||
let visitedNonEmptyLine = false;
|
||||
export function paragraphBackward(document: vscode.TextDocument, line: number): number {
|
||||
let visitedNonEmptyLine = false
|
||||
|
||||
for (let i = line; i >= 0; --i) {
|
||||
if (visitedNonEmptyLine) {
|
||||
if (document.lineAt(i).isEmptyOrWhitespace) {
|
||||
return i;
|
||||
return i
|
||||
}
|
||||
} else {
|
||||
if (!document.lineAt(i).isEmptyOrWhitespace) {
|
||||
visitedNonEmptyLine = true;
|
||||
visitedNonEmptyLine = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
export function paragraphRangeOuter(
|
||||
document: vscode.TextDocument,
|
||||
line: number
|
||||
line: number,
|
||||
): SimpleRange | undefined {
|
||||
if (document.lineAt(line).isEmptyOrWhitespace) return undefined;
|
||||
if (document.lineAt(line).isEmptyOrWhitespace) return undefined
|
||||
|
||||
return {
|
||||
start: paragraphRangeBackward(document, line - 1),
|
||||
end: paragraphRangeForwardOuter(document, line + 1)
|
||||
};
|
||||
end: paragraphRangeForwardOuter(document, line + 1),
|
||||
}
|
||||
}
|
||||
|
||||
function paragraphRangeForwardOuter(
|
||||
document: vscode.TextDocument,
|
||||
line: number
|
||||
): number {
|
||||
let seenWhitespace = false;
|
||||
function paragraphRangeForwardOuter(document: vscode.TextDocument, line: number): number {
|
||||
let seenWhitespace = false
|
||||
|
||||
for (let i = line; i < document.lineCount; ++i) {
|
||||
if (document.lineAt(i).isEmptyOrWhitespace) {
|
||||
seenWhitespace = true;
|
||||
seenWhitespace = true
|
||||
} else if (seenWhitespace) {
|
||||
return i - 1;
|
||||
return i - 1
|
||||
}
|
||||
}
|
||||
|
||||
return document.lineCount - 1;
|
||||
return document.lineCount - 1
|
||||
}
|
||||
|
||||
function paragraphRangeBackward(
|
||||
document: vscode.TextDocument,
|
||||
line: number
|
||||
): number {
|
||||
function paragraphRangeBackward(document: vscode.TextDocument, line: number): number {
|
||||
for (let i = line; i >= 0; --i) {
|
||||
if (document.lineAt(i).isEmptyOrWhitespace) {
|
||||
return i + 1;
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
export function paragraphRangeInner(
|
||||
document: vscode.TextDocument,
|
||||
line: number
|
||||
line: number,
|
||||
): SimpleRange | undefined {
|
||||
if (document.lineAt(line).isEmptyOrWhitespace) return undefined;
|
||||
if (document.lineAt(line).isEmptyOrWhitespace) return undefined
|
||||
|
||||
return {
|
||||
start: paragraphRangeBackward(document, line - 1),
|
||||
end: paragraphRangeForwardInner(document, line + 1)
|
||||
};
|
||||
end: paragraphRangeForwardInner(document, line + 1),
|
||||
}
|
||||
}
|
||||
|
||||
function paragraphRangeForwardInner(
|
||||
document: vscode.TextDocument,
|
||||
line: number
|
||||
): number {
|
||||
function paragraphRangeForwardInner(document: vscode.TextDocument, line: number): number {
|
||||
for (let i = line; i < document.lineCount; ++i) {
|
||||
if (document.lineAt(i).isEmptyOrWhitespace) {
|
||||
return i - 1;
|
||||
return i - 1
|
||||
}
|
||||
}
|
||||
|
||||
return document.lineCount - 1;
|
||||
return document.lineCount - 1
|
||||
}
|
||||
|
@ -1,113 +1,109 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { VimState } from "./vim_state_types";
|
||||
import { Mode } from "./modes_types";
|
||||
import { VimState } from './vim_state_types'
|
||||
import { Mode } from './modes_types'
|
||||
import {
|
||||
ParseKeysStatus,
|
||||
OperatorRange,
|
||||
ParseFailure,
|
||||
ParseOperatorPartSuccess,
|
||||
ParseOperatorRangeSuccess
|
||||
} from "./parse_keys_types";
|
||||
import { Action } from "./action_types";
|
||||
ParseOperatorRangeSuccess,
|
||||
} from './parse_keys_types'
|
||||
import { Action } from './action_types'
|
||||
|
||||
export function arrayStartsWith<T>(prefix: T[], xs: T[]) {
|
||||
if (xs.length < prefix.length) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
for (let i = 0; i < prefix.length; ++i) {
|
||||
if (prefix[i] !== xs[i]) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
export function arrayEquals<T>(xs: T[], ys: T[]) {
|
||||
if (xs.length !== ys.length) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
for (let i = 0; i < xs.length; ++i) {
|
||||
if (xs[i] !== ys[i]) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
export function parseKeysExact(
|
||||
matchKeys: string[],
|
||||
modes: Mode[],
|
||||
action: (vimState: VimState, editor: vscode.TextEditor) => void
|
||||
action: (vimState: VimState, editor: vscode.TextEditor) => void,
|
||||
): Action {
|
||||
return (vimState, keys, editor) => {
|
||||
if (modes && modes.indexOf(vimState.mode) < 0) {
|
||||
return ParseKeysStatus.NO;
|
||||
return ParseKeysStatus.NO
|
||||
}
|
||||
|
||||
if (arrayEquals(keys, matchKeys)) {
|
||||
action(vimState, editor);
|
||||
return ParseKeysStatus.YES;
|
||||
action(vimState, editor)
|
||||
return ParseKeysStatus.YES
|
||||
} else if (arrayStartsWith(keys, matchKeys)) {
|
||||
return ParseKeysStatus.MORE_INPUT;
|
||||
return ParseKeysStatus.MORE_INPUT
|
||||
} else {
|
||||
return ParseKeysStatus.NO;
|
||||
return ParseKeysStatus.NO
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function parseKeysRegex(
|
||||
doesPattern: RegExp,
|
||||
couldPattern: RegExp,
|
||||
modes: Mode[],
|
||||
action: (
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
match: RegExpMatchArray
|
||||
) => void
|
||||
action: (vimState: VimState, editor: vscode.TextEditor, match: RegExpMatchArray) => void,
|
||||
): Action {
|
||||
return (vimState, keys, editor) => {
|
||||
if (modes && modes.indexOf(vimState.mode) < 0) {
|
||||
return ParseKeysStatus.NO;
|
||||
return ParseKeysStatus.NO
|
||||
}
|
||||
|
||||
const keysStr = keys.join("");
|
||||
const doesMatch = keysStr.match(doesPattern);
|
||||
const keysStr = keys.join('')
|
||||
const doesMatch = keysStr.match(doesPattern)
|
||||
|
||||
if (doesMatch) {
|
||||
action(vimState, editor, doesMatch);
|
||||
return ParseKeysStatus.YES;
|
||||
action(vimState, editor, doesMatch)
|
||||
return ParseKeysStatus.YES
|
||||
} else if (keysStr.match(couldPattern)) {
|
||||
return ParseKeysStatus.MORE_INPUT;
|
||||
return ParseKeysStatus.MORE_INPUT
|
||||
} else {
|
||||
return ParseKeysStatus.NO;
|
||||
return ParseKeysStatus.NO
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function parseOperatorPart(
|
||||
keys: string[],
|
||||
operatorKeys: string[]
|
||||
operatorKeys: string[],
|
||||
): ParseFailure | ParseOperatorPartSuccess {
|
||||
if (arrayStartsWith(operatorKeys, keys)) {
|
||||
return {
|
||||
kind: "success",
|
||||
rest: keys.slice(operatorKeys.length)
|
||||
};
|
||||
kind: 'success',
|
||||
rest: keys.slice(operatorKeys.length),
|
||||
}
|
||||
} else if (arrayStartsWith(keys, operatorKeys)) {
|
||||
return {
|
||||
kind: "failure",
|
||||
status: ParseKeysStatus.MORE_INPUT
|
||||
};
|
||||
kind: 'failure',
|
||||
status: ParseKeysStatus.MORE_INPUT,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
kind: "failure",
|
||||
status: ParseKeysStatus.NO
|
||||
};
|
||||
kind: 'failure',
|
||||
status: ParseKeysStatus.NO,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,29 +111,29 @@ function parseOperatorRangePart(
|
||||
vimState: VimState,
|
||||
keys: string[],
|
||||
editor: vscode.TextEditor,
|
||||
motions: OperatorRange[]
|
||||
motions: OperatorRange[],
|
||||
): ParseFailure | ParseOperatorRangeSuccess {
|
||||
let could = false;
|
||||
let could = false
|
||||
for (const motion of motions) {
|
||||
const result = motion(vimState, keys, editor);
|
||||
const result = motion(vimState, keys, editor)
|
||||
|
||||
if (result.kind === "success") {
|
||||
return result;
|
||||
if (result.kind === 'success') {
|
||||
return result
|
||||
} else if (result.status === ParseKeysStatus.MORE_INPUT) {
|
||||
could = true;
|
||||
could = true
|
||||
}
|
||||
}
|
||||
|
||||
if (could) {
|
||||
return {
|
||||
kind: "failure",
|
||||
status: ParseKeysStatus.MORE_INPUT
|
||||
};
|
||||
kind: 'failure',
|
||||
status: ParseKeysStatus.MORE_INPUT,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
kind: "failure",
|
||||
status: ParseKeysStatus.NO
|
||||
};
|
||||
kind: 'failure',
|
||||
status: ParseKeysStatus.NO,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,45 +144,40 @@ export function parseKeysOperator(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
ranges: (vscode.Range | undefined)[],
|
||||
linewise: boolean
|
||||
) => void
|
||||
linewise: boolean,
|
||||
) => void,
|
||||
): Action {
|
||||
return (vimState, keys, editor) => {
|
||||
const operatorResult = parseOperatorPart(keys, operatorKeys);
|
||||
if (operatorResult.kind === "failure") {
|
||||
return operatorResult.status;
|
||||
const operatorResult = parseOperatorPart(keys, operatorKeys)
|
||||
if (operatorResult.kind === 'failure') {
|
||||
return operatorResult.status
|
||||
}
|
||||
|
||||
let ranges: (vscode.Range | undefined)[];
|
||||
let linewise = true;
|
||||
let ranges: (vscode.Range | undefined)[]
|
||||
let linewise = true
|
||||
if (vimState.mode === Mode.Normal) {
|
||||
if (operatorResult.rest.length === 0) {
|
||||
return ParseKeysStatus.MORE_INPUT;
|
||||
return ParseKeysStatus.MORE_INPUT
|
||||
}
|
||||
|
||||
const motionResult = parseOperatorRangePart(
|
||||
vimState,
|
||||
operatorResult.rest,
|
||||
editor,
|
||||
motions
|
||||
);
|
||||
if (motionResult.kind === "failure") {
|
||||
return motionResult.status;
|
||||
const motionResult = parseOperatorRangePart(vimState, operatorResult.rest, editor, motions)
|
||||
if (motionResult.kind === 'failure') {
|
||||
return motionResult.status
|
||||
}
|
||||
|
||||
ranges = motionResult.ranges;
|
||||
linewise = motionResult.linewise;
|
||||
ranges = motionResult.ranges
|
||||
linewise = motionResult.linewise
|
||||
} else if (vimState.mode === Mode.VisualLine) {
|
||||
ranges = editor.selections;
|
||||
linewise = true;
|
||||
ranges = editor.selections
|
||||
linewise = true
|
||||
} else {
|
||||
ranges = editor.selections;
|
||||
linewise = false;
|
||||
ranges = editor.selections
|
||||
linewise = false
|
||||
}
|
||||
|
||||
operator(vimState, editor, ranges, linewise);
|
||||
return ParseKeysStatus.YES;
|
||||
};
|
||||
operator(vimState, editor, ranges, linewise)
|
||||
return ParseKeysStatus.YES
|
||||
}
|
||||
}
|
||||
|
||||
export function createOperatorRangeExactKeys(
|
||||
@ -195,31 +186,31 @@ export function createOperatorRangeExactKeys(
|
||||
f: (
|
||||
vimState: VimState,
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
) => vscode.Range | undefined
|
||||
position: vscode.Position,
|
||||
) => vscode.Range | undefined,
|
||||
): OperatorRange {
|
||||
return (vimState, keys, editor) => {
|
||||
if (arrayEquals(keys, matchKeys)) {
|
||||
const ranges = editor.selections.map(selection => {
|
||||
return f(vimState, editor.document, selection.active);
|
||||
});
|
||||
const ranges = editor.selections.map((selection) => {
|
||||
return f(vimState, editor.document, selection.active)
|
||||
})
|
||||
return {
|
||||
kind: "success",
|
||||
kind: 'success',
|
||||
ranges: ranges,
|
||||
linewise: linewise
|
||||
};
|
||||
linewise: linewise,
|
||||
}
|
||||
} else if (arrayStartsWith(keys, matchKeys)) {
|
||||
return {
|
||||
kind: "failure",
|
||||
status: ParseKeysStatus.MORE_INPUT
|
||||
};
|
||||
kind: 'failure',
|
||||
status: ParseKeysStatus.MORE_INPUT,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
kind: "failure",
|
||||
status: ParseKeysStatus.NO
|
||||
};
|
||||
kind: 'failure',
|
||||
status: ParseKeysStatus.NO,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function createOperatorRangeRegex(
|
||||
@ -230,32 +221,32 @@ export function createOperatorRangeRegex(
|
||||
vimState: VimState,
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position,
|
||||
match: RegExpMatchArray
|
||||
) => vscode.Range | undefined
|
||||
match: RegExpMatchArray,
|
||||
) => vscode.Range | undefined,
|
||||
): OperatorRange {
|
||||
return (vimState, keys, editor) => {
|
||||
const keysStr = keys.join("");
|
||||
const doesMatch = keysStr.match(doesPattern);
|
||||
const keysStr = keys.join('')
|
||||
const doesMatch = keysStr.match(doesPattern)
|
||||
|
||||
if (doesMatch) {
|
||||
const ranges = editor.selections.map(selection => {
|
||||
return f(vimState, editor.document, selection.active, doesMatch);
|
||||
});
|
||||
const ranges = editor.selections.map((selection) => {
|
||||
return f(vimState, editor.document, selection.active, doesMatch)
|
||||
})
|
||||
return {
|
||||
kind: "success",
|
||||
kind: 'success',
|
||||
ranges: ranges,
|
||||
linewise: linewise
|
||||
};
|
||||
linewise: linewise,
|
||||
}
|
||||
} else if (keysStr.match(couldPattern)) {
|
||||
return {
|
||||
kind: "failure",
|
||||
status: ParseKeysStatus.MORE_INPUT
|
||||
};
|
||||
kind: 'failure',
|
||||
status: ParseKeysStatus.MORE_INPUT,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
kind: "failure",
|
||||
status: ParseKeysStatus.NO
|
||||
};
|
||||
kind: 'failure',
|
||||
status: ParseKeysStatus.NO,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,36 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { VimState } from "./vim_state_types";
|
||||
import { VimState } from './vim_state_types'
|
||||
|
||||
export enum ParseKeysStatus {
|
||||
YES,
|
||||
NO,
|
||||
MORE_INPUT
|
||||
MORE_INPUT,
|
||||
}
|
||||
|
||||
export type ParseFailure = {
|
||||
kind: "failure";
|
||||
status: ParseKeysStatus;
|
||||
};
|
||||
kind: 'failure'
|
||||
status: ParseKeysStatus
|
||||
}
|
||||
|
||||
export type ParseOperatorPartSuccess = {
|
||||
kind: "success";
|
||||
rest: string[];
|
||||
};
|
||||
kind: 'success'
|
||||
rest: string[]
|
||||
}
|
||||
|
||||
export type ParseOperatorRangeSuccess = {
|
||||
kind: "success";
|
||||
ranges: (vscode.Range | undefined)[];
|
||||
linewise: boolean;
|
||||
};
|
||||
kind: 'success'
|
||||
ranges: (vscode.Range | undefined)[]
|
||||
linewise: boolean
|
||||
}
|
||||
|
||||
export type ParseOperatorSuccess = {
|
||||
kind: "success";
|
||||
motion: OperatorRange | undefined;
|
||||
};
|
||||
kind: 'success'
|
||||
motion: OperatorRange | undefined
|
||||
}
|
||||
|
||||
export type OperatorRange = (
|
||||
vimState: VimState,
|
||||
keys: string[],
|
||||
editor: vscode.TextEditor
|
||||
) => ParseFailure | ParseOperatorRangeSuccess;
|
||||
editor: vscode.TextEditor,
|
||||
) => ParseFailure | ParseOperatorRangeSuccess
|
||||
|
@ -1,87 +1,81 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
export function left(
|
||||
position: vscode.Position,
|
||||
count: number = 1
|
||||
): vscode.Position {
|
||||
export function left(position: vscode.Position, count = 1): vscode.Position {
|
||||
return position.with({
|
||||
character: Math.max(position.character - count, 0)
|
||||
});
|
||||
character: Math.max(position.character - count, 0),
|
||||
})
|
||||
}
|
||||
|
||||
export function right(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position,
|
||||
count: number = 1
|
||||
count = 1,
|
||||
): vscode.Position {
|
||||
const lineLength = document.lineAt(position.line).text.length;
|
||||
const lineLength = document.lineAt(position.line).text.length
|
||||
return position.with({
|
||||
character: Math.min(position.character + count, lineLength)
|
||||
});
|
||||
character: Math.min(position.character + count, lineLength),
|
||||
})
|
||||
}
|
||||
|
||||
export function rightNormal(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position,
|
||||
count: number = 1
|
||||
count = 1,
|
||||
): vscode.Position {
|
||||
const lineLength = document.lineAt(position.line).text.length;
|
||||
const lineLength = document.lineAt(position.line).text.length
|
||||
|
||||
if (lineLength === 0) {
|
||||
return position.with({ character: 0 });
|
||||
return position.with({ character: 0 })
|
||||
} else {
|
||||
return position.with({
|
||||
character: Math.min(position.character + count, lineLength - 1)
|
||||
});
|
||||
character: Math.min(position.character + count, lineLength - 1),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function leftWrap(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
): vscode.Position {
|
||||
if (position.character <= 0) {
|
||||
if (position.line <= 0) {
|
||||
return position;
|
||||
return position
|
||||
} else {
|
||||
const previousLineLength = document.lineAt(position.line - 1).text.length;
|
||||
return new vscode.Position(position.line - 1, previousLineLength);
|
||||
const previousLineLength = document.lineAt(position.line - 1).text.length
|
||||
return new vscode.Position(position.line - 1, previousLineLength)
|
||||
}
|
||||
} else {
|
||||
return position.with({ character: position.character - 1 });
|
||||
return position.with({ character: position.character - 1 })
|
||||
}
|
||||
}
|
||||
|
||||
export function rightWrap(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
): vscode.Position {
|
||||
const lineLength = document.lineAt(position.line).text.length;
|
||||
const lineLength = document.lineAt(position.line).text.length
|
||||
|
||||
if (position.character >= lineLength) {
|
||||
if (position.line >= document.lineCount - 1) {
|
||||
return position;
|
||||
return position
|
||||
} else {
|
||||
return new vscode.Position(position.line + 1, 0);
|
||||
return new vscode.Position(position.line + 1, 0)
|
||||
}
|
||||
} else {
|
||||
return position.with({ character: position.character + 1 });
|
||||
return position.with({ character: position.character + 1 })
|
||||
}
|
||||
}
|
||||
|
||||
export function lineEnd(
|
||||
document: vscode.TextDocument,
|
||||
position: vscode.Position
|
||||
): vscode.Position {
|
||||
const lineLength = document.lineAt(position.line).text.length;
|
||||
export function lineEnd(document: vscode.TextDocument, position: vscode.Position): vscode.Position {
|
||||
const lineLength = document.lineAt(position.line).text.length
|
||||
return position.with({
|
||||
character: lineLength
|
||||
});
|
||||
character: lineLength,
|
||||
})
|
||||
}
|
||||
|
||||
export function lastChar(document: vscode.TextDocument): vscode.Position {
|
||||
return new vscode.Position(
|
||||
document.lineCount - 1,
|
||||
document.lineAt(document.lineCount - 1).text.length
|
||||
);
|
||||
document.lineAt(document.lineCount - 1).text.length,
|
||||
)
|
||||
}
|
||||
|
@ -1,77 +1,65 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { VimState } from "../vim_state_types";
|
||||
import { VimState } from '../vim_state_types'
|
||||
|
||||
export function getRegisterContentsList(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor
|
||||
) {
|
||||
if (vimState.registers.contentsList.length === 0) return undefined;
|
||||
export function getRegisterContentsList(vimState: VimState, editor: vscode.TextEditor) {
|
||||
if (vimState.registers.contentsList.length === 0) return undefined
|
||||
|
||||
let registerContentsList = vimState.registers.contentsList;
|
||||
let registerContentsList = vimState.registers.contentsList
|
||||
|
||||
// Handle putting with a different number of cursors than when you yanked
|
||||
if (vimState.registers.contentsList.length !== editor.selections.length) {
|
||||
const combinedContents = vimState.registers.contentsList.join("\n");
|
||||
registerContentsList = editor.selections.map(selection => combinedContents);
|
||||
const combinedContents = vimState.registers.contentsList.join('\n')
|
||||
registerContentsList = editor.selections.map(() => combinedContents)
|
||||
}
|
||||
|
||||
return registerContentsList;
|
||||
return registerContentsList
|
||||
}
|
||||
|
||||
// Given contents and positions at the end of the contents, return the position at the beginning of the contents
|
||||
export function getInsertRangesFromEnd(
|
||||
document: vscode.TextDocument,
|
||||
positions: vscode.Position[],
|
||||
contentsList: (string | undefined)[]
|
||||
contentsList: (string | undefined)[],
|
||||
) {
|
||||
return positions.map((position, i) => {
|
||||
const contents = contentsList[i];
|
||||
if (!contents) return undefined;
|
||||
const contents = contentsList[i]
|
||||
if (!contents) return undefined
|
||||
|
||||
const lines = contents.split(/\r?\n/);
|
||||
const lines = contents.split(/\r?\n/)
|
||||
|
||||
let beginningPosition;
|
||||
let beginningPosition
|
||||
if (lines.length > 1) {
|
||||
const beginningLine = position.line - (lines.length - 1);
|
||||
const beginningCharacter =
|
||||
document.lineAt(beginningLine).text.length - lines[0].length;
|
||||
beginningPosition = new vscode.Position(
|
||||
beginningLine,
|
||||
beginningCharacter
|
||||
);
|
||||
const beginningLine = position.line - (lines.length - 1)
|
||||
const beginningCharacter = document.lineAt(beginningLine).text.length - lines[0].length
|
||||
beginningPosition = new vscode.Position(beginningLine, beginningCharacter)
|
||||
} else {
|
||||
beginningPosition = position.with({
|
||||
character: position.character - lines[0].length
|
||||
});
|
||||
character: position.character - lines[0].length,
|
||||
})
|
||||
}
|
||||
|
||||
return new vscode.Range(beginningPosition, position);
|
||||
});
|
||||
return new vscode.Range(beginningPosition, position)
|
||||
})
|
||||
}
|
||||
|
||||
// Given positions and contents inserted at those positions, return the range that will
|
||||
// select that contents
|
||||
export function getInsertRangesFromBeginning(
|
||||
positions: vscode.Position[],
|
||||
contentsList: (string | undefined)[]
|
||||
contentsList: (string | undefined)[],
|
||||
) {
|
||||
return positions.map((position, i) => {
|
||||
const contents = contentsList[i];
|
||||
if (!contents) return undefined;
|
||||
const contents = contentsList[i]
|
||||
if (!contents) return undefined
|
||||
|
||||
const lines = contents.split(/\r?\n/);
|
||||
const endLine = position.line + lines.length - 1;
|
||||
const lines = contents.split(/\r?\n/)
|
||||
const endLine = position.line + lines.length - 1
|
||||
const endCharacter =
|
||||
lines.length === 1
|
||||
? position.character + lines[0].length
|
||||
: lines[lines.length - 1].length;
|
||||
lines.length === 1 ? position.character + lines[0].length : lines[lines.length - 1].length
|
||||
|
||||
return new vscode.Range(
|
||||
position,
|
||||
new vscode.Position(endLine, endCharacter)
|
||||
);
|
||||
});
|
||||
return new vscode.Range(position, new vscode.Position(endLine, endCharacter))
|
||||
})
|
||||
}
|
||||
|
||||
// Given positions and contents inserted at those positions, figure out how the positions will move
|
||||
@ -79,63 +67,62 @@ export function getInsertRangesFromBeginning(
|
||||
// line number by one.
|
||||
export function adjustInsertPositions(
|
||||
positions: vscode.Position[],
|
||||
contentsList: (string | undefined)[]
|
||||
contentsList: (string | undefined)[],
|
||||
) {
|
||||
const indexPositions = positions.map((position, i) => ({
|
||||
originalIndex: i,
|
||||
position: position
|
||||
}));
|
||||
position: position,
|
||||
}))
|
||||
|
||||
indexPositions.sort((a, b) => {
|
||||
if (a.position.isBefore(b.position)) return -1;
|
||||
else if (a.position.isEqual(b.position)) return 0;
|
||||
else return 1;
|
||||
});
|
||||
if (a.position.isBefore(b.position)) return -1
|
||||
else if (a.position.isEqual(b.position)) return 0
|
||||
else return 1
|
||||
})
|
||||
|
||||
const adjustedIndexPositions = [];
|
||||
let lineOffset = 0;
|
||||
let characterOffset = 0;
|
||||
let lineNumber = 0;
|
||||
const adjustedIndexPositions = []
|
||||
let lineOffset = 0
|
||||
let characterOffset = 0
|
||||
let lineNumber = 0
|
||||
|
||||
for (const indexPosition of indexPositions) {
|
||||
// Adjust position
|
||||
|
||||
const adjustedLine = indexPosition.position.line + lineOffset;
|
||||
const adjustedLine = indexPosition.position.line + lineOffset
|
||||
|
||||
let adjustedCharacter = indexPosition.position.character;
|
||||
let adjustedCharacter = indexPosition.position.character
|
||||
if (indexPosition.position.line === lineNumber) {
|
||||
adjustedCharacter += characterOffset;
|
||||
adjustedCharacter += characterOffset
|
||||
}
|
||||
|
||||
adjustedIndexPositions.push({
|
||||
originalIndex: indexPosition.originalIndex,
|
||||
position: new vscode.Position(adjustedLine, adjustedCharacter)
|
||||
});
|
||||
position: new vscode.Position(adjustedLine, adjustedCharacter),
|
||||
})
|
||||
|
||||
// Increase offsets
|
||||
|
||||
const contents = contentsList[indexPosition.originalIndex];
|
||||
const contents = contentsList[indexPosition.originalIndex]
|
||||
|
||||
if (contents !== undefined) {
|
||||
const contentsLines = contents.split(/\r?\n/);
|
||||
const contentsLines = contents.split(/\r?\n/)
|
||||
|
||||
lineOffset += contentsLines.length - 1;
|
||||
lineOffset += contentsLines.length - 1
|
||||
|
||||
if (indexPosition.position.line === lineNumber) {
|
||||
if (contentsLines.length === 1) {
|
||||
characterOffset += contentsLines[0].length;
|
||||
characterOffset += contentsLines[0].length
|
||||
} else {
|
||||
characterOffset +=
|
||||
contentsLines[contentsLines.length - 1].length -
|
||||
indexPosition.position.character;
|
||||
contentsLines[contentsLines.length - 1].length - indexPosition.position.character
|
||||
}
|
||||
} else {
|
||||
characterOffset = 0;
|
||||
lineNumber = indexPosition.position.line;
|
||||
characterOffset = 0
|
||||
lineNumber = indexPosition.position.line
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adjustedIndexPositions.sort((a, b) => a.originalIndex - b.originalIndex);
|
||||
return adjustedIndexPositions.map(indexPosition => indexPosition.position);
|
||||
adjustedIndexPositions.sort((a, b) => a.originalIndex - b.originalIndex)
|
||||
return adjustedIndexPositions.map((indexPosition) => indexPosition.position)
|
||||
}
|
||||
|
@ -1,190 +1,180 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import * as positionUtils from "../position_utils";
|
||||
import { VimState } from "../vim_state_types";
|
||||
import { Mode } from "../modes_types";
|
||||
import { enterNormalMode, setModeCursorStyle } from "../modes";
|
||||
import * as positionUtils from '../position_utils'
|
||||
import { VimState } from '../vim_state_types'
|
||||
import { Mode } from '../modes_types'
|
||||
import { enterNormalMode, setModeCursorStyle } from '../modes'
|
||||
import {
|
||||
getRegisterContentsList,
|
||||
adjustInsertPositions,
|
||||
getInsertRangesFromBeginning,
|
||||
getInsertRangesFromEnd
|
||||
} from "./common";
|
||||
getInsertRangesFromEnd,
|
||||
} from './common'
|
||||
|
||||
export function putAfter(vimState: VimState, editor: vscode.TextEditor) {
|
||||
const registerContentsList = getRegisterContentsList(vimState, editor);
|
||||
if (registerContentsList === undefined) return;
|
||||
const registerContentsList = getRegisterContentsList(vimState, editor)
|
||||
if (registerContentsList === undefined) return
|
||||
|
||||
if (vimState.mode === Mode.Normal) {
|
||||
if (vimState.registers.linewise) {
|
||||
normalModeLinewise(vimState, editor, registerContentsList);
|
||||
normalModeLinewise(vimState, editor, registerContentsList)
|
||||
} else {
|
||||
normalModeCharacterwise(vimState, editor, registerContentsList);
|
||||
normalModeCharacterwise(vimState, editor, registerContentsList)
|
||||
}
|
||||
} else if (vimState.mode === Mode.Visual) {
|
||||
visualMode(vimState, editor, registerContentsList);
|
||||
visualMode(vimState, editor, registerContentsList)
|
||||
} else {
|
||||
visualLineMode(vimState, editor, registerContentsList);
|
||||
visualLineMode(vimState, editor, registerContentsList)
|
||||
}
|
||||
}
|
||||
|
||||
function normalModeLinewise(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
registerContentsList: (string | undefined)[]
|
||||
registerContentsList: (string | undefined)[],
|
||||
) {
|
||||
const insertContentsList = registerContentsList.map(contents => {
|
||||
if (contents === undefined) return undefined;
|
||||
else return "\n" + contents;
|
||||
});
|
||||
const insertContentsList = registerContentsList.map((contents) => {
|
||||
if (contents === undefined) return undefined
|
||||
else return `\n${contents}`
|
||||
})
|
||||
|
||||
const insertPositions = editor.selections.map(selection => {
|
||||
const lineLength = editor.document.lineAt(selection.active.line).text
|
||||
.length;
|
||||
return new vscode.Position(selection.active.line, lineLength);
|
||||
});
|
||||
const insertPositions = editor.selections.map((selection) => {
|
||||
const lineLength = editor.document.lineAt(selection.active.line).text.length
|
||||
return new vscode.Position(selection.active.line, lineLength)
|
||||
})
|
||||
|
||||
const adjustedInsertPositions = adjustInsertPositions(
|
||||
insertPositions,
|
||||
insertContentsList
|
||||
);
|
||||
const adjustedInsertPositions = adjustInsertPositions(insertPositions, insertContentsList)
|
||||
const rangeBeginnings = adjustedInsertPositions.map(
|
||||
position => new vscode.Position(position.line + 1, 0)
|
||||
);
|
||||
(position) => new vscode.Position(position.line + 1, 0),
|
||||
)
|
||||
|
||||
editor
|
||||
.edit(editBuilder => {
|
||||
.edit((editBuilder) => {
|
||||
insertPositions.forEach((position, i) => {
|
||||
const contents = insertContentsList[i];
|
||||
if (contents === undefined) return;
|
||||
const contents = insertContentsList[i]
|
||||
if (contents === undefined) return
|
||||
|
||||
editBuilder.insert(position, contents);
|
||||
});
|
||||
editBuilder.insert(position, contents)
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
editor.selections = rangeBeginnings.map(
|
||||
position => new vscode.Selection(position, position)
|
||||
);
|
||||
});
|
||||
(position) => new vscode.Selection(position, position),
|
||||
)
|
||||
})
|
||||
|
||||
vimState.lastPutRanges = {
|
||||
ranges: getInsertRangesFromBeginning(rangeBeginnings, registerContentsList),
|
||||
linewise: true
|
||||
};
|
||||
linewise: true,
|
||||
}
|
||||
}
|
||||
|
||||
function normalModeCharacterwise(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
registerContentsList: (string | undefined)[]
|
||||
registerContentsList: (string | undefined)[],
|
||||
) {
|
||||
const insertPositions = editor.selections.map(selection => {
|
||||
return positionUtils.right(editor.document, selection.active);
|
||||
});
|
||||
const insertPositions = editor.selections.map((selection) => {
|
||||
return positionUtils.right(editor.document, selection.active)
|
||||
})
|
||||
|
||||
const adjustedInsertPositions = adjustInsertPositions(
|
||||
insertPositions,
|
||||
registerContentsList
|
||||
);
|
||||
const insertRanges = getInsertRangesFromBeginning(
|
||||
adjustedInsertPositions,
|
||||
registerContentsList
|
||||
);
|
||||
const adjustedInsertPositions = adjustInsertPositions(insertPositions, registerContentsList)
|
||||
const insertRanges = getInsertRangesFromBeginning(adjustedInsertPositions, registerContentsList)
|
||||
|
||||
editor
|
||||
.edit(editBuilder => {
|
||||
.edit((editBuilder) => {
|
||||
insertPositions.forEach((insertPosition, i) => {
|
||||
const registerContents = registerContentsList[i];
|
||||
if (registerContents === undefined) return;
|
||||
const registerContents = registerContentsList[i]
|
||||
if (registerContents === undefined) return
|
||||
|
||||
editBuilder.insert(insertPosition, registerContents);
|
||||
});
|
||||
editBuilder.insert(insertPosition, registerContents)
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
editor.selections = editor.selections.map((selection, i) => {
|
||||
const range = insertRanges[i];
|
||||
if (range === undefined) return selection;
|
||||
const range = insertRanges[i]
|
||||
if (range === undefined) return selection
|
||||
|
||||
const position = positionUtils.left(range.end);
|
||||
return new vscode.Selection(position, position);
|
||||
});
|
||||
});
|
||||
const position = positionUtils.left(range.end)
|
||||
return new vscode.Selection(position, position)
|
||||
})
|
||||
})
|
||||
|
||||
vimState.lastPutRanges = {
|
||||
ranges: insertRanges,
|
||||
linewise: false
|
||||
};
|
||||
linewise: false,
|
||||
}
|
||||
}
|
||||
|
||||
function visualMode(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
registerContentsList: (string | undefined)[]
|
||||
registerContentsList: (string | undefined)[],
|
||||
) {
|
||||
const insertContentsList = vimState.registers.linewise
|
||||
? registerContentsList.map(contents => {
|
||||
if (!contents) return undefined;
|
||||
else return "\n" + contents + "\n";
|
||||
? registerContentsList.map((contents) => {
|
||||
if (!contents) return undefined
|
||||
else return '\n' + contents + '\n'
|
||||
})
|
||||
: registerContentsList;
|
||||
: registerContentsList
|
||||
|
||||
editor
|
||||
.edit(editBuilder => {
|
||||
.edit((editBuilder) => {
|
||||
editor.selections.forEach((selection, i) => {
|
||||
const contents = insertContentsList[i];
|
||||
if (contents === undefined) return;
|
||||
const contents = insertContentsList[i]
|
||||
if (contents === undefined) return
|
||||
|
||||
editBuilder.delete(selection);
|
||||
editBuilder.insert(selection.start, contents);
|
||||
});
|
||||
editBuilder.delete(selection)
|
||||
editBuilder.insert(selection.start, contents)
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
vimState.lastPutRanges = {
|
||||
ranges: getInsertRangesFromEnd(
|
||||
editor.document,
|
||||
editor.selections.map(selection => selection.active),
|
||||
insertContentsList
|
||||
editor.selections.map((selection) => selection.active),
|
||||
insertContentsList,
|
||||
),
|
||||
linewise: vimState.registers.linewise
|
||||
};
|
||||
linewise: vimState.registers.linewise,
|
||||
}
|
||||
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
const newPosition = positionUtils.left(selection.active);
|
||||
return new vscode.Selection(newPosition, newPosition);
|
||||
});
|
||||
});
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
const newPosition = positionUtils.left(selection.active)
|
||||
return new vscode.Selection(newPosition, newPosition)
|
||||
})
|
||||
})
|
||||
|
||||
enterNormalMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
enterNormalMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
}
|
||||
|
||||
function visualLineMode(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
registerContentsList: (string | undefined)[]
|
||||
registerContentsList: (string | undefined)[],
|
||||
) {
|
||||
editor
|
||||
.edit(editBuilder => {
|
||||
.edit((editBuilder) => {
|
||||
editor.selections.forEach((selection, i) => {
|
||||
const registerContents = registerContentsList[i];
|
||||
if (registerContents === undefined) return;
|
||||
const registerContents = registerContentsList[i]
|
||||
if (registerContents === undefined) return
|
||||
|
||||
editBuilder.replace(selection, registerContents);
|
||||
});
|
||||
editBuilder.replace(selection, registerContents)
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
vimState.lastPutRanges = {
|
||||
ranges: editor.selections.map(
|
||||
selection => new vscode.Range(selection.start, selection.end)
|
||||
(selection) => new vscode.Range(selection.start, selection.end),
|
||||
),
|
||||
linewise: vimState.registers.linewise
|
||||
};
|
||||
linewise: vimState.registers.linewise,
|
||||
}
|
||||
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
return new vscode.Selection(selection.start, selection.start);
|
||||
});
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
return new vscode.Selection(selection.start, selection.start)
|
||||
})
|
||||
|
||||
enterNormalMode(vimState);
|
||||
setModeCursorStyle(vimState.mode, editor);
|
||||
});
|
||||
enterNormalMode(vimState)
|
||||
setModeCursorStyle(vimState.mode, editor)
|
||||
})
|
||||
}
|
||||
|
@ -1,106 +1,93 @@
|
||||
import * as vscode from "vscode";
|
||||
|
||||
import * as positionUtils from "../position_utils";
|
||||
import { VimState } from "../vim_state_types";
|
||||
import * as vscode from 'vscode'
|
||||
import * as positionUtils from '../position_utils'
|
||||
import type { VimState } from '../vim_state_types'
|
||||
import {
|
||||
getRegisterContentsList,
|
||||
adjustInsertPositions,
|
||||
getInsertRangesFromBeginning
|
||||
} from "./common";
|
||||
getInsertRangesFromBeginning,
|
||||
getRegisterContentsList,
|
||||
} from './common'
|
||||
|
||||
export function putBefore(vimState: VimState, editor: vscode.TextEditor) {
|
||||
const registerContentsList = getRegisterContentsList(vimState, editor);
|
||||
if (registerContentsList === undefined) return;
|
||||
const registerContentsList = getRegisterContentsList(vimState, editor)
|
||||
if (registerContentsList === undefined) return
|
||||
|
||||
if (vimState.registers.linewise) {
|
||||
normalModeLinewise(vimState, editor, registerContentsList);
|
||||
normalModeLinewise(vimState, editor, registerContentsList)
|
||||
} else {
|
||||
normalModeCharacterwise(vimState, editor, registerContentsList);
|
||||
normalModeCharacterwise(vimState, editor, registerContentsList)
|
||||
}
|
||||
}
|
||||
|
||||
function normalModeLinewise(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
registerContentsList: (string | undefined)[]
|
||||
registerContentsList: (string | undefined)[],
|
||||
) {
|
||||
const insertContentsList = registerContentsList.map(contents => {
|
||||
if (contents === undefined) return undefined;
|
||||
else return contents + "\n";
|
||||
});
|
||||
const insertContentsList = registerContentsList.map((contents) => {
|
||||
if (contents === undefined) return undefined
|
||||
else return `${contents}\n`
|
||||
})
|
||||
|
||||
const insertPositions = editor.selections.map(selection => {
|
||||
return new vscode.Position(selection.active.line, 0);
|
||||
});
|
||||
const insertPositions = editor.selections.map((selection) => {
|
||||
return new vscode.Position(selection.active.line, 0)
|
||||
})
|
||||
|
||||
const adjustedInsertPositions = adjustInsertPositions(
|
||||
insertPositions,
|
||||
insertContentsList
|
||||
);
|
||||
const adjustedInsertPositions = adjustInsertPositions(insertPositions, insertContentsList)
|
||||
|
||||
editor
|
||||
.edit(editBuilder => {
|
||||
.edit((editBuilder) => {
|
||||
insertPositions.forEach((position, i) => {
|
||||
const contents = insertContentsList[i];
|
||||
if (contents === undefined) return;
|
||||
const contents = insertContentsList[i]
|
||||
if (contents === undefined) return
|
||||
|
||||
editBuilder.insert(position, contents);
|
||||
});
|
||||
editBuilder.insert(position, contents)
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
editor.selections = editor.selections.map((selection, i) => {
|
||||
const position = adjustedInsertPositions[i];
|
||||
if (position === undefined) return selection;
|
||||
const position = adjustedInsertPositions[i]
|
||||
if (position === undefined) return selection
|
||||
|
||||
return new vscode.Selection(position, position);
|
||||
});
|
||||
});
|
||||
return new vscode.Selection(position, position)
|
||||
})
|
||||
})
|
||||
|
||||
vimState.lastPutRanges = {
|
||||
ranges: getInsertRangesFromBeginning(
|
||||
adjustedInsertPositions,
|
||||
registerContentsList
|
||||
),
|
||||
linewise: true
|
||||
};
|
||||
ranges: getInsertRangesFromBeginning(adjustedInsertPositions, registerContentsList),
|
||||
linewise: true,
|
||||
}
|
||||
}
|
||||
|
||||
function normalModeCharacterwise(
|
||||
vimState: VimState,
|
||||
editor: vscode.TextEditor,
|
||||
registerContentsList: (string | undefined)[]
|
||||
registerContentsList: (string | undefined)[],
|
||||
) {
|
||||
const insertPositions = editor.selections.map(selection => selection.active);
|
||||
const adjustedInsertPositions = adjustInsertPositions(
|
||||
insertPositions,
|
||||
registerContentsList
|
||||
);
|
||||
const insertRanges = getInsertRangesFromBeginning(
|
||||
adjustedInsertPositions,
|
||||
registerContentsList
|
||||
);
|
||||
const insertPositions = editor.selections.map((selection) => selection.active)
|
||||
const adjustedInsertPositions = adjustInsertPositions(insertPositions, registerContentsList)
|
||||
const insertRanges = getInsertRangesFromBeginning(adjustedInsertPositions, registerContentsList)
|
||||
|
||||
editor
|
||||
.edit(editBuilder => {
|
||||
.edit((editBuilder) => {
|
||||
insertPositions.forEach((insertPosition, i) => {
|
||||
const registerContents = registerContentsList[i];
|
||||
if (registerContents === undefined) return;
|
||||
const registerContents = registerContentsList[i]
|
||||
if (registerContents === undefined) return
|
||||
|
||||
editBuilder.insert(insertPosition, registerContents);
|
||||
});
|
||||
editBuilder.insert(insertPosition, registerContents)
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
editor.selections = editor.selections.map((selection, i) => {
|
||||
const range = insertRanges[i];
|
||||
if (range === undefined) return selection;
|
||||
const range = insertRanges[i]
|
||||
if (range === undefined) return selection
|
||||
|
||||
const position = positionUtils.left(range.end);
|
||||
return new vscode.Selection(position, position);
|
||||
});
|
||||
});
|
||||
const position = positionUtils.left(range.end)
|
||||
return new vscode.Selection(position, position)
|
||||
})
|
||||
})
|
||||
|
||||
vimState.lastPutRanges = {
|
||||
ranges: insertRanges,
|
||||
linewise: false
|
||||
};
|
||||
linewise: false,
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +1,54 @@
|
||||
import * as vscode from "vscode";
|
||||
|
||||
import { SimpleRange } from "./simple_range_types";
|
||||
import * as vscode from 'vscode'
|
||||
import { SimpleRange } from './simple_range_types'
|
||||
|
||||
export function findQuoteRange(
|
||||
ranges: SimpleRange[],
|
||||
position: vscode.Position
|
||||
position: vscode.Position,
|
||||
): SimpleRange | undefined {
|
||||
const insideResult = ranges.find(
|
||||
x => x.start <= position.character && x.end >= position.character
|
||||
);
|
||||
(x) => x.start <= position.character && x.end >= position.character,
|
||||
)
|
||||
|
||||
if (insideResult) {
|
||||
return insideResult;
|
||||
return insideResult
|
||||
}
|
||||
|
||||
const outsideResult = ranges.find(x => x.start > position.character);
|
||||
const outsideResult = ranges.find((x) => x.start > position.character)
|
||||
|
||||
if (outsideResult) {
|
||||
return outsideResult;
|
||||
return outsideResult
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function quoteRanges(quoteChar: string, s: string): SimpleRange[] {
|
||||
let stateInQuote = false;
|
||||
let stateStartIndex = 0;
|
||||
let backslashCount = 0;
|
||||
const ranges = [];
|
||||
let stateInQuote = false
|
||||
let stateStartIndex = 0
|
||||
let backslashCount = 0
|
||||
const ranges = []
|
||||
|
||||
for (let i = 0; i < s.length; ++i) {
|
||||
if (s[i] === quoteChar && backslashCount % 2 === 0) {
|
||||
if (stateInQuote) {
|
||||
ranges.push({
|
||||
start: stateStartIndex,
|
||||
end: i
|
||||
});
|
||||
end: i,
|
||||
})
|
||||
|
||||
stateInQuote = false;
|
||||
stateInQuote = false
|
||||
} else {
|
||||
stateInQuote = true;
|
||||
stateStartIndex = i;
|
||||
stateInQuote = true
|
||||
stateStartIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
if (s[i] === "\\") {
|
||||
++backslashCount;
|
||||
if (s[i] === '\\') {
|
||||
++backslashCount
|
||||
} else {
|
||||
backslashCount = 0;
|
||||
backslashCount = 0
|
||||
}
|
||||
}
|
||||
|
||||
return ranges;
|
||||
return ranges
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
function editorScroll(to: string, by: string) {
|
||||
vscode.commands.executeCommand("editorScroll", {
|
||||
vscode.commands.executeCommand('editorScroll', {
|
||||
to: to,
|
||||
by: by
|
||||
});
|
||||
by: by,
|
||||
})
|
||||
}
|
||||
|
||||
export function scrollDownHalfPage(): void {
|
||||
editorScroll("down", "halfPage");
|
||||
editorScroll('down', 'halfPage')
|
||||
}
|
||||
|
||||
export function scrollUpHalfPage(): void {
|
||||
editorScroll("up", "halfPage");
|
||||
editorScroll('up', 'halfPage')
|
||||
}
|
||||
|
||||
export function scrollDownPage(): void {
|
||||
editorScroll("down", "page");
|
||||
editorScroll('down', 'page')
|
||||
}
|
||||
|
||||
export function scrollUpPage(): void {
|
||||
editorScroll("up", "page");
|
||||
editorScroll('up', 'page')
|
||||
}
|
||||
|
@ -1,95 +1,93 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
export function searchForward(
|
||||
document: vscode.TextDocument,
|
||||
needle: string,
|
||||
fromPosition: vscode.Position
|
||||
fromPosition: vscode.Position,
|
||||
): vscode.Position | undefined {
|
||||
for (let i = fromPosition.line; i < document.lineCount; ++i) {
|
||||
const lineText = document.lineAt(i).text;
|
||||
const fromIndex = i === fromPosition.line ? fromPosition.character : 0;
|
||||
const matchIndex = lineText.indexOf(needle, fromIndex);
|
||||
const lineText = document.lineAt(i).text
|
||||
const fromIndex = i === fromPosition.line ? fromPosition.character : 0
|
||||
const matchIndex = lineText.indexOf(needle, fromIndex)
|
||||
|
||||
if (matchIndex >= 0) {
|
||||
return new vscode.Position(i, matchIndex);
|
||||
return new vscode.Position(i, matchIndex)
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function searchBackward(
|
||||
document: vscode.TextDocument,
|
||||
needle: string,
|
||||
fromPosition: vscode.Position
|
||||
fromPosition: vscode.Position,
|
||||
): vscode.Position | undefined {
|
||||
for (let i = fromPosition.line; i >= 0; --i) {
|
||||
const lineText = document.lineAt(i).text;
|
||||
const fromIndex =
|
||||
i === fromPosition.line ? fromPosition.character : +Infinity;
|
||||
const matchIndex = lineText.lastIndexOf(needle, fromIndex);
|
||||
const lineText = document.lineAt(i).text
|
||||
const fromIndex = i === fromPosition.line ? fromPosition.character : +Infinity
|
||||
const matchIndex = lineText.lastIndexOf(needle, fromIndex)
|
||||
|
||||
if (matchIndex >= 0) {
|
||||
return new vscode.Position(i, matchIndex);
|
||||
return new vscode.Position(i, matchIndex)
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function searchForwardBracket(
|
||||
document: vscode.TextDocument,
|
||||
openingChar: string,
|
||||
closingChar: string,
|
||||
fromPosition: vscode.Position
|
||||
fromPosition: vscode.Position,
|
||||
): vscode.Position | undefined {
|
||||
let n = 0;
|
||||
let n = 0
|
||||
|
||||
for (let i = fromPosition.line; i < document.lineCount; ++i) {
|
||||
const lineText = document.lineAt(i).text;
|
||||
const fromIndex = i === fromPosition.line ? fromPosition.character : 0;
|
||||
const lineText = document.lineAt(i).text
|
||||
const fromIndex = i === fromPosition.line ? fromPosition.character : 0
|
||||
|
||||
for (let j = fromIndex; j < lineText.length; ++j) {
|
||||
if (lineText[j] === openingChar) {
|
||||
++n;
|
||||
++n
|
||||
} else if (lineText[j] === closingChar) {
|
||||
if (n === 0) {
|
||||
return new vscode.Position(i, j);
|
||||
return new vscode.Position(i, j)
|
||||
} else {
|
||||
--n;
|
||||
--n
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function searchBackwardBracket(
|
||||
document: vscode.TextDocument,
|
||||
openingChar: string,
|
||||
closingChar: string,
|
||||
fromPosition: vscode.Position
|
||||
fromPosition: vscode.Position,
|
||||
): vscode.Position | undefined {
|
||||
let n = 0;
|
||||
let n = 0
|
||||
|
||||
for (let i = fromPosition.line; i >= 0; --i) {
|
||||
const lineText = document.lineAt(i).text;
|
||||
const fromIndex =
|
||||
i === fromPosition.line ? fromPosition.character : lineText.length - 1;
|
||||
const lineText = document.lineAt(i).text
|
||||
const fromIndex = i === fromPosition.line ? fromPosition.character : lineText.length - 1
|
||||
|
||||
for (let j = fromIndex; j >= 0; --j) {
|
||||
if (lineText[j] === closingChar) {
|
||||
++n;
|
||||
++n
|
||||
} else if (lineText[j] === openingChar) {
|
||||
if (n === 0) {
|
||||
return new vscode.Position(i, j);
|
||||
return new vscode.Position(i, j)
|
||||
} else {
|
||||
--n;
|
||||
--n
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return undefined
|
||||
}
|
||||
|
@ -1,69 +1,61 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import * as positionUtils from "./position_utils";
|
||||
import * as positionUtils from './position_utils'
|
||||
|
||||
export function vscodeToVimVisualSelection(
|
||||
document: vscode.TextDocument,
|
||||
vscodeSelection: vscode.Selection
|
||||
vscodeSelection: vscode.Selection,
|
||||
): vscode.Selection {
|
||||
if (vscodeSelection.active.isBefore(vscodeSelection.anchor)) {
|
||||
return new vscode.Selection(
|
||||
positionUtils.left(vscodeSelection.anchor),
|
||||
vscodeSelection.active
|
||||
);
|
||||
return new vscode.Selection(positionUtils.left(vscodeSelection.anchor), vscodeSelection.active)
|
||||
} else {
|
||||
return new vscode.Selection(
|
||||
vscodeSelection.anchor,
|
||||
positionUtils.left(vscodeSelection.active)
|
||||
);
|
||||
return new vscode.Selection(vscodeSelection.anchor, positionUtils.left(vscodeSelection.active))
|
||||
}
|
||||
}
|
||||
|
||||
export function vimToVscodeVisualSelection(
|
||||
document: vscode.TextDocument,
|
||||
vimSelection: vscode.Selection
|
||||
vimSelection: vscode.Selection,
|
||||
): vscode.Selection {
|
||||
if (vimSelection.active.isBefore(vimSelection.anchor)) {
|
||||
return new vscode.Selection(
|
||||
positionUtils.right(document, vimSelection.anchor),
|
||||
vimSelection.active
|
||||
);
|
||||
vimSelection.active,
|
||||
)
|
||||
} else {
|
||||
return new vscode.Selection(
|
||||
vimSelection.anchor,
|
||||
positionUtils.right(document, vimSelection.active)
|
||||
);
|
||||
positionUtils.right(document, vimSelection.active),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function vscodeToVimVisualLineSelection(
|
||||
document: vscode.TextDocument,
|
||||
vscodeSelection: vscode.Selection
|
||||
vscodeSelection: vscode.Selection,
|
||||
): vscode.Selection {
|
||||
return new vscode.Selection(
|
||||
vscodeSelection.anchor.with({ character: 0 }),
|
||||
vscodeSelection.active.with({ character: 0 })
|
||||
);
|
||||
vscodeSelection.active.with({ character: 0 }),
|
||||
)
|
||||
}
|
||||
|
||||
export function vimToVscodeVisualLineSelection(
|
||||
document: vscode.TextDocument,
|
||||
vimSelection: vscode.Selection
|
||||
vimSelection: vscode.Selection,
|
||||
): vscode.Selection {
|
||||
const anchorLineLength = document.lineAt(vimSelection.anchor.line).text
|
||||
.length;
|
||||
const activeLineLength = document.lineAt(vimSelection.active.line).text
|
||||
.length;
|
||||
const anchorLineLength = document.lineAt(vimSelection.anchor.line).text.length
|
||||
const activeLineLength = document.lineAt(vimSelection.active.line).text.length
|
||||
|
||||
if (vimSelection.active.isBefore(vimSelection.anchor)) {
|
||||
return new vscode.Selection(
|
||||
vimSelection.anchor.with({ character: anchorLineLength }),
|
||||
vimSelection.active.with({ character: 0 })
|
||||
);
|
||||
vimSelection.active.with({ character: 0 }),
|
||||
)
|
||||
} else {
|
||||
return new vscode.Selection(
|
||||
vimSelection.anchor.with({ character: 0 }),
|
||||
vimSelection.active.with({ character: activeLineLength })
|
||||
);
|
||||
vimSelection.active.with({ character: activeLineLength }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
export type SimpleRange = {
|
||||
start: number;
|
||||
end: number;
|
||||
};
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
|
157
src/tag_utils.ts
157
src/tag_utils.ts
@ -1,56 +1,53 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { SimpleRange } from "./simple_range_types";
|
||||
import { SimpleRange } from './simple_range_types'
|
||||
|
||||
type PartialTagOpening = {
|
||||
kind: "opening";
|
||||
name: string;
|
||||
range: SimpleRange;
|
||||
};
|
||||
|
||||
type PartialTagClosing = {
|
||||
kind: "closing";
|
||||
name: string;
|
||||
range: SimpleRange;
|
||||
};
|
||||
|
||||
type PartialTagSelfClosing = {
|
||||
kind: "self_closing";
|
||||
name: string;
|
||||
range: SimpleRange;
|
||||
};
|
||||
|
||||
type PartialTag = PartialTagOpening | PartialTagClosing | PartialTagSelfClosing;
|
||||
|
||||
type OffsetTag = {
|
||||
name: string;
|
||||
opening: SimpleRange;
|
||||
closing?: SimpleRange; // Doesn't exist for self-closing tags
|
||||
};
|
||||
|
||||
type PositionTag = {
|
||||
name: string;
|
||||
opening: vscode.Range;
|
||||
closing?: vscode.Range; // Doesn't exist for self-closing tags
|
||||
};
|
||||
|
||||
const OPEN_SLASH_GROUP = 1;
|
||||
const TAG_NAME_GROUP = 2;
|
||||
const CLOSE_SLASH_GROUP = 3;
|
||||
|
||||
export function getTags(document: vscode.TextDocument): PositionTag[] {
|
||||
return positionTags(document, matchTags(getPartialTags(document.getText())));
|
||||
kind: 'opening'
|
||||
name: string
|
||||
range: SimpleRange
|
||||
}
|
||||
|
||||
function positionTags(
|
||||
document: vscode.TextDocument,
|
||||
offsetTags: OffsetTag[]
|
||||
): PositionTag[] {
|
||||
return offsetTags.map(tag => {
|
||||
type PartialTagClosing = {
|
||||
kind: 'closing'
|
||||
name: string
|
||||
range: SimpleRange
|
||||
}
|
||||
|
||||
type PartialTagSelfClosing = {
|
||||
kind: 'self_closing'
|
||||
name: string
|
||||
range: SimpleRange
|
||||
}
|
||||
|
||||
type PartialTag = PartialTagOpening | PartialTagClosing | PartialTagSelfClosing
|
||||
|
||||
type OffsetTag = {
|
||||
name: string
|
||||
opening: SimpleRange
|
||||
closing?: SimpleRange // Doesn't exist for self-closing tags
|
||||
}
|
||||
|
||||
type PositionTag = {
|
||||
name: string
|
||||
opening: vscode.Range
|
||||
closing?: vscode.Range // Doesn't exist for self-closing tags
|
||||
}
|
||||
|
||||
const OPEN_SLASH_GROUP = 1
|
||||
const TAG_NAME_GROUP = 2
|
||||
const CLOSE_SLASH_GROUP = 3
|
||||
|
||||
export function getTags(document: vscode.TextDocument): PositionTag[] {
|
||||
return positionTags(document, matchTags(getPartialTags(document.getText())))
|
||||
}
|
||||
|
||||
function positionTags(document: vscode.TextDocument, offsetTags: OffsetTag[]): PositionTag[] {
|
||||
return offsetTags.map((tag) => {
|
||||
const openingRange = new vscode.Range(
|
||||
document.positionAt(tag.opening.start),
|
||||
document.positionAt(tag.opening.end)
|
||||
);
|
||||
document.positionAt(tag.opening.end),
|
||||
)
|
||||
|
||||
if (tag.closing) {
|
||||
return {
|
||||
@ -58,77 +55,77 @@ function positionTags(
|
||||
opening: openingRange,
|
||||
closing: new vscode.Range(
|
||||
document.positionAt(tag.closing.start),
|
||||
document.positionAt(tag.closing.end)
|
||||
)
|
||||
};
|
||||
document.positionAt(tag.closing.end),
|
||||
),
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
name: tag.name,
|
||||
opening: openingRange
|
||||
};
|
||||
opening: openingRange,
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function matchTags(partialTags: PartialTag[]): OffsetTag[] {
|
||||
const tags: OffsetTag[] = [];
|
||||
const openingStack: PartialTagOpening[] = [];
|
||||
const tags: OffsetTag[] = []
|
||||
const openingStack: PartialTagOpening[] = []
|
||||
|
||||
partialTags.forEach(partialTag => {
|
||||
if (partialTag.kind === "opening") {
|
||||
openingStack.push(partialTag);
|
||||
} else if (partialTag.kind === "self_closing") {
|
||||
partialTags.forEach((partialTag) => {
|
||||
if (partialTag.kind === 'opening') {
|
||||
openingStack.push(partialTag)
|
||||
} else if (partialTag.kind === 'self_closing') {
|
||||
tags.push({
|
||||
name: partialTag.name,
|
||||
opening: partialTag.range
|
||||
});
|
||||
} else if (partialTag.kind === "closing") {
|
||||
let stackTag = openingStack.pop();
|
||||
opening: partialTag.range,
|
||||
})
|
||||
} else if (partialTag.kind === 'closing') {
|
||||
let stackTag = openingStack.pop()
|
||||
|
||||
while (stackTag) {
|
||||
if (stackTag.name === partialTag.name) {
|
||||
tags.push({
|
||||
name: stackTag.name,
|
||||
opening: stackTag.range,
|
||||
closing: partialTag.range
|
||||
});
|
||||
closing: partialTag.range,
|
||||
})
|
||||
|
||||
break;
|
||||
break
|
||||
} else {
|
||||
// Treat unclosed tags as self-closing because that's often the case in HTML
|
||||
tags.push({
|
||||
name: stackTag.name,
|
||||
opening: stackTag.range
|
||||
});
|
||||
opening: stackTag.range,
|
||||
})
|
||||
}
|
||||
|
||||
stackTag = openingStack.pop();
|
||||
stackTag = openingStack.pop()
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
return tags.sort((a, b) => a.opening.start - b.opening.start);
|
||||
return tags.sort((a, b) => a.opening.start - b.opening.start)
|
||||
}
|
||||
|
||||
function getPartialTags(text: string): PartialTag[] {
|
||||
const regex = /\<(\/)?([^\>\<\s]+)[^\>\<]*?(\/?)\>/g;
|
||||
const tagRanges: PartialTag[] = [];
|
||||
let match = regex.exec(text);
|
||||
const regex = /<(\/)?([^><\s]+)[^><]*?(\/?)>/g
|
||||
const tagRanges: PartialTag[] = []
|
||||
let match = regex.exec(text)
|
||||
|
||||
while (match) {
|
||||
const name = match[TAG_NAME_GROUP];
|
||||
const range = { start: match.index, end: regex.lastIndex - 1 };
|
||||
const name = match[TAG_NAME_GROUP]
|
||||
const range = { start: match.index, end: regex.lastIndex - 1 }
|
||||
|
||||
if (match[CLOSE_SLASH_GROUP]) {
|
||||
tagRanges.push({ kind: "self_closing", name: name, range: range });
|
||||
tagRanges.push({ kind: 'self_closing', name: name, range: range })
|
||||
} else if (match[OPEN_SLASH_GROUP]) {
|
||||
tagRanges.push({ kind: "closing", name: name, range: range });
|
||||
tagRanges.push({ kind: 'closing', name: name, range: range })
|
||||
} else {
|
||||
tagRanges.push({ kind: "opening", name: name, range: range });
|
||||
tagRanges.push({ kind: 'opening', name: name, range: range })
|
||||
}
|
||||
|
||||
match = regex.exec(text);
|
||||
match = regex.exec(text)
|
||||
}
|
||||
|
||||
return tagRanges;
|
||||
return tagRanges
|
||||
}
|
||||
|
@ -1,33 +1,33 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { ParseKeysStatus } from "./parse_keys_types";
|
||||
import { actions } from "./actions";
|
||||
import { VimState } from "./vim_state_types";
|
||||
import { ParseKeysStatus } from './parse_keys_types'
|
||||
import { actions } from './actions'
|
||||
import { VimState } from './vim_state_types'
|
||||
|
||||
export function typeHandler(vimState: VimState, char: string): void {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
const editor = vscode.window.activeTextEditor
|
||||
|
||||
if (!editor) return;
|
||||
if (!editor) return
|
||||
|
||||
vimState.keysPressed.push(char);
|
||||
vimState.keysPressed.push(char)
|
||||
|
||||
try {
|
||||
let could = false;
|
||||
let could = false
|
||||
for (const action of actions) {
|
||||
const result = action(vimState, vimState.keysPressed, editor);
|
||||
const result = action(vimState, vimState.keysPressed, editor)
|
||||
|
||||
if (result === ParseKeysStatus.YES) {
|
||||
vimState.keysPressed = [];
|
||||
break;
|
||||
vimState.keysPressed = []
|
||||
break
|
||||
} else if (result === ParseKeysStatus.MORE_INPUT) {
|
||||
could = true;
|
||||
could = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!could) {
|
||||
vimState.keysPressed = [];
|
||||
vimState.keysPressed = []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { VimState } from "./vim_state_types";
|
||||
import { VimState } from './vim_state_types'
|
||||
|
||||
export function addTypeSubscription(
|
||||
vimState: VimState,
|
||||
typeHandler: (vimState: VimState, char: string) => void
|
||||
typeHandler: (vimState: VimState, char: string) => void,
|
||||
): void {
|
||||
vimState.typeSubscription = vscode.commands.registerCommand("type", e => {
|
||||
typeHandler(vimState, e.text);
|
||||
});
|
||||
vimState.typeSubscription = vscode.commands.registerCommand('type', (e) => {
|
||||
typeHandler(vimState, e.text)
|
||||
})
|
||||
}
|
||||
|
||||
export function removeTypeSubscription(vimState: VimState): void {
|
||||
if (vimState.typeSubscription) {
|
||||
vimState.typeSubscription.dispose();
|
||||
vimState.typeSubscription.dispose()
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import { Mode } from "./modes_types";
|
||||
import type { Mode } from './modes_types'
|
||||
|
||||
export type VimState = {
|
||||
typeSubscription: vscode.Disposable | undefined;
|
||||
mode: Mode;
|
||||
keysPressed: string[];
|
||||
typeSubscription: vscode.Disposable | undefined
|
||||
mode: Mode
|
||||
keysPressed: string[]
|
||||
registers: {
|
||||
contentsList: (string | undefined)[];
|
||||
linewise: boolean;
|
||||
};
|
||||
semicolonAction: (vimState: VimState, editor: vscode.TextEditor) => void;
|
||||
commaAction: (vimState: VimState, editor: vscode.TextEditor) => void;
|
||||
contentsList: (string | undefined)[]
|
||||
linewise: boolean
|
||||
}
|
||||
semicolonAction: (vimState: VimState, editor: vscode.TextEditor) => void
|
||||
commaAction: (vimState: VimState, editor: vscode.TextEditor) => void
|
||||
lastPutRanges: {
|
||||
ranges: (vscode.Range | undefined)[];
|
||||
linewise: boolean;
|
||||
};
|
||||
};
|
||||
ranges: (vscode.Range | undefined)[]
|
||||
linewise: boolean
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,19 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
export function setVisualLineSelections(editor: vscode.TextEditor): void {
|
||||
editor.selections = editor.selections.map(selection => {
|
||||
editor.selections = editor.selections.map((selection) => {
|
||||
if (!selection.isReversed || selection.isSingleLine) {
|
||||
const activeLineLength = editor.document.lineAt(selection.active.line)
|
||||
.text.length;
|
||||
const activeLineLength = editor.document.lineAt(selection.active.line).text.length
|
||||
return new vscode.Selection(
|
||||
selection.anchor.with({ character: 0 }),
|
||||
selection.active.with({ character: activeLineLength })
|
||||
);
|
||||
selection.active.with({ character: activeLineLength }),
|
||||
)
|
||||
} else {
|
||||
const anchorLineLength = editor.document.lineAt(selection.anchor.line)
|
||||
.text.length;
|
||||
const anchorLineLength = editor.document.lineAt(selection.anchor.line).text.length
|
||||
return new vscode.Selection(
|
||||
selection.anchor.with({ character: anchorLineLength }),
|
||||
selection.active.with({ character: 0 })
|
||||
);
|
||||
selection.active.with({ character: 0 }),
|
||||
)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
@ -1,40 +1,37 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
import * as positionUtils from "./position_utils";
|
||||
import * as positionUtils from './position_utils'
|
||||
|
||||
// This fixes the selection anchor when selection is changed so that active and anchor are reversed.
|
||||
// For most motions we use execMotion for perfect visual mode emulation, but for some we need to
|
||||
// use VSCode's cursorMove instead and this function allows us to fix the selection after the fact.
|
||||
export function setVisualSelections(
|
||||
editor: vscode.TextEditor,
|
||||
originalSelections: vscode.Selection[]
|
||||
originalSelections: vscode.Selection[],
|
||||
): void {
|
||||
editor.selections = editor.selections.map((selection, i) => {
|
||||
const originalSelection = originalSelections[i];
|
||||
const originalSelection = originalSelections[i]
|
||||
|
||||
let activePosition = selection.active;
|
||||
let activePosition = selection.active
|
||||
if (!selection.isReversed && selection.active.character === 0) {
|
||||
activePosition = positionUtils.right(editor.document, selection.active);
|
||||
activePosition = positionUtils.right(editor.document, selection.active)
|
||||
}
|
||||
|
||||
if (
|
||||
originalSelection.active.isBefore(originalSelection.anchor) &&
|
||||
selection.active.isAfterOrEqual(selection.anchor)
|
||||
) {
|
||||
return new vscode.Selection(
|
||||
positionUtils.left(selection.anchor),
|
||||
activePosition
|
||||
);
|
||||
return new vscode.Selection(positionUtils.left(selection.anchor), activePosition)
|
||||
} else if (
|
||||
originalSelection.active.isAfter(originalSelection.anchor) &&
|
||||
selection.active.isBeforeOrEqual(selection.anchor)
|
||||
) {
|
||||
return new vscode.Selection(
|
||||
positionUtils.right(editor.document, selection.anchor),
|
||||
activePosition
|
||||
);
|
||||
activePosition,
|
||||
)
|
||||
} else {
|
||||
return new vscode.Selection(selection.anchor, activePosition);
|
||||
return new vscode.Selection(selection.anchor, activePosition)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
@ -1,33 +1,31 @@
|
||||
const NON_WORD_CHARACTERS = "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-";
|
||||
const NON_WORD_CHARACTERS = '/\\()"\':,.;<>~!@#$%^&*|+=[]{}`?-'
|
||||
|
||||
export function whitespaceWordRanges(
|
||||
text: string
|
||||
): { start: number; end: number }[] {
|
||||
export function whitespaceWordRanges(text: string): { start: number; end: number }[] {
|
||||
enum State {
|
||||
Whitespace,
|
||||
Word
|
||||
Word,
|
||||
}
|
||||
|
||||
let state = State.Whitespace;
|
||||
let startIndex = 0;
|
||||
const ranges = [];
|
||||
let state = State.Whitespace
|
||||
let startIndex = 0
|
||||
const ranges = []
|
||||
|
||||
for (let i = 0; i < text.length; ++i) {
|
||||
const char = text[i];
|
||||
const char = text[i]
|
||||
|
||||
if (state === State.Whitespace) {
|
||||
if (!isWhitespaceCharacter(char)) {
|
||||
startIndex = i;
|
||||
state = State.Word;
|
||||
startIndex = i
|
||||
state = State.Word
|
||||
}
|
||||
} else {
|
||||
if (isWhitespaceCharacter(char)) {
|
||||
ranges.push({
|
||||
start: startIndex,
|
||||
end: i - 1
|
||||
});
|
||||
end: i - 1,
|
||||
})
|
||||
|
||||
state = State.Whitespace;
|
||||
state = State.Whitespace
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,58 +33,58 @@ export function whitespaceWordRanges(
|
||||
if (state === State.Word) {
|
||||
ranges.push({
|
||||
start: startIndex,
|
||||
end: text.length - 1
|
||||
});
|
||||
end: text.length - 1,
|
||||
})
|
||||
}
|
||||
|
||||
return ranges;
|
||||
return ranges
|
||||
}
|
||||
|
||||
export function wordRanges(text: string): { start: number; end: number }[] {
|
||||
enum State {
|
||||
Whitespace,
|
||||
Word,
|
||||
NonWord
|
||||
NonWord,
|
||||
}
|
||||
|
||||
let state = State.Whitespace;
|
||||
let startIndex = 0;
|
||||
const ranges = [];
|
||||
let state = State.Whitespace
|
||||
let startIndex = 0
|
||||
const ranges = []
|
||||
|
||||
for (let i = 0; i < text.length; ++i) {
|
||||
const char = text[i];
|
||||
const char = text[i]
|
||||
|
||||
if (state === State.Whitespace) {
|
||||
if (!isWhitespaceCharacter(char)) {
|
||||
startIndex = i;
|
||||
state = isWordCharacter(char) ? State.Word : State.NonWord;
|
||||
startIndex = i
|
||||
state = isWordCharacter(char) ? State.Word : State.NonWord
|
||||
}
|
||||
} else if (state === State.Word) {
|
||||
if (!isWordCharacter(char)) {
|
||||
ranges.push({
|
||||
start: startIndex,
|
||||
end: i - 1
|
||||
});
|
||||
end: i - 1,
|
||||
})
|
||||
|
||||
if (isWhitespaceCharacter(char)) {
|
||||
state = State.Whitespace;
|
||||
state = State.Whitespace
|
||||
} else {
|
||||
state = State.NonWord;
|
||||
startIndex = i;
|
||||
state = State.NonWord
|
||||
startIndex = i
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!isNonWordCharacter(char)) {
|
||||
ranges.push({
|
||||
start: startIndex,
|
||||
end: i - 1
|
||||
});
|
||||
end: i - 1,
|
||||
})
|
||||
|
||||
if (isWhitespaceCharacter(char)) {
|
||||
state = State.Whitespace;
|
||||
state = State.Whitespace
|
||||
} else {
|
||||
state = State.Word;
|
||||
startIndex = i;
|
||||
state = State.Word
|
||||
startIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -95,21 +93,21 @@ export function wordRanges(text: string): { start: number; end: number }[] {
|
||||
if (state !== State.Whitespace) {
|
||||
ranges.push({
|
||||
start: startIndex,
|
||||
end: text.length - 1
|
||||
});
|
||||
end: text.length - 1,
|
||||
})
|
||||
}
|
||||
|
||||
return ranges;
|
||||
return ranges
|
||||
}
|
||||
|
||||
function isNonWordCharacter(char: string): boolean {
|
||||
return NON_WORD_CHARACTERS.indexOf(char) >= 0;
|
||||
return NON_WORD_CHARACTERS.includes(char)
|
||||
}
|
||||
|
||||
function isWhitespaceCharacter(char: string): boolean {
|
||||
return char === " " || char === "\t";
|
||||
return char === ' ' || char === '\t'
|
||||
}
|
||||
|
||||
function isWordCharacter(char: string): boolean {
|
||||
return !isWhitespaceCharacter(char) && !isNonWordCharacter(char);
|
||||
return !isWhitespaceCharacter(char) && !isNonWordCharacter(char)
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as vscode from 'vscode'
|
||||
|
||||
export function flashYankHighlight(
|
||||
editor: vscode.TextEditor,
|
||||
ranges: vscode.Range[]
|
||||
) {
|
||||
export function flashYankHighlight(editor: vscode.TextEditor, ranges: vscode.Range[]) {
|
||||
const decoration = vscode.window.createTextEditorDecorationType({
|
||||
backgroundColor: vscode.workspace
|
||||
.getConfiguration("simpleVim")
|
||||
.get("yankHighlightBackgroundColor")
|
||||
});
|
||||
.getConfiguration('simpleVim')
|
||||
.get('yankHighlightBackgroundColor'),
|
||||
})
|
||||
|
||||
editor.setDecorations(decoration, ranges);
|
||||
setTimeout(() => decoration.dispose(), 200);
|
||||
editor.setDecorations(decoration, ranges)
|
||||
setTimeout(() => decoration.dispose(), 200)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user