mirror of
https://github.com/VSCodeVim/Vim.git
synced 2024-09-11 12:25:59 +03:00
parent
63bb90947b
commit
c3dd400854
@ -17,6 +17,7 @@ import { taskQueue } from './src/taskQueue';
|
||||
import { Register } from './src/register/register';
|
||||
import { SpecialKeys } from './src/util/specialKeys';
|
||||
import { HistoryTracker } from './src/history/historyTracker';
|
||||
import { exCommandParser } from './src/vimscript/exCommandParser';
|
||||
|
||||
let extensionContext: vscode.ExtensionContext;
|
||||
let previousActiveEditorUri: vscode.Uri | undefined;
|
||||
@ -97,6 +98,8 @@ async function loadConfiguration() {
|
||||
* The extension's entry point
|
||||
*/
|
||||
export async function activate(context: vscode.ExtensionContext, handleLocal: boolean = true) {
|
||||
ExCommandLine.parser = exCommandParser;
|
||||
|
||||
// before we do anything else, we need to load the configuration
|
||||
await loadConfiguration();
|
||||
|
||||
|
@ -1196,6 +1196,7 @@
|
||||
"@types/source-map-support": "0.5.6",
|
||||
"@types/vscode": "1.67.0",
|
||||
"@vscode/test-electron": "2.2.0",
|
||||
"circular-dependency-plugin": "^5.2.2",
|
||||
"clean-webpack-plugin": "4.0.0",
|
||||
"event-stream": "4.0.1",
|
||||
"fork-ts-checker-webpack-plugin": "7.2.13",
|
||||
|
@ -10,6 +10,8 @@ import { VimState } from './../state/vimState';
|
||||
export abstract class BaseAction implements IBaseAction {
|
||||
abstract readonly actionType: ActionType;
|
||||
|
||||
public name = '';
|
||||
|
||||
/**
|
||||
* If true, the cursor position will be added to the jump list on completion.
|
||||
*/
|
||||
|
@ -34,7 +34,6 @@ import { shouldWrapKey } from '../wrapping';
|
||||
import { ErrorCode, VimError } from '../../error';
|
||||
import { SearchDirection } from '../../vimscript/pattern';
|
||||
import { doesFileExist } from 'platform/fs';
|
||||
import { exCommandParser } from '../../vimscript/exCommandParser';
|
||||
|
||||
/**
|
||||
* A very special snowflake.
|
||||
@ -231,6 +230,7 @@ class EnableExtension extends BaseCommand {
|
||||
export class CommandNumber extends BaseCommand {
|
||||
modes = [Mode.Normal, Mode.Visual, Mode.VisualLine, Mode.VisualBlock];
|
||||
keys = ['<number>'];
|
||||
override name = 'cmd_num';
|
||||
override isCompleteAction = false;
|
||||
override actionType = 'number' as const;
|
||||
override runsOnceForEveryCursor() {
|
||||
@ -289,6 +289,7 @@ export class CommandNumber extends BaseCommand {
|
||||
export class CommandRegister extends BaseCommand {
|
||||
modes = [Mode.Normal, Mode.Visual, Mode.VisualLine, Mode.VisualBlock];
|
||||
keys = ['"', '<character>'];
|
||||
override name = 'cmd_register';
|
||||
override isCompleteAction = false;
|
||||
|
||||
public override async exec(position: Position, vimState: VimState): Promise<void> {
|
||||
@ -640,6 +641,10 @@ export class CommandShowCommandHistory extends BaseCommand {
|
||||
}
|
||||
}
|
||||
|
||||
ExCommandLine.onSearch = async (vimState: VimState) => {
|
||||
new CommandShowCommandHistory().exec(vimState.cursorStopPosition, vimState);
|
||||
};
|
||||
|
||||
@RegisterAction
|
||||
export class CommandShowSearchHistory extends BaseCommand {
|
||||
modes = [Mode.Normal, Mode.Visual, Mode.VisualLine, Mode.VisualBlock];
|
||||
@ -690,6 +695,11 @@ export class CommandShowSearchHistory extends BaseCommand {
|
||||
}
|
||||
}
|
||||
|
||||
// Register the command to execute on CtrlF.
|
||||
SearchCommandLine.onSearch = async (vimState: VimState, direction: SearchDirection) => {
|
||||
return new CommandShowSearchHistory(direction).exec(vimState.cursorStopPosition, vimState);
|
||||
};
|
||||
|
||||
@RegisterAction
|
||||
class CommandDot extends BaseCommand {
|
||||
modes = [Mode.Normal];
|
||||
@ -718,7 +728,7 @@ class CommandRepeatSubstitution extends BaseCommand {
|
||||
public override async exec(position: Position, vimState: VimState): Promise<void> {
|
||||
// Parsing the command from a string, while not ideal, is currently
|
||||
// necessary to make this work with and without neovim integration
|
||||
await exCommandParser.tryParse('s').command.execute(vimState);
|
||||
await ExCommandLine.parser.tryParse('s').command.execute(vimState);
|
||||
}
|
||||
}
|
||||
|
||||
@ -843,6 +853,7 @@ class CommandDeleteToLineEnd extends BaseCommand {
|
||||
export class CommandYankFullLine extends BaseCommand {
|
||||
modes = [Mode.Normal];
|
||||
keys = ['Y'];
|
||||
override name = 'yank_full_line';
|
||||
|
||||
public override async exec(position: Position, vimState: VimState): Promise<void> {
|
||||
const linesDown = (vimState.recordedState.count || 1) - 1;
|
||||
@ -1334,6 +1345,7 @@ class CommandTabPrevious extends BaseCommand {
|
||||
export class ActionDeleteChar extends BaseCommand {
|
||||
modes = [Mode.Normal];
|
||||
keys = ['x'];
|
||||
override name = 'delete_char';
|
||||
override createsUndoPoint = true;
|
||||
|
||||
public override async exec(position: Position, vimState: VimState): Promise<void> {
|
||||
@ -1358,6 +1370,7 @@ export class ActionDeleteChar extends BaseCommand {
|
||||
export class ActionDeleteCharWithDeleteKey extends BaseCommand {
|
||||
modes = [Mode.Normal];
|
||||
keys = ['<Del>'];
|
||||
override name = 'delete_char_with_del';
|
||||
override runsOnceForEachCountPrefix = true;
|
||||
override createsUndoPoint = true;
|
||||
|
||||
@ -1382,6 +1395,7 @@ export class ActionDeleteCharWithDeleteKey extends BaseCommand {
|
||||
export class ActionDeleteLastChar extends BaseCommand {
|
||||
modes = [Mode.Normal];
|
||||
keys = ['X'];
|
||||
override name = 'delete_last_char';
|
||||
override createsUndoPoint = true;
|
||||
|
||||
public override async exec(position: Position, vimState: VimState): Promise<void> {
|
||||
@ -2116,6 +2130,7 @@ class ActionGoToInsertVisualBlockModeAppend extends BaseCommand {
|
||||
export class ActionDeleteCharVisualLineMode extends BaseCommand {
|
||||
modes = [Mode.VisualLine];
|
||||
keys = ['x'];
|
||||
override name = 'delete_char_visual_line_mode';
|
||||
|
||||
public override async exec(position: Position, vimState: VimState): Promise<void> {
|
||||
const [start, end] = sorted(vimState.cursorStartPosition, vimState.cursorStopPosition);
|
||||
|
@ -184,6 +184,15 @@ class CommandLineEscape extends CommandLineAction {
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
class CommandLineCtrlF extends CommandLineAction {
|
||||
keys = ['<C-f>'];
|
||||
|
||||
protected override async run(vimState: VimState, commandLine: CommandLine): Promise<void> {
|
||||
await commandLine.ctrlF(vimState);
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterAction
|
||||
class CommandLineBackspace extends CommandLineAction {
|
||||
keys = [['<BS>'], ['<S-BS>'], ['<C-h>']];
|
||||
|
@ -7,7 +7,6 @@ import { Register, RegisterMode } from './../register/register';
|
||||
import { VimState } from './../state/vimState';
|
||||
import { TextEditor } from './../textEditor';
|
||||
import { BaseAction, RegisterAction } from './base';
|
||||
import { CommandNumber } from './commands/actions';
|
||||
import { reportLinesChanged, reportLinesYanked } from '../util/statusBarTextUtils';
|
||||
import { ExCommandLine } from './../cmd_line/commandLine';
|
||||
import { Position } from 'vscode';
|
||||
@ -55,9 +54,7 @@ export abstract class BaseOperator extends BaseAction {
|
||||
}
|
||||
|
||||
public doesRepeatedOperatorApply(vimState: VimState, keysPressed: string[]) {
|
||||
const nonCountActions = vimState.recordedState.actionsRun.filter(
|
||||
(x) => !(x instanceof CommandNumber)
|
||||
);
|
||||
const nonCountActions = vimState.recordedState.actionsRun.filter((x) => x.name !== 'cmd_num');
|
||||
const prevAction = nonCountActions[nonCountActions.length - 1];
|
||||
return (
|
||||
keysPressed.length === 1 &&
|
||||
@ -101,6 +98,7 @@ export abstract class BaseOperator extends BaseAction {
|
||||
|
||||
@RegisterAction
|
||||
export class DeleteOperator extends BaseOperator {
|
||||
public override name = 'delete_op';
|
||||
public keys = ['d'];
|
||||
public modes = [Mode.Normal, Mode.Visual, Mode.VisualLine];
|
||||
|
||||
@ -188,6 +186,7 @@ class DeleteOperatorVisual extends BaseOperator {
|
||||
export class YankOperator extends BaseOperator {
|
||||
public keys = ['y'];
|
||||
public modes = [Mode.Normal, Mode.Visual, Mode.VisualLine];
|
||||
override name = 'yank_op';
|
||||
override createsUndoPoint = false;
|
||||
|
||||
public async run(vimState: VimState, start: Position, end: Position): Promise<void> {
|
||||
|
3
src/actions/types.d.ts
vendored
3
src/actions/types.d.ts
vendored
@ -4,7 +4,8 @@ import type { VimState } from '../state/vimState';
|
||||
export type ActionType = 'command' | 'motion' | 'operator' | 'number';
|
||||
|
||||
export interface IBaseAction {
|
||||
readonly actionType: ActionType
|
||||
name: string;
|
||||
readonly actionType: ActionType;
|
||||
readonly isJump: boolean;
|
||||
readonly createsUndoPoint: boolean;
|
||||
|
||||
|
@ -7,10 +7,9 @@ import { VimState } from '../state/vimState';
|
||||
import { configuration } from '../configuration/configuration';
|
||||
import { Register } from '../register/register';
|
||||
import { RecordedState } from '../state/recordedState';
|
||||
import { exCommandParser } from '../vimscript/exCommandParser';
|
||||
import { Parser } from 'parsimmon';
|
||||
import { IndexedPosition, IndexedRange, SearchState } from '../state/searchState';
|
||||
import { getWordLeftInText, getWordRightInText, WordType } from '../textobject/word';
|
||||
import { CommandShowCommandHistory, CommandShowSearchHistory } from '../actions/commands/actions';
|
||||
import { SearchDirection } from '../vimscript/pattern';
|
||||
import { reportSearch, escapeCSSIcons } from '../util/statusBarTextUtils';
|
||||
import { SearchDecorations, getDecorationsForSearchMatchRanges } from '../util/decorationUtils';
|
||||
@ -190,6 +189,8 @@ export abstract class CommandLine {
|
||||
|
||||
export class ExCommandLine extends CommandLine {
|
||||
static history: CommandLineHistory;
|
||||
static parser: Parser<{ lineRange: LineRange | undefined; command: ExCommand }>;
|
||||
static onSearch: (vimState: VimState) => Promise<void>;
|
||||
|
||||
public static async loadHistory(context: ExtensionContext): Promise<void> {
|
||||
ExCommandLine.history = new CommandLineHistory(context);
|
||||
@ -231,7 +232,7 @@ export class ExCommandLine extends CommandLine {
|
||||
|
||||
try {
|
||||
// TODO: This eager parsing is costly, and if it's not `:s` or similar, don't need to parse the args at all
|
||||
const { lineRange, command } = exCommandParser.tryParse(this.commandText);
|
||||
const { lineRange, command } = ExCommandLine.parser.tryParse(this.commandText);
|
||||
this.lineRange = lineRange;
|
||||
this.command = command;
|
||||
} catch (err) {
|
||||
@ -270,7 +271,7 @@ export class ExCommandLine extends CommandLine {
|
||||
try {
|
||||
if (this.command === undefined) {
|
||||
// TODO: A bit gross:
|
||||
exCommandParser.tryParse(this.text);
|
||||
ExCommandLine.parser.tryParse(this.text);
|
||||
throw new Error(`Expected parsing ExCommand '${this.text}' to fail`);
|
||||
}
|
||||
|
||||
@ -314,13 +315,14 @@ export class ExCommandLine extends CommandLine {
|
||||
}
|
||||
|
||||
public async ctrlF(vimState: VimState): Promise<void> {
|
||||
new CommandShowCommandHistory().exec(vimState.cursorStopPosition, vimState);
|
||||
ExCommandLine.onSearch(vimState);
|
||||
}
|
||||
}
|
||||
|
||||
export class SearchCommandLine extends CommandLine {
|
||||
public static history: SearchHistory;
|
||||
public static readonly previousSearchStates: SearchState[] = [];
|
||||
public static onSearch: (vimState: VimState, direction: SearchDirection) => Promise<void>;
|
||||
|
||||
/**
|
||||
* Shows the search history as a QuickPick (popup list)
|
||||
@ -525,10 +527,7 @@ export class SearchCommandLine extends CommandLine {
|
||||
}
|
||||
|
||||
public async ctrlF(vimState: VimState): Promise<void> {
|
||||
await new CommandShowSearchHistory(this.searchState.direction).exec(
|
||||
vimState.cursorStopPosition,
|
||||
vimState
|
||||
);
|
||||
await SearchCommandLine.onSearch(vimState, this.searchState.direction);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,7 +21,7 @@ import {
|
||||
import * as packagejson from '../../package.json';
|
||||
import { SUPPORT_VIMRC } from 'platform/constants';
|
||||
|
||||
// https://stackovrflow.com/questions/51465182/how-to-remove-index-signature-using-mapped-types/51956054#51956054
|
||||
// https://stackoverflow.com/questions/51465182/how-to-remove-index-signature-using-mapped-types/51956054#51956054
|
||||
type RemoveIndex<T> = {
|
||||
[P in keyof T as string extends P ? never : number extends P ? never : P]: T[P];
|
||||
};
|
||||
|
@ -6,7 +6,6 @@ import * as vscode from 'vscode';
|
||||
import { IConfiguration, IVimrcKeyRemapping } from './iconfiguration';
|
||||
import { vimrcKeyRemappingBuilder } from './vimrcKeyRemappingBuilder';
|
||||
import { window } from 'vscode';
|
||||
import { configuration } from './configuration';
|
||||
import { Logger } from '../util/logger';
|
||||
|
||||
export class VimrcImpl {
|
||||
@ -92,7 +91,13 @@ export class VimrcImpl {
|
||||
});
|
||||
if (newVimrc) {
|
||||
await fs.writeFileAsync(newVimrc.fsPath, '', 'utf-8');
|
||||
configuration.getConfiguration('vim').update('vimrc.path', newVimrc.fsPath, true);
|
||||
const document = vscode.window.activeTextEditor?.document;
|
||||
const resource = document
|
||||
? { uri: document.uri, languageId: document.languageId }
|
||||
: undefined;
|
||||
vscode.workspace
|
||||
.getConfiguration('vim', resource)
|
||||
.update('vimrc.path', newVimrc.fsPath, true);
|
||||
await vscode.workspace.openTextDocument(newVimrc);
|
||||
// TODO: add some sample remaps/settings in here?
|
||||
await vscode.window.showTextDocument(newVimrc);
|
||||
|
@ -1,13 +1,4 @@
|
||||
import { Clipboard } from './../util/clipboard';
|
||||
import {
|
||||
ActionDeleteChar,
|
||||
ActionDeleteCharVisualLineMode,
|
||||
ActionDeleteCharWithDeleteKey,
|
||||
ActionDeleteLastChar,
|
||||
CommandRegister,
|
||||
CommandYankFullLine,
|
||||
} from './../actions/commands/actions';
|
||||
import { DeleteOperator, YankOperator } from './../actions/operator';
|
||||
import { RecordedState } from './../state/recordedState';
|
||||
import { VimState } from './../state/vimState';
|
||||
import { readFileAsync, writeFileAsync } from 'platform/fs';
|
||||
@ -216,11 +207,14 @@ export class Register {
|
||||
private static processNumberedRegisters(vimState: VimState, content: RegisterContent): void {
|
||||
// Find the BaseOperator of the current actions
|
||||
const baseOperator = vimState.recordedState.operator || vimState.recordedState.command;
|
||||
if (!baseOperator) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (baseOperator instanceof YankOperator || baseOperator instanceof CommandYankFullLine) {
|
||||
if (baseOperator.name === 'yank_op' || baseOperator.name === 'yank_full_line') {
|
||||
// 'yank' to 0 only if no register was specified
|
||||
const registerCommand = vimState.recordedState.actionsRun.find((value) => {
|
||||
return value instanceof CommandRegister;
|
||||
return value.name === 'cmd_register';
|
||||
});
|
||||
|
||||
if (!registerCommand) {
|
||||
@ -232,11 +226,11 @@ export class Register {
|
||||
]);
|
||||
}
|
||||
} else if (
|
||||
(baseOperator instanceof DeleteOperator ||
|
||||
baseOperator instanceof ActionDeleteChar ||
|
||||
baseOperator instanceof ActionDeleteLastChar ||
|
||||
baseOperator instanceof ActionDeleteCharVisualLineMode ||
|
||||
baseOperator instanceof ActionDeleteCharWithDeleteKey) &&
|
||||
(baseOperator.name === 'delete_op' ||
|
||||
baseOperator.name === 'delete_char' ||
|
||||
baseOperator.name === 'delete_last_char' ||
|
||||
baseOperator.name === 'delete_char_visual_line_mode' ||
|
||||
baseOperator.name === 'delete_char_with_del') &&
|
||||
!(vimState.macro !== undefined || vimState.isReplayingMacro)
|
||||
) {
|
||||
if (
|
||||
|
@ -6,6 +6,7 @@ const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
|
||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
||||
const CircularDependencyPlugin = require('circular-dependency-plugin');
|
||||
|
||||
/**@type {import('webpack').Configuration}*/
|
||||
const config = {
|
||||
@ -54,6 +55,19 @@ const config = {
|
||||
cleanOnceBeforeBuildPatterns: [], // disable initial clean
|
||||
}),
|
||||
new ForkTsCheckerWebpackPlugin(),
|
||||
new CircularDependencyPlugin({
|
||||
// exclude detection of files based on a RegExp
|
||||
exclude: /node_modules/,
|
||||
// include specific files based on a RegExp
|
||||
include: /src/,
|
||||
// add errors to webpack instead of warnings
|
||||
failOnError: true,
|
||||
// allow import cycles that include an asyncronous import,
|
||||
// e.g. via import(/* webpackMode: "weak" */ './file.js')
|
||||
allowAsyncCycles: true,
|
||||
// set the current working directory for displaying module paths
|
||||
cwd: process.cwd(),
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
|
@ -1134,6 +1134,11 @@ chrome-trace-event@^1.0.2:
|
||||
dependencies:
|
||||
tslib "^1.9.0"
|
||||
|
||||
circular-dependency-plugin@^5.2.2:
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz#39e836079db1d3cf2f988dc48c5188a44058b600"
|
||||
integrity sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==
|
||||
|
||||
class-utils@^0.3.5:
|
||||
version "0.3.6"
|
||||
resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
|
||||
|
Loading…
Reference in New Issue
Block a user