Fix the remaining dependency cycles. (#7483)

Fixes #6177
This commit is contained in:
Evgeny Gryaznov 2022-12-06 04:08:15 +01:00 committed by GitHub
parent 63bb90947b
commit c3dd400854
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 82 additions and 35 deletions

View File

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

View File

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

View File

@ -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.
*/

View File

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

View File

@ -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>']];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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