Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion packages/codemirror-vim-core/test/vim_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1333,9 +1333,14 @@ testVim('on_mode_change', async function(cm, vim, helpers) {
test('a', 'insert');
test('<Esc>', 'normal');
test('v', 'visual');
test(':', ''); // Event for Command-line mode not implemented.
test(':', isOldCodeMirror ? '' : 'command');
test('y\n', 'normal');
test(":startinsert\n", "insert");
test('<Esc>', 'normal');
if (!isOldCodeMirror) {
test(':', 'command');
test('<Esc>', 'normal');
}
});

// Swapcase commands edit in place and do not modify registers.
Expand Down
7 changes: 7 additions & 0 deletions packages/codemirror-vim-core/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,13 @@ export type ExParams = {
callback?: () => void,
}

export type VimMode = 'normal' | 'insert' | 'visual' | 'replace' | 'command';
export type VimSubMode = 'linewise' | 'blockwise' | '';

export type VimModeChangeEvent =
| { mode: 'visual'; subMode?: VimSubMode }
| { mode: 'normal' | 'insert' | 'replace' | 'command'; subMode?: undefined };

export type PromptOptions = {
onClose?: Function;
prefix: string|HTMLElement;
Expand Down
32 changes: 29 additions & 3 deletions packages/codemirror-vim/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,15 @@ const vimStyle = EditorView.baseTheme({
});
type EditorViewExtended = EditorView & { cm: CodeMirror };

import type { VimMode, VimSubMode, VimModeChangeEvent } from "@replit/codemirror-vim-core";
export type { VimMode, VimSubMode, VimModeChangeEvent };

const vimPlugin = ViewPlugin.fromClass(
class implements PluginValue {
private dom: HTMLElement;
private statusButton: HTMLElement;
private spacer: HTMLElement;
private inCommandMode = false;
public view: EditorViewExtended;
public cm: CodeMirror;
public status = "";
Expand All @@ -72,11 +76,16 @@ const vimPlugin = ViewPlugin.fromClass(
this.blockCursor.scheduleRedraw();
this.updateStatus();
});
this.cm.on("vim-mode-change", (e: any) => {
this.cm.on("vim-mode-change", (e: VimModeChangeEvent) => {
if (!cm.state.vim) return;
if (e.mode !== "command") {
this.inCommandMode = false;
}
cm.state.vim.mode = e.mode;
if (e.subMode) {
cm.state.vim.mode += e.subMode === "linewise" ? " line" : " block";
if (e.subMode === "linewise") {
cm.state.vim.mode += " line";
} else if (e.subMode === "blockwise") {
cm.state.vim.mode += " block";
}
cm.state.vim.status = "";
this.blockCursor.scheduleRedraw();
Expand All @@ -92,6 +101,23 @@ const vimPlugin = ViewPlugin.fromClass(
effects: showVimPanel.of(!!this.cm.state.dialog),
});
}
// Emit mode change for interactive command/search prompt enter/exit
const isPrompt = !!this.cm.state.dialog?.querySelector("input");
if (isPrompt) {
if (!this.inCommandMode) {
this.inCommandMode = true;
CodeMirror.signal(cm, "vim-mode-change", { mode: "command" });
}
} else if (this.inCommandMode) {
this.inCommandMode = false;
const vim = cm.state.vim;
if (vim) {
CodeMirror.signal(cm, "vim-mode-change", {
mode: vim.insertMode ? "insert" : vim.visualMode ? "visual" : "normal",
subMode: vim.visualLine ? "linewise" : vim.visualBlock ? "blockwise" : undefined,
});
}
}
});

this.dom = document.createElement("span");
Expand Down
Loading