R-nvim / R.nvim

Neovim plugin to edit R files
GNU General Public License v3.0
159 stars 18 forks source link

Using an ir kernel as R_app #249

Open benlubas opened 1 day ago

benlubas commented 1 day ago

Does this sound possible? I've fiddled around a little with it, and run into issues, but I don't really understand the internals of this plugin too well, so I figured I'd ask.

The motivation is to get R.nvim features to work with an existing jupyter kernel (the kernel is running on the same machine as nvim btw).

I'm setting R_app = "/path/to/bash_script.sh"

#!/usr/bin/env bash

jupyter console --existing $(cat /tmp/kernel-id)

where the tmp file is created by something else.

When I do this, I can start the plugin/create a tmux split with \rf and the split opens, the jupyter console starts and works as expected (ie. it has access to variables I've evaluated in the jupyter kernel). But R.nvim gets stuck at vim.g.R_Nvim_status = 6 so whenever I attempt to send code to the terminal I get R is not ready yet.

I've tried to run require("nvimcom") manually in the jupyter console b/c I suspect autoload would not work since the process is already running, but this doesn't change anything. The require succeeds, however, so it's able to find the package.

When I run Sys.getenv(RNVIM_ID) in the console I see a value, same for all the other environment variables.

Any suggestions would be appreciated!

jalvesaq commented 1 day ago

Please, run these commands in an R session started by R.nvim:

Sys.getenv("R_DEFAULT_PACKAGES")
Sys.getenv()[grep("^RNVIM_", names(Sys.getenv()))]

The nvimcom library is automatically loaded when "nvimcom" is included in R_DEFAULT_PACKAGES. Then, all the nine environment variables beginning with "RNVIM_" must be properly set to get full communication between nvim and R. The value of vim.g.R_Nvim_status goes from 6 to 7 when R sends Neovim a TCP message with information on the running nvimcom. This happens when the TCP client is started.

The first lines of .onLoad() in nvimcomR/nvimcom.R are:

    if (Sys.getenv("RNVIM_TMPDIR") == "")
        return(invisible(NULL))

That is, the TCP client is started only if the environment variable RNVIM_TMPDIR is set.

That said, I have zero experience with Jupyter and it seems you that already knew everything I explained. But I hope that the explanation might be useful to someone wanting to help you.

benlubas commented 1 day ago

Thanks for the swift response!

Sys.getenv("R_DEFAULT_PACKAGES") does include nvimcom, here's the full list: "datasets,utils,grDevices,graphics,stats,methods,nvimcom"

the nine environment variables beginning with "RNVIM_"

There are nine of them? This could be an issue. Sys.getenv()[grep("^RNVIM_", names(Sys.getenv()))] only shows the 5 that are set here: https://github.com/R-nvim/R.nvim/blob/4cf60ea7e18f7fbeac5709f6a898a91c6924cc32/lua/r/external_term.lua#L141

RNVIM_COMPLDIR=/home/me/.cache/R.nvim\ 0
RNVIM_ID=12...
RNVIM_PORT=10101
RNVIM_SECRET=186...
RNVIM_TMPDIR=/dev/shm/R.nvim-me\ 0

grepping around I see a few other environment variable names that fit. Which do you expect to see?

When I run without the custom script, I see an additional RNVIM_RSLV_CB is set. I wonder if I could just set that one too, let me check. Just going to send this now b/c I've stopped myself from sending it like 4 times to dig into something first.

benlubas commented 1 day ago

Ah, when running with a normal R console. I also notice that the compldir and tmpdir don't have \ 0 at the end

benlubas commented 1 day ago

I'm facepalming massively right now. The env vars I see have been persisting in the kernel this whole time, I think I remember manually setting them as the first thing I tried. Even when you restart an R kernel, the env vars persist (something I just learned).

So the secret and ID will have been wrong this whole time.

Starting the kernel with FOO=BAR jupyter console --existing <id> does not transfer those variables to the kernel. So I suspect I will have to send the code to the kernel to set them (I can do this in the background on start by just modifying the plugin source, I'll try to make it clean, but I doubt that it will be).

jalvesaq commented 1 day ago

The nine variables:

RNVIM_TMPDIR            Local temporary directory
RNVIM_COMPLDIR          Local cache directory
RNVIM_ID                Random number
RNVIM_SECRET            Random number
RNVIM_PORT              TCP port where the server is waiting for connections
RNVIM_REMOTE_COMPLDIR   Cache directory if running R in a remote machine
RNVIM_REMOTE_TMPDIR     Temporary directory if running R in a remote machine
RNVIM_COMPL_CB          Callback function for completion of object names
RNVIM_RSLV_CB           Callback function for resolving completion
jalvesaq commented 1 day ago

This \ 0 isn't normal. I don't know where it came from.

jalvesaq commented 1 day ago

Note that RNVIM_ID and RNVIM_SECRET are generated by R.nvim (lua/r/config.lua) and you can't guess what their values will be:

    vim.env.RNVIM_ID = vim.fn.rand(vim.fn.srand())
    vim.env.RNVIM_SECRET = vim.fn.rand()
benlubas commented 1 day ago

Thank you. Unfortunately, even with a script to set all of the environment variables correctly before calling require("nvimcom") I still get the same error message.

I'm out of ideas for now

jalvesaq commented 1 day ago

You should not set any variable. They must all be set by R.nvim. For example, if I create the following shell script (~/bin/fake_R):

#/bin/sh

env > /tmp/Rnvim_env

and put in my R.nvim config:

R_app = '~/bin/fake_R',

Then, after <LocalLeader>rf, I can see that all nine environment variables are inserted in the /tmp/Rnvim_env file.

Perhaps, Jupyter restricts what variables are read from the calling environment.

benlubas commented 1 day ago

Perhaps, Jupyter restricts what variables are read from the calling environment.

Yeah it certainly seems to be the case.

I attempted to work around it by setting each variable by sending the corresponding Sys.setenv commands from a neovim user command. I had to change the way R.nvim opened a tmux split so that the pane ID could be communicated without the server connection, and then was able to call send_cmd_to_external_term.

In theory this should have the same result (ie. all of the environment variables are set to the same values they'd otherwise have), and I was able to see them all set when I ran the grep command, but unfortunately this doesn't seem to have been enough