diff --git a/.config/nvim/lua/config/options.lua b/.config/nvim/lua/config/options.lua index 5fbaf95..0a41fb7 100644 --- a/.config/nvim/lua/config/options.lua +++ b/.config/nvim/lua/config/options.lua @@ -45,6 +45,21 @@ vim.opt.signcolumn = "yes" -- always show the signcolumn to minimize distraction -- vim.cmd(":autocmd InsertLeave * set nocul") -- Remove color upon existing insert mode -- vim.cmd("set guicursor=i:block") -- Always use block cursor. In some terminals and fonts (like iTerm), it can be hard to see the cursor when it changes to a line. --- Copy all yanked/deleted lines to the "+" buffer. Useful when you want to use --- the OS clipboard. -vim.cmd("set clipboard=unnamedplus") +-- Use osc52 as clipboard provider +local function paste() + return {vim.fn.split(vim.fn.getreg(''), '\n'), vim.fn.getregtype('')} +end +vim.g.clipboard = { + name = 'OSC 52', + copy = { + ['+'] = require('vim.ui.clipboard.osc52').copy('+'), + ['*'] = require('vim.ui.clipboard.osc52').copy('*'), + }, + paste = { + ['+'] = paste, + ['*'] = paste, + }, +} +-- To ALWAYS use the clipboard for ALL operations +-- (instead of interacting with the "+" and/or "*" registers explicitly): +vim.opt.clipboard = "unnamedplus" diff --git a/.config/nvim/lua/plugins/r.nvim.lua b/.config/nvim/lua/plugins/r.nvim.lua new file mode 100644 index 0000000..3f7d0e5 --- /dev/null +++ b/.config/nvim/lua/plugins/r.nvim.lua @@ -0,0 +1,43 @@ +return { + "R-nvim/R.nvim", + + -- Still in experimental mode. + -- enabled = false, + + lazy = false, + config = function() + local opts = { + + -- Disable highlighting of R in the terminal + hl_term = false, + + -- Use default pdf viewer (or none) + pdfviewer = "", + + -- This is intended to be used with tmux. Viewing a dataframe with + -- rv will save the dataframe to file, open a new tmux + -- pane, and run visidata on that file. Quitting visidata will close that + -- pane. + view_df = { + open_app = "tmux split-window -v vd", + }, + + -- Override some of the built-in commands to match historical commands in + -- these dotfiles. + hook = { + on_filetype = function() + vim.api.nvim_buf_set_keymap(0, "n", "gxx", "RDSendLine", {}) + vim.api.nvim_buf_set_keymap(0, "v", "gx", "RSendSelection", {}) + vim.api.nvim_buf_set_keymap(0, "n", "k", "RMakeHTML", {}) + vim.api.nvim_buf_set_keymap(0, "n", "cd", "RSendChunkRNextRChunk", {}) + end, + -- Optional notification of which nvimcom is being used + -- after_R_start = function() + -- require('r.send').cmd('paste("r.nvim plugin is using this nvimcom:", system.file(package="nvimcom"))') + -- end, + }, + R_args = { "--no-save" }, + } + require("r").setup(opts) + end, +} diff --git a/.config/nvim/lua/plugins/treesitter.lua b/.config/nvim/lua/plugins/treesitter.lua index ad84ed7..a63b7e5 100644 --- a/.config/nvim/lua/plugins/treesitter.lua +++ b/.config/nvim/lua/plugins/treesitter.lua @@ -5,6 +5,9 @@ return { version = false, build = ":TSUpdate", event = { "BufReadPost", "BufNewFile" }, + dependencies = { + "nvim-treesitter/nvim-treesitter-textobjects", + }, config = function() require("nvim-treesitter.configs").setup({ highlight = { @@ -12,13 +15,15 @@ return { }, indent = { enable = true, - -- Let vim-python-pep8-indent handle the python and snakemake indentation; - -- disable markdown indentation because it prevents bulleted lists from wrapping correctly with `gq`. + + -- Disable markdown indentation because it prevents bulleted lists + -- from wrapping correctly with `gq`. disable = { "markdown" }, }, -- -------------------------------------------------------------------- -- CONFIGURE ADDITIONAL PARSERS HERE - -- These will be attempted to be installed automatically, but you'll need a C compiler installed. + -- These will be attempted to be installed automatically, but you'll + -- need a C compiler installed. ensure_installed = { "bash", "css", @@ -29,13 +34,17 @@ return { "markdown", "markdown_inline", "python", - "vim", - "vimdoc", - "yaml", "r", + "rnoweb", "rst", "snakemake", + "vim", + "vimdoc", + "yaml", }, + + -- Starting from the current line, use Tab or Shift-Tab to increase or + -- decrease the selection depending on scope. incremental_selection = { enable = true, keymaps = { @@ -45,6 +54,35 @@ return { node_decremental = "", }, }, + + -- Support selecting objects based on parser. E.g., vaf to visually + -- select a function, or cip to change inside a parameter. More can be + -- added, see + -- https://github.com/nvim-treesitter/nvim-treesitter-textobjects + textobjects = { + select = { + enable = true, + lookahead = true, + keymaps = { + ["af"] = { query = "@function.outer", desc = "Select function (outer)" }, + ["if"] = { query = "@function.inner", desc = "Select function (inner)" }, + ["ap"] = { query = "@parameter.outer", desc = "Select parameter (outer)" }, + ["ip"] = { query = "@parameter.inner", desc = "Select parameter (inner)" }, + }, + + -- use the entire line V) or just characters (v (default)) when + -- selecting + selection_modes = { + ["@parameter.inner"] = "v", -- charwise + ["@parameter.outer"] = "v", -- charwise + ["@function.inner"] = "V", -- linewise + ["@function.outer"] = "V", -- linewise + ["@class.inner"] = "V", -- linewise + ["@class.outer"] = "V", -- linewise + ["@scope"] = "v", + }, + }, + }, }) vim.cmd("set foldmethod=expr") vim.cmd("set foldexpr=nvim_treesitter#foldexpr()") diff --git a/.tmux.conf b/.tmux.conf index 12f94eb..b906bd6 100644 --- a/.tmux.conf +++ b/.tmux.conf @@ -63,3 +63,6 @@ bind % split-window -h -c "#{pane_current_path}" unbind -T copy-mode-vi MouseDragEnd1Pane bind -T copy-mode-vi MouseDragEnd1Pane send -X stop-dragging-selection bind -T copy-mode-vi MouseDown1Pane select-pane \; send-keys -X clear-selection + +set-option -s set-clipboard on +set -g allow-passthrough on diff --git a/docs/images/iterm2_clipboard.png b/docs/images/iterm2_clipboard.png new file mode 100644 index 0000000..eb26240 Binary files /dev/null and b/docs/images/iterm2_clipboard.png differ diff --git a/docs/vim.rst b/docs/vim.rst index 6376c95..5bf546b 100644 --- a/docs/vim.rst +++ b/docs/vim.rst @@ -568,10 +568,19 @@ track of what has changed recently. - - fancy rendering of markdown files + * - :ref:`browsher` + - 2024-12-15 + - + - open corresponding github/gitlab page directly from your code + + * - :ref:`r.nvim` + - 2025-03-18 + - + - lots of features for working in R -Sometimes there are better plugins for a particular functionality. I've kept -the documentation, but noted when they've been deprecated here and in the -linked description. +Sometimes there are better plugins for a particular functionality, in which +case the old one will be deprecated. I've kept the documentation, but noted +when they've been deprecated here and in the linked description. .. list-table:: :header-rows: 1 @@ -1755,6 +1764,8 @@ I'm still figuring out when it's better to use this, fugitive, or gitsigns. See the homepage for details. .. list-table:: + :header-rows: 1 + :align: left * - command - description @@ -1787,6 +1798,8 @@ a way that the changes can be undone (in contrast to running ``black`` manually on the file, which overwrites it). .. list-table:: + :header-rows: 1 + :align: left * - command - description @@ -2051,6 +2064,8 @@ Notes on other plugins: The mapped commands below use :kbd:`o` ([o]bsidian) as a a prefix. .. list-table:: + :header-rows: 1 + :align: left * - command - description @@ -2114,6 +2129,8 @@ distracting when entering and exiting insert mode. However, this plugin can be useful when reviewing a long RMarkdown file to focus on the narrative text. .. list-table:: + :header-rows: 1 + :align: left * - command - description @@ -2141,6 +2158,8 @@ colors. .. list-table:: + :header-rows: 1 + :align: left * - command - description @@ -2175,6 +2194,8 @@ GitHub/GitLab instances. See the config file :file:`.config/nvim/lua/plugins/browsher.lua` for details. .. list-table:: + :header-rows: 1 + :align: left * - command - description @@ -2182,6 +2203,164 @@ GitHub/GitLab instances. See the config file * - ``Browsher`` - Store URL on OS clipboard +``r.nvim`` +~~~~~~~~~~ + +`r.nvim `__ provides *extensive* integration with R. + +.. versionadded:: 2025-03-18 + +.. details:: Config + + This can be found in :file:`.config/nvim/lua/plugins/r.nvim.lua`: + + .. literalinclude:: ../.config/nvim/lua/plugins/r.nvim.lua + :language: lua + +This is still in testing mode, so to try it out you'll need to comment out the +``enable = false`` line in the config. + +This plugin needs: + +- R available in the environment *before* opening an R or Rmd file +- nvim v0.10.4 or later +- gcc compilre to build the ``nvimcom`` package + +It also needs a one-time installation of the package ``nvimcom``, which +happends automatically the first time you open an R or Rmd file with this +plugin activated. This package is used to communicate between R and nvim. + +This gets tricky when using an R installation in a conda environment that will +be saved with ``conda env export`` for reproducibility. That's because we want +to avoid "contaminating" that R environment with this ``nvimcom`` package which +has nothing to do with the actual analysis. + +For this, we should use the ``R_LIBS_USER`` environment variable, which in turn +needs to be versioned for particular versions of R. This can be accomplished +with the following function that will set the ``R_LIBS_USER`` appropriately +depending on the particular version of R you happen to be using. + +.. note:: + + If you are intending to run ``install.packages()`` within a conda + environment to add analysis dependencies, then do not use this function + because it will put installed packages in your home directory, which will + not be reproducible for others. + + +.. code-block:: bash + + # Usage: Ropen + # (*.R, *.Rmd) + + function Ropen () { + R_VERSION=$(R --version | head -n1 | grep -Eo "[0-9]+\.[0-9]+") + export R_LIBS_USER="/home/$USER/R/$R_VERSION" + mkdir -p R_LIBS_USER + nvim $1 + } + + +.. details:: Notes on this function + + ``R_LIBS_USER`` can be specified with a ``%v`` as a placeholder for + major.minor version, which R will fill in. It also has a default value + *within* R, but not in bash. + + Our goal is to install ``nvimcom`` in the ``R_LIBS_USER`` directory so that + we are not adding in *interface* dependencies into *analysis* dependencies. + + R will only use ``R_LIBS_USER`` to install packages into if the directory + already exists -- which might not be the case, if this is the first time + we're running this version of R. + + We can't use the ``%v`` placeholder and create the directory outside of R, + because bash doesn't know how to fill in the ``%v``. Our options are to have + R interpret ``%v`` and make the directory:: + + Rscript -e "dir.create(Sys.getenv('R_LIBS_USER'), showWarnings=FALSE)" + + Or parse the output of ``R --version``:: + + R_VERSION=$(R --version | head -n1 | grep -Eo "[0-9]+\.[0-9]+") + + It appears that ``Rscript`` takes a little bit longer to start up than ``R + --version``, so I opted to go with the bash version. See ``help(.libPaths)`` + for more info. + +Interesting things that this plugin provides: + + +- run a command in R, copy the output, and insert into the current file + commented out. Perfect for things like ``df %>% head`` to document what + a dataframe looks like in your code. + +- help shows up in a panel in nvim instead of less + +- tab completion of objects in R terminal + +- tab completion of objects in nvim .R / .Rmd file + +- inspect an object -- for dataframes, this will save the object under the + cursor to a file, open a new tmux pane, open the file in visidata in that + pane. Quitting visidata closes the pane as well. This is equivalent to the + ``View()`` function in RStudio + +- an object browser. This is equivalent to the object browser panel in RStudio + +- capability to map arbitrary nvim commands to arbitrary R commands on the + identifier in the code. For example, you could map ``dim({object})`` to + ``do``, and then you could use ``do`` when your cursor is + over an object in .R or .Rmd to quickly check dimensions. + + +.. note:: + + This plugin is configured by default to use the ````, which is + ``\`` (backslash) by default. Local leader is intended to be used for + filetype-specific mappings (see ``:help maplocalleader``). These dotfiles + are not good about doing this, but the ``r.nvim`` plugin is, hence most of the + mappings using local leader. For consistency other mapped commands with + other plugins, I've remapped some commands to use leader, as indicated in + the table below. + +.. list-table:: + :header-rows: 1 + :align: left + + * - command + - description + + * - :kbd:`rf` + - Start R in a terminal to the right + + * - :kbd:`ro` + - Open the object browser + + * - :kbd:`rq` + - Quit R without saving workspace + + * - :kbd:`k` + - Render Rmd into HTML + + * - :kbd:`rv` + - View the dataframe or matrix under the cursor in visidata + + * - :kbd:`o` + - Send the line to R, capture the output, and insert it here as a comment + + * - :kbd:`cd` + - Send the current chunk to R and move to the next + + * - :kbd:`gx` + - Send the current selection to R + + * - :kbd:`gxx` + - Send the current line to R + + * - ``RMapsDesc`` + - List all mappings for this plugin (there are a lot!) + Colorschemes ------------ diff --git a/setup.sh b/setup.sh index a535154..94859e4 100755 --- a/setup.sh +++ b/setup.sh @@ -22,7 +22,7 @@ set -eo pipefail # Change tool versions here VISIDATA_VERSION=2.11 HUB_VERSION=2.14.2 -NVIM_VERSION=0.10.1 +NVIM_VERSION=0.10.4 RG_VERSION=13.0.0 BAT_VERSION=0.19.0 JQ_VERSION=1.6 @@ -498,15 +498,6 @@ elif [ $task == "--conda-env" ]; then elif [ $task == "--install-neovim" ]; then - # Too-old of a GLIBC on the system will not work with later nvim versions - if [[ $HOSTNAME == "helix.nih.gov" || $HOSTNAME == "biowulf.nih.gov" ]]; then - printf "\n${RED}Looks like you're on helix/biowulf. You should use the nvim installed on Biowulf " - printf "for compatibility with the system's glibc.\n\nTwo ways to do this: either add 'module load neovim/$NVIM_VERSION' " - printf "to your .extra file or .bashrc, or directly add the path shown from " - printf "'module show neovim/$NVIM_VERSION' to your PATH.${UNSET}\n\n" - exit 1 - fi - if [ -d ~/opt/neovim ]; then printf "${RED}nvim already appears to be installed at ~/opt/neovim. Please remove that dir first.${UNSET}\n" exit 1 @@ -523,10 +514,11 @@ elif [ $task == "--install-neovim" ]; then mkdir -p "$HOME/opt/bin" mv nvim-macos-*64 "$HOME/opt/neovim" else - download https://github.com/neovim/neovim/releases/download/v${NVIM_VERSION}/nvim-linux64.tar.gz nvim-linux64.tar.gz - tar -xzf nvim-linux64.tar.gz - mv nvim-linux64 "$HOME/opt/neovim" - rm nvim-linux64.tar.gz + # Use release built with older glibc + download https://github.com/neovim/neovim-releases/releases/download/v${NVIM_VERSION}/nvim-linux-x86_64.tar.gz nvim-linux-x86_64.tar.gz + tar -xzf nvim-linux-x86_64.tar.gz + mv nvim-linux-x86_64 "$HOME/opt/neovim" + rm nvim-linux-x86_64.tar.gz fi ln -sf ~/opt/neovim/bin/nvim ~/opt/bin/nvim printf "${YELLOW}- installed neovim to $HOME/opt/neovim${UNSET}\n"