• This repository has been archived on 31/May/2024
  • Stars
    star
    177
  • Rank 215,985 (Top 5 %)
  • Language
    Lua
  • License
    GNU General Publi...
  • Created over 1 year ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

First select, then edit. A helix/kakoune-like editing in neovim

Visual.nvim

N.B. This is still in a very experimental stage and mappings will suddenly change in the next few weeks.

Serendipity

noun, formal; the fact of finding interesting or valuable things by chance

visual2.mp4

What is this

In nvim, you do c3w. Ah no! It was wrong, let's retry: uc5w... wooops! Sorry, it is still wrong: uc6w!

In Kakoune (which inspired Helix), you do the opposite: 3w. First select 3 words, then you see you still need three words, so 3w. Then finally d for deleting.

In visual.nvim, this actually becomes 3wv3wd, with the v used for "refining" selections. If you do not need to adjust the selection, 3wd is all you need. The magic here is that visual.nvim puts you in a special mode named "serendipity" in which you can use some normal commands but also some visual commands. This allows you to have a preview of what your edit command will modify, so that you can occasionally change the selection by entering the visual mode.

First select, then edit. This should be the way.

If you have been tempted by Kakoune and Helix editors, this may be your new plugin!

Features

  • Selection first mode
  • New "serendipity" mode: discover motion errors by chance!
  • Surrounding commands (change, delete, add) that operate over selections
  • Repeat motions
  • Compatible with treesitter-textobjects

Usage

Just install it using your preferred package manager (Lazy recommended).

{ 
    '00sapo/visual.nvim',
    event = "VeryLazy", -- this is for making sure our keymaps are applied after the others: we call the previous mapppings, but other plugins/configs usually not!
}

Further configuration examples below. The mappings can be fine-tuned at your will as well, see Keymaps

Usage

Motion commands such as w, e, b, ge, f, t and their punctuation-aware alternatives W, E, B, gE, F, T behave the same as vim (or are supposed so), but also put you in "serendipity" mode.

Once you are in serendipity mode, you can modify text (c, x, i, a) as if you were in normal mode. d and y will work as in visual mode. With <A-,>, you can repeat the last motion selection, while with <A-.> you can repeat the last edit applied in insert mode from serendipity or visual mode.

Serendipity mode is built around the nvim's visual mode, so you can use all visual commands if they don't interfer with your config. From serendipity mode, you can enter visual mode with v, <S-v>, <C-v>. You can also switch between visual and serendipity mode with -. Moreover, d from normal mode will be the same as <S-v>, followed by serendipity enter -. From serendipity mode, <esc> will lead you to normal mode.

Note that motion commands in visual mode are different from normal mode. Serendipity mode emulates normal mode for motion commands!

Remember using o to move the cursor to the other end of the visual/serendipity selection when needed.

Selection of text objects is possible as in usual nvim with i<text object> and a<text object> in visual mode, thus becoming va and vi from normal mode, similarly to Helix's mi and ma. From serendipity mode, since i and a are mapped to append and insert, they become I and A, (or still vi and va). If you are a treesitter-textobjects user, simply set the treesitter_textobjects option to true for using them from serendipity mode.

Visual.nvim also offers surrounding commands with sd, sc, and sa (delete, change, add).

Finally, in serendipity mode, pressing hjkl will extend the selection. You can move to normal mode with <A-h>, <A-j>, etc.

Limitations

  • Visual.nvim still does not support macros due to limitations in the lua API (see issue). For this reason, pressing q will disable Visual.nvim mappings. You should re-enable them manually with :VisualEnable when you have finished recording/running the macros.

  • Dot-repeat are supported via A-. and A-,. Moreover, usual . works from normal mode. This may create confusion in the workflow.

  • The way movements work is still being fine-tuned. Help wanted!

Example config

Configuration with some change to commands in order to make them compatible (needed by NvChad):

{
  '00sapo/visual.nvim',
  config = function()
    require('visual').setup({
    commands = {
      move_up_then_normal = { amend = true },
      move_down_then_normal = { amend = true },
      move_right_then_normal = { amend = true },
      move_left_then_normal = { amend = true },
    },
  } )
  end,
  event = "VeryLazy"
}

Configuration for color scheme (changing the serendipity color, see here for a list of (n)vim colors):

{
  '00sapo/visual.nvim',
  config = function()
    require('visual').setup({
    serendipity = {
        highlight = "guibg=LightCyan guifg=none"
    }
  } )
  end,
  event = "VeryLazy"
}

Example with Treesitter text objects

{
  "00sapo/visual.nvim",
  opts = { treesitter_textobjects = true },
  dependencies = { "nvim-treesitter", "nvim-treesitter-textobjects" }, -- this is needed so that visual.nvim is loaded *afterwards* Treesitter
  event = "VeryLazy"
},
{
  "nvim-treesitter/nvim-treesitter",
  --etc.
}

Example with custom mappings (more info below)

{
  '00sapo/visual.nvim',
  opts = {
    mappings = {
      save = "<C-s>",
      docs = "K",
      to_normal = "jk"
    },
    commands = {
      save = {
        pre_amend = { "<sde>", "<esc>", "<cmd>w<cr>" }, -- <sde> is for exiting serendipity, also <sdi> for init it and <sdt> for toggling
        post_amend = {},
        modes = { "sd", "v" }, -- "sd", "v", or "n"
        amend = false, -- if true, also run the original keymap
        countable = false, -- can this mapping be counted (e.g. 3w, 3e, etc.)
      },
      docs = {
        pre_amend = {
          "<sde><esc>",
          vim.lsp.buf.hover
        },
        post_amend = {},
        modes = { "sd" },
        amend = false, -- can't use true, because keys feeded to nvim are the mode seen by `K` is visual even after <esc>. Same issue as macros.
        countable = false,
      },
      to_normal = { -- only `amend` and `countable` keys are needed and only if true
        {"<sde><esc>"}, {}, {"sd", "n"}
      }
    },
  }
  event = "VeryLazy"
}

Keymaps

The plugin is highly customizable. It maps commands to keymaps, and you can define new commands or edit the existing ones. The following is the default set-up. Read the comments to understand how to modify it.

Feel free to suggest new default keybindings in the issues!

See the full default options with documentation in the comments.

Testing

  • curl https://raw.githubusercontent.com/00sapo/visual.nvim/main/test/init.lua -o /tmp/visual.nvim-test.lua
  • nvim -u /tmp/visual.nvim-test.lua <file>

Developing

  • Use nvim -u test/init.lua test/init.lua for testing
  • Use Vdbg(...) from anywhere to debug lua objects
  • Use <A-d>u to show the log of debugged objects and <A-d>c to clean the log