zudo-codemirror-wisdom

Type to search...

to open search from anywhere

vimrc サポート

作成2026年3月29日更新2026年4月3日Takeshi Takatsudo

Vim.handleEx() を使って @replit/codemirror-vim に vimrc スタイルの設定を適用する方法。

vimrc サポート

@replit/codemirror-vimVim.handleEx() メソッドを使って、実行時に vimrc スタイルのコマンドを実行できます。これにより、ユーザーが提供する Vim 設定テキストをアプリケーションで1行ずつパースして適用できます。

Vim.handleEx()

Vim.handleEx() は、ユーザーがコマンドラインモードで入力したかのように、単一の Ex コマンド文字列を実行します。

import { getCM, Vim } from "@replit/codemirror-vim";

const cm = getCM(view)!;
Vim.handleEx(cm, "set number");
Vim.handleEx(cm, "imap jk <Esc>");

第1引数は getCM(view) で取得できる CodeMirror アダプターオブジェクトです。第2引数は生の Ex コマンド文字列(先頭の : なし)です。

CodeMirror アダプターの取得

getCM() は EditorView を受け取り、Vim レイヤーが操作する内部の CodeMirror アダプターを返します。

import { getCM } from "@replit/codemirror-vim";

const cm = getCM(view);

⚠️ Warning

getCM() は、指定された view で Vim Extension がアクティブでない場合、undefined を返すことがあります。Vim.handleEx() に渡す前に戻り値を確認してください。

vimrc 文字列のパース

vimrc ファイルは1行に1コマンドで構成されます。空行と "(ダブルクォート)で始まる行はコメントです。

function parseVimrc(content: string): string[] {
  return content
    .split("\n")
    .map((line) => line.trim())
    .filter((line) => line.length > 0 && !line.startsWith('"'));
}

vimrc コマンドの適用

パースされたコマンドを順に実行します。すべての vimrc コマンドがサポートされているわけではないため、try/catch でラップします。

import { getCM, Vim } from "@replit/codemirror-vim";

function applyVimrc(view: EditorView, vimrcContent: string) {
  const cm = getCM(view);
  if (!cm) return;

  for (const cmd of parseVimrc(vimrcContent)) {
    try {
      Vim.handleEx(cm, cmd);
    } catch (e) {
      console.warn("vimrc command failed:", cmd, e);
    }
  }
}

vimrc の内容の例

ユーザーが提供する典型的な vimrc 文字列です。

" Basic settings
set number

" Key mappings
imap jk <Esc>
nmap H ^
nmap L $
nnoremap j gj
nnoremap k gk

" Leader mappings
map <Space> <Leader>
nmap <Leader>w :w<CR>
nmap <Leader>q :q<CR>

よく使われる vimrc 設定

行番号

set number
set nonumber

これらは @replit/codemirror-vim でそのまま動作します。

行の折り返し

set wrap
set nowrap

📝 Note

set wrapset nowrapVim.defineOption() によるカスタムオプション定義が必要です。実装方法は Vim オプションのページを参照してください。

Insert モードのエスケープマッピング

imap jk <Esc>

表示行でのナビゲーション

j/k をバッファ行ではなく表示行(折り返された行)での移動にマッピングします。

nnoremap j gj
nnoremap k gk

リーダーキーの設定

map <Space> <Leader>
nmap <Leader>w :w<CR>
nmap <Leader>q :q<CR>
nmap <Leader>h :nohlsearch<CR>

タイミングに関する注意

vimrc コマンドは、EditorView が作成され Vim Extension が初期化された後に適用してください。早すぎるタイミングで適用すると、getCM(view)undefined を返す場合があります。

const view = new EditorView({
  extensions: [vim(), basicSetup],
  parent: document.getElementById("editor")!,
});

// Apply vimrc after view creation
applyVimrc(view, userVimrcContent);

ユーザー入力からの vimrc 読み込み

実用的なパターンとして、ユーザーに vimrc をペーストまたはアップロードしてもらい、保存し、エディター初期化時に再適用する方法があります。

function loadVimrc(): string | null {
  return localStorage.getItem("user-vimrc");
}

function saveVimrc(content: string) {
  localStorage.setItem("user-vimrc", content);
}

// On editor init
const vimrc = loadVimrc();
if (vimrc) {
  applyVimrc(view, vimrc);
}

ファイルベース + 設定ベースの vimrc レイヤリング

デスクトップアプリケーションでは、2つの vimrc ソースをサポートしたい場合があります。

  1. ファイルベースの vimrc — ディスク上の .vimrc ファイル。バックエンド(例: Tauri IPC)経由でロード
  2. 設定ベースの vimrc — アプリケーション設定 UI に保存された vimrc 文字列

レイヤリング戦略は、ファイルベースの vimrc を最初に適用し、次に設定ベースの vimrc を適用します。これにより、設定ベースのオーバーライドが優先され、ユーザーはディスクファイルを編集せずに動作をカスタマイズできます。

import { getCM, Vim } from "@replit/codemirror-vim";

async function applyLayeredVimrc(
  view: EditorView,
  settingsVimrc: string,
  readVimrcFromDisk: () => Promise<string | null>,
) {
  const cm = getCM(view);
  if (!cm) return;

  const applyVimrc = (source: string, label: string) => {
    for (const cmd of parseVimrc(source)) {
      try {
        Vim.handleEx(cm, cmd);
      } catch (e) {
        console.warn(`${label} vimrc command failed: ${cmd}`, e);
      }
    }
  };

  // レイヤー 1: ファイルベースの vimrc(ディスクからロード)
  const fileVimrc = await readVimrcFromDisk();
  if (fileVimrc) {
    applyVimrc(fileVimrc, "file-based");
  }

  // レイヤー 2: 設定ベースの vimrc(ファイルベースをオーバーライド)
  if (settingsVimrc) {
    applyVimrc(settingsVimrc, "settings");
  }
}

💡 Tip

このレイヤリングパターンはシェル設定の動作(/etc/profile の後に ~/.profile)を模倣しています。ファイルベースの vimrc はマシンレベルのデフォルトを提供し、設定ベースの vimrc は UI を通じたアプリケーションごとのカスタマイズを可能にします。

非同期ロードの処理

ファイルベースの vimrc はファイルシステム API 経由で非同期にロードされるため、vimrc の適用は EditorView の作成後に行われます。破棄されたエディターへの vimrc 適用を防ぐために、キャンセルガードを使用します。

let cancelled = false;

readVimrcFromDisk().then((vimrcContent) => {
  if (cancelled) return;
  const cm = getCM(view);
  if (!cm) return;

  if (vimrcContent) {
    applyVimrc(vimrcContent, "file-based");
  }
  if (settingsVimrc) {
    applyVimrc(settingsVimrc, "settings");
  }
});

// クリーンアップ時:
cancelled = true;

これは、非同期の vimrc 読み取りが完了する前にエディターが破棄され再作成される可能性がある React アプリケーションで重要です。

Revision History