Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

send alt-x keycodes to vim.fn.chansend() #29299

Open
rish987 opened this issue Jun 12, 2024 · 5 comments
Open

send alt-x keycodes to vim.fn.chansend() #29299

rish987 opened this issue Jun 12, 2024 · 5 comments
Labels
enhancement feature request terminal built-in :terminal or :shell
Milestone

Comments

@rish987
Copy link
Contributor

rish987 commented Jun 12, 2024

Problem

I've been tinkering around with nested neovim instances and sending pre-recorded keystrokes to them with vim.fn.feedkeys. In order to allow me to send these keys without having to have the nested sessions open in a terminal as my current window, I've been trying to transition my code to use vim.fn.chansend instead. But it doesn't seem to have the same effect when sending alt-modified keycodes.

Steps to reproduce

Execute the following script, "hello" is not printed as expected:

map = "<A-x>"
job_id = vim.fn.termopen("nvim --cmd 'map " .. map .. " :echo \"hello\"<CR>'")
vim.defer_fn(function()
  vim.fn.chansend(job_id, vim.api.nvim_replace_termcodes(map, true, true, true))
end, 500)

Expected behavior

The mapping in the nested instance should execute and "hello" should be printed, as it does when we use feedkeys:

map = "<A-x>"
vim.fn.termopen("nvim --cmd 'map " .. map .. " :echo \"hello\"<CR>'")
vim.defer_fn(function()
  vim.fn.feedkeys("i" .. vim.api.nvim_replace_termcodes(map, true, true, true))
end, 500)

or when we use a different mapping:

map = "<C-q>"
job_id = vim.fn.termopen("nvim --cmd 'map " .. map .. " :echo \"hello\"<CR>'")
vim.defer_fn(function()
  vim.fn.chansend(job_id, vim.api.nvim_replace_termcodes(map, true, true, true))
end, 500)

Neovim version (nvim -v)

NVIM v0.10.0

Vim (not Nvim) behaves the same?

N/A

Operating system/version

Ubuntu 22.04.3

Terminal name/version

Alacritty 0.13.1

$TERM environment variable

xterm-256color

Installation

build from repo

@rish987 rish987 added the bug issues reporting wrong behavior label Jun 12, 2024
@rish987
Copy link
Contributor Author

rish987 commented Jun 12, 2024

Actually, considering that the chansend function is probably fairly simple and just sends bytes to the child process, I'm not sure if this is a bug rather than a misuse of vim.api.nvim_replace_termcodes() on my part. Do you know if there is a different function I should be using?

@zeertzjq
Copy link
Member

zeertzjq commented Jun 12, 2024

This sounds more like a feature request than a bug report.

@zeertzjq zeertzjq added enhancement feature request terminal built-in :terminal or :shell and removed bug issues reporting wrong behavior labels Jun 12, 2024
@justinmk
Copy link
Member

justinmk commented Jun 12, 2024

:help nvim_replace_termcodes() mentions:

Replaces terminal codes and |keycodes| in a string with the internal representation.

chansend() expects the "external" input, not the "internal representation". The external form of <A-x> would be ESC x.

@justinmk justinmk added this to the unplanned milestone Jun 12, 2024
@justinmk justinmk changed the title Cannot send alt-modified keycodes with vim.fn.chansend send alt-x keycodes to vim.fn.chansend() Jun 12, 2024
@rish987
Copy link
Contributor Author

rish987 commented Jun 12, 2024

Okay, so it seems that what might be lacking here is a vim.api.nvim_replace_termcodes()-like function for getting the external, rather than internal form? Or perhaps one to go from internal to external (which would be more useful in my case as I'm originally getting my keys from recorded macros in registers, where they have an internal representation)?

For the record, I've managed to work around this using an RPC session which calls vim.api.feedkeys() on the side of the nested instance:

map = "<A-x>"
job_id = vim.fn.termopen("nvim --cmd 'map " .. map .. " :echo \"hello\"<CR>' --listen /tmp/exnvimsock")
vim.defer_fn(function()
  local sock = vim.fn.sockconnect("pipe", "/tmp/exnvimsock", {rpc = true})
  vim.fn.rpcrequest(sock, "nvim_exec_lua",
    "vim.fn.feedkeys(vim.api.nvim_replace_termcodes(..., true, true, true))", {map})
end, 500)

But obviously that's not a completely general solution (unless you're willing to always execute your automated terminal sessions through an extra layer of nvim).

@justinmk
Copy link
Member

justinmk commented Jun 12, 2024

I assume you are using termopen() because you want to see the UI of the nested nvim in a buffer. The :terminal buffer will have :help $NVIM env var set, so the child Nvim can open a channel to the parent, and call a function in the parent which adds the channel to a list. Then from the parent, you can call RPC functions such as nvim_input on the child.

Thus there is no need to send raw bytes via chansend().

Alternatively if you don't need to see the nested Nvim in a :terminal...

  • you can start it with nvim --embed, from jobstart(), which will return the RPC channel.
  • you can still view the UI by connecting to the headless, nested nvim via --remote-ui

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement feature request terminal built-in :terminal or :shell
Projects
None yet
Development

No branches or pull requests

3 participants