iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🌐

Writing Claude Code prompts in Neovim (tmux version)

に公開
2

Introduction

Writing Claude Code prompts comfortably in Neovim

The article above introduced a method using zellij, but since I'm a tmux user, I tried setting it up to do something similar with tmux. I had just recently moved to Neovim, so it was very helpful to see how this could be achieved.

Previously, it was difficult to write directly into the prompt on Claude Code, and I often made accidental submissions, so I used to write in a notepad first and then submit it.
However, with this setup, I can now write and submit prompts in a pop-up Neovim without leaving Claude Code, which has made it considerably more comfortable.

Operation Image

Operation image

Prerequisites

  • tmux
  • neovim
  • fzf

Settings

neovim

If you are using lazy.nvim, configure it as follows.
The fzf itself needs to be installed using mise or similar, and its PATH needs to be specified, so you will need to modify the relevant parts.

~/.config/nvim/lua/plugins/fzf.lua

return {
  "ibhagwan/fzf-lua",
  dependencies = { "nvim-tree/nvim-web-devicons" },

  config = function()
    local fzf = require("fzf-lua")

    -- ★ PATH issue workaround: fix fzf_bin
    fzf.setup({
      fzf_bin = os.getenv("HOME") .. "/.local/share/mise/shims/fzf",
    })

    -- ★ In markdown, @ → insert file
    vim.api.nvim_create_autocmd("FileType", {
      pattern = "markdown",
      callback = function(ev)
        vim.keymap.set("i", "@", function()
          local selected_path = nil
          fzf.files({
            file_icons = false,
            git_icons = false,
            actions = {
              ["default"] = function(selected, opts)
                if selected and selected[1] then
                  local file = require("fzf-lua.path").entry_to_file(selected[1], opts)
                  selected_path = file and file.path or nil
                end
              end
            },
            winopts = {
              on_close = function()
                vim.schedule(function()
                  if selected_path then
                    vim.api.nvim_put({ "@" .. selected_path }, "", false, true)
                  else
                    vim.api.nvim_put({ "@" }, "", false, true)
                  end
                  vim.defer_fn(function()
                    vim.cmd("startinsert!")
                  end, 10)
                end)
              end
            }
          })
        end, { buffer = ev.buf, noremap = true })
      end,
    })
  end
}

tmux

Add the following to ~/.tmux.conf. I have set it to bind e, but you can change this to your preference.

# Alt-e to launch popup editor (pass the ID of the caller pane)
bind e run-shell "bash ~/.config/tmux/claude-prompt-edit.sh '#{pane_id}'"

Create a script named ~/.config/tmux/claude-prompt-edit.sh and add the following content.

#!/usr/bin/env bash

# Caller pane ID (passed from tmux.conf)
TARGET_PANE="$1"

# Create a temporary file
TMPFILE="$(mktemp /tmp/claude-prompt-XXXXXX.md)"

# Check if running inside a tmux session (precaution)
if [ -z "${TMUX:-}" ]; then
  echo "Error: This script must be run inside a tmux session." >&2
  exit 1
fi

# Launch "usual shell environment + nvim" inside the popup
# -E: Close popup when command (nvim) finishes
tmux display-popup -E -w 80% -h 70% -T "Claude Prompt" \
  "$SHELL -i -c 'nvim \"$TMPFILE\"'"

# ==== The following will be executed after nvim is closed ====

# Debug: Display TMPFILE path and size in tmux status
if [ -f "$TMPFILE" ]; then
  SIZE="$(wc -c < "$TMPFILE" 2>/dev/null || echo 0)"
  tmux display-message "claude-popup: file=$TMPFILE size=${SIZE}B"
else
  tmux display-message "claude-popup: TMPFILE not found: $TMPFILE"
fi

# Paste if temporary file has content
if [ -s "$TMPFILE" ]; then
  CONTENT="$(cat "$TMPFILE")"

  # Put into buffer
  tmux set-buffer -b claude_prompt -- "$CONTENT"

  # ★ Explicitly paste into the caller pane ★
  tmux paste-buffer -b claude_prompt -t "$TARGET_PANE"
else
  tmux display-message "claude-popup: TMPFILE is empty, skip paste"
fi

# Cleanup
rm -f "$TMPFILE"

exit 0

Conclusion

It's a bit strange that the prompt isn't automatically pasted onto Claude Code when returning from the Neovim popup. However, it still works fine since pressing Enter sends it correctly. If anyone knows a solution, please let me know.

GitHubで編集を提案

Discussion

Ticklon DEVTicklon DEV

私も似たようなことをやっています。
バッファを介さず

tmux send-keys -t "$TMUX_PANE" "$(cat $TMPFILE)"

で直接送りつけています!

この保険的フォールバックは参考になりました!ありがとうございます☺️

if [ -z "${TMUX:-}" ]; then
  echo "Error: This script must be run inside a tmux session." >&2
  exit 1
fi
sumiksumik

みんなやっぱりclaude codeのプロンプトで苦戦してますね笑
vimモードあっても使いにくいですよね

まぁでもメモ帳で残しておくのも、実行した内容をログとして残しておけるのでこれはこれで良かったかも?とちょっと思ってたり。(ログを残す仕組み作ってる方もいるし、claude-memもありますが