icon

Fohte Blog

2023-09-18

GhostText: Vim でブラウザのテキストエリアを入力する

この記事は Vim 駅伝 の 2023-09-18 の記事です。


皆さんは「Vim でブラウザのテキストエリアを入力したい」と思ったことはありますか?
筆者は幾度となくありました。

これは GhostText を使うと実現できます。
筆者は記事執筆時点で 1 ヶ月利用しており、テキスト入力が非常に快適になったため、今回はその GhostText を紹介します。

GhostText とはなにか?

GhostText は、Chrome をはじめとする多くのブラウザを介して、Vim や Neovim などのエディターに接続し、双方向に入力内容を同期するブラウザ拡張機能およびエディタープラグインです。

GhostText で入力を同期する例
GhostText で入力を同期する例

「ブラウザのテキストエリアを Vim で編集する」という目的を達成できるツールは GhostText 以外にも、Firenvim というテキストエリアに Neovim を埋め込むツールだったり、wasavi という textarea を vi のクローンに置き換える Chrome 拡張機能などもあります。
(筆者は Firenvim も試しましたが、日本語入力がうまく機能しなかったのと、ショートカットキーなどの入力が Chrome に吸われてしまうのが難点でした。)

サポートされているブラウザ・エディター

Chrome と Vim/Neovim だけでなく、様々なブラウザ・エディターをサポートしています。

  • ブラウザ: Chrome, Firefox, Safari, Edge, Opera
  • エディター: VSCode, Emacs, Vim, Neovim, Sublime Text

プロトコルのドキュメントが公開されているため、サポートされていないブラウザやエディターで使いたい場合でも自作が可能です。

GhostText を使うことによる嬉しさ

GhostText を使うと何が嬉しいかというと、やはり使い慣れたエディターでテキスト入力ができることでしょう。

筆者は GitHub Issue/PR 等で Markdown テキストを書くときに GhostText を多用しています。
インデントをしたかったり、ちょっとしたコードを書きたい場合だったり、まとめてテキスト操作したい場合だったり、Vim 操作ができると便利なケースがあります。

また、macOS の場合 Emacs-like なキーバインドが拡張機能不要で使えます。
行頭の Ctrl-a や行末の Ctrl-e、行末まで削除する Ctrl-k などは多用するのですが、やはり Vim で入力できたほうが便利であるケースも多いと感じています。

GhostText が使えないケース

残念ながら、GhostText が使えないケースもあります。
例えば、Google Docs のような純粋な textarea ではないリッチなテキストエリアは GhostText が使えません。1

GhostText のインストール方法

GhostText を利用するには、利用するブラウザに拡張機能、利用するエディターにプラグインをインストールする必要があります。

各ブラウザ拡張機能・エディタープラグインは、インストール方法を含め 公式ドキュメント にリンクされています。

筆者の場合は Neovim を使っているため、プラグインは (公式には紹介されていない) subnut/nvim-ghost.nvim をインストールしています。

https://github.com/fohte/dotfiles/blob/52fc6b35b95767597eb225b89f394424e5a7b03d/config/nvim/lua/plugins/nvim-ghost.lua

config/nvim/lua/plugins/nvim-ghost.lua
return {
'subnut/nvim-ghost.nvim',
init = function()
vim.g.nvim_ghost_autostart = 0
end,
config = function()
vim.api.nvim_create_augroup('nvim_ghost_user_autocommands', { clear = true })
vim.api.nvim_create_autocmd('User', {
pattern = { '*github.com' },
group = 'nvim_ghost_user_autocommands',
callback = function()
vim.opt.filetype = 'markdown'
end,
})
end,
}

GhostText の使い方

以下の手順で任意の textarea とエディターの同期が開始できます。

  1. テキストエディターを立ち上げる
  2. ブラウザーで任意のテキストエリアにフォーカスを当て、拡張機能のアイコンをクリックするかキーボードショートカットで GhostText を起動する
    • デフォルト設定:
      • macOS: Cmd-Shift-k
      • Windows: Ctrl-Shift-k
      • Linux: Ctrl-Shift-h

起動できれば、エディター側でテキスト入力すると、その内容が textarea に同期されます。
また、textarea でテキスト入力しても、エディター側に同期されます。

GhostText を起動して入力同期する例
GhostText を起動して入力同期する例

余談: 筆者のカスタマイズ

筆者は Neovim をプロジェクトごとに開く運用をしているため、GhostText 用の Neovim はそれ専用で立ち上げたく、ウィンドウも分けたいという気持ちがありました。

それを実現するために以下のような工夫をしています。

  • Neovim 側で GhostText が自動起動しないようにする (手動で立ち上げるため)

  • WezTerm で GhostText 専用のウィンドウを立ち上げる

    • https://github.com/fohte/dotfiles/blob/52fc6b35b95767597eb225b89f394424e5a7b03d/config/wezterm/wezterm.lua#L43-L62

      wezterm.lua
      local hacky_user_commands = {
      ['new-ghosttext-window'] = function(window, pane, cmd_context)
      local _, _, window = wezterm.mux.spawn_window({
      args = { 'zsh', '-c', 'nvim -c GhostTextStart' },
      cwd = wezterm.home_dir,
      })
      wezterm.GLOBAL.ghosttext_window_id = window:window_id()
      return
      end,
      }
      wezterm.on('user-var-changed', function(window, pane, name, value)
      if name == 'hacky-user-command' then
      local cmd_context = wezterm.json_parse(value)
      hacky_user_commands[cmd_context.cmd](window, pane, cmd_context)
      return
      end
      end)
    • https://github.com/fohte/dotfiles/blob/52fc6b35b95767597eb225b89f394424e5a7b03d/roles/bin/files/wezterm-user-command#L1-L8

      wezterm-user-command
      #!/usr/bin/env bash
      set -euo pipefail
      printf \
      "\033]1337;SetUserVar=%s=%s\007" \
      hacky-user-command \
      "$(jq -n --arg cmd "$1" '{"cmd":$cmd}' | base64)"
    • $ wezterm-user-command new-ghosttext-window で起動

  • Hammerspoon で WezTerm の専用ウィンドウにフォーカスするショートカットを割り当てる

まとめ

GhostText は、各ブラウザーのテキストエリアに Vim/Neovim をはじめとするエディターからテキスト入力できるツールです。
この記事では、GhostText の基本的な使い方や筆者が利用しているカスタマイズについて紹介しました。

好きなエディターでテキストエリアを入力できる体験は非常に快適で、手放せなくなります。
この記事が、GhostText を活用し日々の QoL を上げる一助となれば幸いです。

Footnotes

  1. issue はありますが、"it's too complex" ということで close されています。 https://github.com/fregante/GhostText/issues/162

icon

Fohte

© 2020 Fohte