format with prettier

This commit is contained in:
garlandcrow 2022-11-09 14:35:37 +09:00
parent 14b5c79d36
commit dab8857c6a
41 changed files with 1963 additions and 5609 deletions

View File

@ -1,3 +0,0 @@
{
"extends": "@antfu"
}

27
.eslintrc.cjs Normal file
View 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
View File

@ -1,5 +1,5 @@
.DS_Store
out
dist/
node_modules
.vscode-test/
.vsix

View File

@ -2,7 +2,7 @@
"printWidth": 100,
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"trailingComma": "all",
"arrowParens": "always",
"pluginSearchDirs": ["."]
}

3177
dist/index.js vendored

File diff suppressed because it is too large Load Diff

24
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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

View File

@ -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,
}
}

View File

@ -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)

View File

@ -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',
},
};
}

View File

@ -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
}
});
};
})
}
}

View File

@ -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
}
}

View File

@ -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,
}
}

View File

@ -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]
}
}

View File

@ -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
}

View File

@ -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 = []
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -3,5 +3,5 @@ export enum Mode {
Normal,
Visual,
VisualLine,
Occurrence
Occurrence,
}

View File

@ -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
}

View File

@ -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,
}
}
};
}
}

View File

@ -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

View File

@ -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,
)
}

View File

@ -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)
}

View File

@ -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)
})
}

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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')
}

View File

@ -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
}

View File

@ -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 }),
)
}
}

View File

@ -1,4 +1,4 @@
export type SimpleRange = {
start: number;
end: number;
};
start: number
end: number
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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()
}
}

View File

@ -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
}
}

View File

@ -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 }),
)
}
});
})
}

View File

@ -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)
}
});
})
}

View File

@ -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)
}

View File

@ -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)
}