Code Monkey home page Code Monkey logo

flash.nvim's Introduction

⚡flash.nvim

flash.nvim lets you navigate your code with search labels, enhanced character motions, and Treesitter integration.

Search Integration Standalone Jump
f, t, F, T Treesitter

✨ Features

  • 🔍 Search Integration: integrate flash.nvim with your regular search using / or ?. Labels appear next to the matches, allowing you to quickly jump to any location. Labels are guaranteed not to exist as a continuation of the search pattern.
  • ⌨️ type as many characters as you want before using a jump label.
  • Enhanced f, t, F, T motions
  • 🌳 Treesitter Integration: all parents of the Treesitter node under your cursor are highlighted with a label for quick selection of a specific Treesitter node.
  • 🎯 Jump Mode: a standalone jumping mode similar to search
  • 🔎 Search Modes: exact, search (regex), and fuzzy search modes
  • 🪟 Multi Window jumping
  • 🌐 Remote Actions: perform motions in remote locations
  • dot-repeatable jumps
  • 📡 highly extensible: check the examples

📋 Requirements

  • Neovim >= 0.8.0 (needs to be built with LuaJIT)

📦 Installation

Install the plugin with your preferred package manager:

lazy.nvim:

{
  "folke/flash.nvim",
  event = "VeryLazy",
  ---@type Flash.Config
  opts = {},
  -- stylua: ignore
  keys = {
    { "s", mode = { "n", "x", "o" }, function() require("flash").jump() end, desc = "Flash" },
    { "S", mode = { "n", "x", "o" }, function() require("flash").treesitter() end, desc = "Flash Treesitter" },
    { "r", mode = "o", function() require("flash").remote() end, desc = "Remote Flash" },
    { "R", mode = { "o", "x" }, function() require("flash").treesitter_search() end, desc = "Treesitter Search" },
    { "<c-s>", mode = { "c" }, function() require("flash").toggle() end, desc = "Toggle Flash Search" },
  },
}

⚠️ When creating the keymaps manually either use a lua function like function() require("flash").jump() end as the rhs, or a string like <cmd>lua require("flash").jump()<cr>. DO NOT use :lua, since that will break dot-repeat

⚙️ Configuration

flash.nvim is highly configurable. Please refer to the default settings below.

Default Settings
{
  -- labels = "abcdefghijklmnopqrstuvwxyz",
  labels = "asdfghjklqwertyuiopzxcvbnm",
  search = {
    -- search/jump in all windows
    multi_window = true,
    -- search direction
    forward = true,
    -- when `false`, find only matches in the given direction
    wrap = true,
    ---@type Flash.Pattern.Mode
    -- Each mode will take ignorecase and smartcase into account.
    -- * exact: exact match
    -- * search: regular search
    -- * fuzzy: fuzzy search
    -- * fun(str): custom function that returns a pattern
    --   For example, to only match at the beginning of a word:
    --   mode = function(str)
    --     return "\\<" .. str
    --   end,
    mode = "exact",
    -- behave like `incsearch`
    incremental = false,
    -- Excluded filetypes and custom window filters
    ---@type (string|fun(win:window))[]
    exclude = {
      "notify",
      "cmp_menu",
      "noice",
      "flash_prompt",
      function(win)
        -- exclude non-focusable windows
        return not vim.api.nvim_win_get_config(win).focusable
      end,
    },
    -- Optional trigger character that needs to be typed before
    -- a jump label can be used. It's NOT recommended to set this,
    -- unless you know what you're doing
    trigger = "",
    -- max pattern length. If the pattern length is equal to this
    -- labels will no longer be skipped. When it exceeds this length
    -- it will either end in a jump or terminate the search
    max_length = false, ---@type number|false
  },
  jump = {
    -- save location in the jumplist
    jumplist = true,
    -- jump position
    pos = "start", ---@type "start" | "end" | "range"
    -- add pattern to search history
    history = false,
    -- add pattern to search register
    register = false,
    -- clear highlight after jump
    nohlsearch = false,
    -- automatically jump when there is only one match
    autojump = false,
    -- You can force inclusive/exclusive jumps by setting the
    -- `inclusive` option. By default it will be automatically
    -- set based on the mode.
    inclusive = nil, ---@type boolean?
    -- jump position offset. Not used for range jumps.
    -- 0: default
    -- 1: when pos == "end" and pos < current position
    offset = nil, ---@type number
  },
  label = {
    -- allow uppercase labels
    uppercase = true,
    -- add any labels with the correct case here, that you want to exclude
    exclude = "",
    -- add a label for the first match in the current window.
    -- you can always jump to the first match with `<CR>`
    current = true,
    -- show the label after the match
    after = true, ---@type boolean|number[]
    -- show the label before the match
    before = false, ---@type boolean|number[]
    -- position of the label extmark
    style = "overlay", ---@type "eol" | "overlay" | "right_align" | "inline"
    -- flash tries to re-use labels that were already assigned to a position,
    -- when typing more characters. By default only lower-case labels are re-used.
    reuse = "lowercase", ---@type "lowercase" | "all" | "none"
    -- for the current window, label targets closer to the cursor first
    distance = true,
    -- minimum pattern length to show labels
    -- Ignored for custom labelers.
    min_pattern_length = 0,
    -- Enable this to use rainbow colors to highlight labels
    -- Can be useful for visualizing Treesitter ranges.
    rainbow = {
      enabled = false,
      -- number between 1 and 9
      shade = 5,
    },
    -- With `format`, you can change how the label is rendered.
    -- Should return a list of `[text, highlight]` tuples.
    ---@class Flash.Format
    ---@field state Flash.State
    ---@field match Flash.Match
    ---@field hl_group string
    ---@field after boolean
    ---@type fun(opts:Flash.Format): string[][]
    format = function(opts)
      return { { opts.match.label, opts.hl_group } }
    end,
  },
  highlight = {
    -- show a backdrop with hl FlashBackdrop
    backdrop = true,
    -- Highlight the search matches
    matches = true,
    -- extmark priority
    priority = 5000,
    groups = {
      match = "FlashMatch",
      current = "FlashCurrent",
      backdrop = "FlashBackdrop",
      label = "FlashLabel",
    },
  },
  -- action to perform when picking a label.
  -- defaults to the jumping logic depending on the mode.
  ---@type fun(match:Flash.Match, state:Flash.State)|nil
  action = nil,
  -- initial pattern to use when opening flash
  pattern = "",
  -- When `true`, flash will try to continue the last search
  continue = false,
  -- Set config to a function to dynamically change the config
  config = nil, ---@type fun(opts:Flash.Config)|nil
  -- You can override the default options for a specific mode.
  -- Use it with `require("flash").jump({mode = "forward"})`
  ---@type table<string, Flash.Config>
  modes = {
    -- options used when flash is activated through
    -- a regular search with `/` or `?`
    search = {
      -- when `true`, flash will be activated during regular search by default.
      -- You can always toggle when searching with `require("flash").toggle()`
      enabled = false,
      highlight = { backdrop = false },
      jump = { history = true, register = true, nohlsearch = true },
      search = {
        -- `forward` will be automatically set to the search direction
        -- `mode` is always set to `search`
        -- `incremental` is set to `true` when `incsearch` is enabled
      },
    },
    -- options used when flash is activated through
    -- `f`, `F`, `t`, `T`, `;` and `,` motions
    char = {
      enabled = true,
      -- dynamic configuration for ftFT motions
      config = function(opts)
        -- autohide flash when in operator-pending mode
        opts.autohide = opts.autohide or (vim.fn.mode(true):find("no") and vim.v.operator == "y")

        -- disable jump labels when not enabled, when using a count,
        -- or when recording/executing registers
        opts.jump_labels = opts.jump_labels
          and vim.v.count == 0
          and vim.fn.reg_executing() == ""
          and vim.fn.reg_recording() == ""

        -- Show jump labels only in operator-pending mode
        -- opts.jump_labels = vim.v.count == 0 and vim.fn.mode(true):find("o")
      end,
      -- hide after jump when not using jump labels
      autohide = false,
      -- show jump labels
      jump_labels = false,
      -- set to `false` to use the current line only
      multi_line = true,
      -- When using jump labels, don't use these keys
      -- This allows using those keys directly after the motion
      label = { exclude = "hjkliardc" },
      -- by default all keymaps are enabled, but you can disable some of them,
      -- by removing them from the list.
      -- If you rather use another key, you can map them
      -- to something else, e.g., { [";"] = "L", [","] = H }
      keys = { "f", "F", "t", "T", ";", "," },
      ---@alias Flash.CharActions table<string, "next" | "prev" | "right" | "left">
      -- The direction for `prev` and `next` is determined by the motion.
      -- `left` and `right` are always left and right.
      char_actions = function(motion)
        return {
          [";"] = "next", -- set to `right` to always go right
          [","] = "prev", -- set to `left` to always go left
          -- clever-f style
          [motion:lower()] = "next",
          [motion:upper()] = "prev",
          -- jump2d style: same case goes next, opposite case goes prev
          -- [motion] = "next",
          -- [motion:match("%l") and motion:upper() or motion:lower()] = "prev",
        }
      end,
      search = { wrap = false },
      highlight = { backdrop = true },
      jump = {
        register = false,
        -- when using jump labels, set to 'true' to automatically jump
        -- or execute a motion when there is only one match
        autojump = false,
      },
    },
    -- options used for treesitter selections
    -- `require("flash").treesitter()`
    treesitter = {
      labels = "abcdefghijklmnopqrstuvwxyz",
      jump = { pos = "range", autojump = true },
      search = { incremental = false },
      label = { before = true, after = true, style = "inline" },
      highlight = {
        backdrop = false,
        matches = false,
      },
    },
    treesitter_search = {
      jump = { pos = "range" },
      search = { multi_window = true, wrap = true, incremental = false },
      remote_op = { restore = true },
      label = { before = true, after = true, style = "inline" },
    },
    -- options used for remote flash
    remote = {
      remote_op = { restore = true, motion = true },
    },
  },
  -- options for the floating window that shows the prompt,
  -- for regular jumps
  -- `require("flash").prompt()` is always available to get the prompt text
  prompt = {
    enabled = true,
    prefix = { { "", "FlashPromptIcon" } },
    win_config = {
      relative = "editor",
      width = 1, -- when <=1 it's a percentage of the editor width
      height = 1,
      row = -1, -- when negative it's an offset from the bottom
      col = 0, -- when negative it's an offset from the right
      zindex = 1000,
    },
  },
  -- options for remote operator pending mode
  remote_op = {
    -- restore window views and cursor position
    -- after doing a remote operation
    restore = false,
    -- For `jump.pos = "range"`, this setting is ignored.
    -- `true`: always enter a new motion when doing a remote operation
    -- `false`: use the window's cursor position and jump target
    -- `nil`: act as `true` for remote windows, `false` for the current window
    motion = false,
  },
}

🚀 Usage

  • Treesitter: require("flash").treesitter(opts?) opens flash in Treesitter mode

    • use a jump label, or use ; and , to increase/decrease the selection
  • regular search: search as you normally do, but enhanced with jump labels. You need to set opts.modes.search.enabled = true, or toggle it with require("flash").toggle()

  • f, t, F, T motions:

    • After typing f{char} or F{char}, you can repeat the motion with f or go to the previous match with F to undo a jump.
    • Similarly, after typing t{char} or T{char}, you can repeat the motion with t or go to the previous match with T.
    • You can also go to the next match with ; or previous match with ,
    • Any highlights clear automatically when moving, changing buffers, or pressing <esc>.
  • toggle Search: require("flash").toggle(boolean?)

    • toggles flash on or off while using regular search
  • Treesitter Search: require("flash").treesitter_search(opts?) opens flash in Treesitter Search mode

    • combination of Treesitter and Search modes
    • do something like yR
    • you can now start typing a search pattern.
    • arround your matches, all the surrounding Treesitter nodes will be labeled.
    • select a label to perform the operator on the new selection
  • remote: require("flash").remote(opts?) opens flash in remote mode

    • equivalent to:

      require("flash").jump({
        remote_op = {
          restore = true,
          motion = true,
        },
      })
    • this is only useful in operator pending mode.

    • For example, press yr to start yanking and open flash

      • select a label to set the cursor position
      • perform any motion, like iw or even start flash Treesitter with S
      • the yank will be performed on the new selection
      • you'll be back in the original window / position
    • You can also configure the remote_op options by default, so that ys, behaves like yr for remote operations

      require("flash").jump({
        remote_op = {
          restore = true,
          motion = nil,
        },
      })
  • jump: require("flash").jump(opts?) opens flash with the given options

    • type any number of characters before typing a jump label
  • VS Code: some functionality is changed/disabled when running flash in VS Code:

    • prompt is disabled. You can use require("flash").prompt() to get the prompt text and integrate it into the statusline.
    • highlights are set to different defaults that will actually work in VS Code

📡 API

The options for require("flash").jump(opts?), are the same as those in the config section, but can additionally have the following fields:

  • matcher: a custom function that generates matches for a given window
  • labeler: a custom function to label matches

You can also add labels in the matcher function and then set labeler to an empty function labeler = function() end

Type Definitions
type FlashMatcher = (win: number, state: FlashState) => FlashMatch[];
type FlashLabeler = (matches: FlashMatch[], state: FlashState) => void;

interface FlashMatch {
  win: number;
  pos: [number, number]; // (1,0)-indexed
  end_pos: [number, number]; // (1,0)-indexed
  label?: string | false; // set to false to never show a label for this match
  highlight?: boolean; // override opts.highlight.matches for this match
}

// Check the code for the full definition
// of Flash.State at `lua/flash/state.lua`
type FlashState = {};

💡 Examples

Forward search only
require("flash").jump({
  search = { forward = true, wrap = false, multi_window = false },
})
Backward search only
require("flash").jump({
  search = { forward = false, wrap = false, multi_window = false },
})
Show diagnostics at target, without changing cursor position
require("flash").jump({
  action = function(match, state)
    vim.api.nvim_win_call(match.win, function()
      vim.api.nvim_win_set_cursor(match.win, match.pos)
      vim.diagnostic.open_float()
    end)
    state:restore()
  end,
})

-- More advanced example that also highlights diagnostics:
require("flash").jump({
  matcher = function(win)
    ---@param diag Diagnostic
    return vim.tbl_map(function(diag)
      return {
        pos = { diag.lnum + 1, diag.col },
        end_pos = { diag.end_lnum + 1, diag.end_col - 1 },
      }
    end, vim.diagnostic.get(vim.api.nvim_win_get_buf(win)))
  end,
  action = function(match, state)
    vim.api.nvim_win_call(match.win, function()
      vim.api.nvim_win_set_cursor(match.win, match.pos)
      vim.diagnostic.open_float()
    end)
    state:restore()
  end,
})
Match beginning of words only
require("flash").jump({
  search = {
    mode = function(str)
      return "\\<" .. str
    end,
  },
})
Initialize flash with the word under the cursor
require("flash").jump({
  pattern = vim.fn.expand("<cword>"),
})
Jump to a line
require("flash").jump({
  search = { mode = "search", max_length = 0 },
  label = { after = { 0, 0 } },
  pattern = "^"
})
Select any word
require("flash").jump({
  pattern = ".", -- initialize pattern with any char
  search = {
    mode = function(pattern)
      -- remove leading dot
      if pattern:sub(1, 1) == "." then
        pattern = pattern:sub(2)
      end
      -- return word pattern and proper skip pattern
      return ([[\<%s\w*\>]]):format(pattern), ([[\<%s]]):format(pattern)
    end,
  },
  -- select the range
  jump = { pos = "range" },
})
f, t, F, T with labels

Use the options below:

{
  modes = {
    char = {
      jump_labels = true
    }
  }
}
Telescope integration

This will allow you to use s in normal mode and <c-s> in insert mode, to jump to a label in Telescope results.

{
    "nvim-telescope/telescope.nvim",
    optional = true,
    opts = function(_, opts)
      local function flash(prompt_bufnr)
        require("flash").jump({
          pattern = "^",
          label = { after = { 0, 0 } },
          search = {
            mode = "search",
            exclude = {
              function(win)
                return vim.bo[vim.api.nvim_win_get_buf(win)].filetype ~= "TelescopeResults"
              end,
            },
          },
          action = function(match)
            local picker = require("telescope.actions.state").get_current_picker(prompt_bufnr)
            picker:set_selection(match.pos[1] - 1)
          end,
        })
      end
      opts.defaults = vim.tbl_deep_extend("force", opts.defaults or {}, {
        mappings = {
          n = { s = flash },
          i = { ["<c-s>"] = flash },
        },
      })
    end,
  }
Continue last search
require("flash").jump({continue = true})
2-char jump, similar to mini.jump2d or HopWord (hop.nvim)
local Flash = require("flash")

---@param opts Flash.Format
local function format(opts)
  -- always show first and second label
  return {
    { opts.match.label1, "FlashMatch" },
    { opts.match.label2, "FlashLabel" },
  }
end

Flash.jump({
  search = { mode = "search" },
  label = { after = false, before = { 0, 0 }, uppercase = false, format = format },
  pattern = [[\<]],
  action = function(match, state)
    state:hide()
    Flash.jump({
      search = { max_length = 0 },
      highlight = { matches = false },
      label = { format = format },
      matcher = function(win)
        -- limit matches to the current label
        return vim.tbl_filter(function(m)
          return m.label == match.label and m.win == win
        end, state.results)
      end,
      labeler = function(matches)
        for _, m in ipairs(matches) do
          m.label = m.label2 -- use the second label
        end
      end,
    })
  end,
  labeler = function(matches, state)
    local labels = state:labels()
    for m, match in ipairs(matches) do
      match.label1 = labels[math.floor((m - 1) / #labels) + 1]
      match.label2 = labels[(m - 1) % #labels + 1]
      match.label = match.label1
    end
  end,
})

🌈 Highlights

Group Default Description
FlashBackdrop Comment backdrop
FlashMatch Search search matches
FlashCurrent IncSearch current match
FlashLabel Substitute jump label
FlashPrompt MsgArea prompt
FlashPromptIcon Special prompt icon
FlashCursor Cursor cursor

📦 Alternatives

flash.nvim's People

Contributors

atusy avatar eyalz800 avatar folke avatar github-actions[bot] avatar indianboy42 avatar j-hui avatar kevintraver avatar mrbeardad avatar myypo avatar singlexyz avatar wvjgsuhp avatar xiyaowong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

flash.nvim's Issues

feature: 'do not update labels' setting

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

Yep. When I specify search.max_length property (2, for example), labels are shown after the first character I type and then they are changed after the second one. It's inconvenient, isn't it? 🤔

Describe the solution you'd like

So, I would suggest to add a property static_labels or something like that. It would mean that labels shouldn't be changed when results are narrowing.

By the way, there's a property highlight.reuse and instead of adding a new one (static_labels), maybe it's better to add a possible none value for the reuse enum?

Describe alternatives you've considered

The alternative I've considered is to set highlight.label.min_pattern_length equal to 2. It kinda solves the problem and even has benefits (labels are shown right after 2 characters and don't cover the next character I wanna type), but I see the labels after typing the full length (2).

Additional context

No response

bug: treesitter selection + `config.search.incremental = true` causes the initial selection to be the entire buffer

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.10.0-dev-541+g96b94f8d7

Operating system/version

Pop!_OS 22.04 LTS

Describe the bug

When config.search.incremental is set (globally or within the treesitter mode) and I start flash.treesitter with the window view scrolled so that the first line of the buffer is not visible. The window viewport jumps to the top of the buffer and, sometimes, the whole buffer is preselected. I can still hit one of the other labels (that are may not even be visible anymore) to do the selection. I believe the whole buffer is preselected if scrolling to the top causes all of the other ranges/labels to not be visible anymore

Removing config.search.incremental = true or adding config.modes.treesitter.search.incremental = false makes this stop happening (the viewport is stable)

Steps To Reproduce

  1. With config.search.incremental = true, scroll down so the first line is no longer visible and start treesitter selection yS
  2. The window viewport is scrolled to the top and potentially the initial selection is not the smallest range but the whole buffer.

Expected Behavior

Shouldn't scroll unnecessarily

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
	vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
	vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
	"folke/tokyonight.nvim",
	{
		"folke/flash.nvim",
		opts = {
			search = {
				incremental = true,
			},
			modes = {
				treesitter = { search = { incremental = true } },
			},
		},
		keys = {
			{
				"s",
				mode = { "n", "x", "o" },
				function()
					-- default options: exact mode, multi window, all directions, with a backdrop
					require("flash").jump()
				end,
			},
			{
				"S",
				mode = { "o", "x" },
				function()
					require("flash").treesitter()
				end,
			},
		},
	},
	-- add any other plugins here
}
require("lazy").setup(plugins, {
	root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here































local a = {
	"folke/tokyonight.nvim",
	{
		"folke/flash.nvim",
		opts = {
			modes = {
				treesitter = { labels = "fdsajkluioprewqmvczx" },
			},
		},
		keys = {
			{
				"s",
				mode = { "n", "x", "o" },
				function()
					-- default options: exact mode, multi window, all directions, with a backdrop
					require("flash").jump()
				end,
			},
			{
				"S",
				mode = { "o", "x" },
				function()
					require("flash").treesitter()
				end,
			},
		},
	},
}

bug: (NFA regexp) Misplaced *

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.10.0-dev-597+gaa362a2af-Homebrew

Operating system/version

macOS 13.4.0 Ventura

Describe the bug

I found out by accident (by mistyping an actual search 😆) that searching the character * generates the following error:

CmdlineChanged Autocommands for "*": Vim(append):Error executing lua callback: .../.local/share/nvim/lazy/flash.nvim/lua/flash/labeler.lua:174: Error executing lua: Vim:E866: (NFA regexp) Misplaced *
stack traceback:
	[C]: in function 'searchpos'
	.../.local/share/nvim/lazy/flash.nvim/lua/flash/labeler.lua:183: in function <.../.local/share/nvim/lazy/flash.nvim/lua/flash/labeler.lua:174>
	[C]: in function 'nvim_win_call'
	.../.local/share/nvim/lazy/flash.nvim/lua/flash/labeler.lua:174: in function 'skip'
	.../.local/share/nvim/lazy/flash.nvim/lua/flash/labeler.lua:58: in function 'reset'
	.../.local/share/nvim/lazy/flash.nvim/lua/flash/labeler.lua:24: in function 'labeler'
	...ro/.local/share/nvim/lazy/flash.nvim/lua/flash/state.lua:269: in function '_update'
	...ro/.local/share/nvim/lazy/flash.nvim/lua/flash/state.lua:222: in function 'update'
	.../share/nvim/lazy/flash.nvim/lua/flash/plugins/search.lua:56: in function 'update'
	.../share/nvim/lazy/flash.nvim/lua/flash/plugins/search.lua:86: in function <.../share/nvim/lazy/flash.nvim/lua/flash/plugins/search.lua:85>
stack traceback:
	[C]: in function 'nvim_win_call'
	.../.local/share/nvim/lazy/flash.nvim/lua/flash/labeler.lua:174: in function 'skip'
	.../.local/share/nvim/lazy/flash.nvim/lua/flash/labeler.lua:58: in function 'reset'
	.../.local/share/nvim/lazy/flash.nvim/lua/flash/labeler.lua:24: in function 'labeler'
	...ro/.local/share/nvim/lazy/flash.nvim/lua/flash/state.lua:269: in function '_update'
	...ro/.local/share/nvim/lazy/flash.nvim/lua/flash/state.lua:222: in function 'update'
	.../share/nvim/lazy/flash.nvim/lua/flash/plugins/search.lua:56: in function 'update'
	.../share/nvim/lazy/flash.nvim/lua/flash/plugins/search.lua:86: in function <.../share/nvim/lazy/flash.nvim/lua/flash/plugins/search.lua:85>
E315: ml_get: Invalid lnum: 245

By quickly glancing and the stacktrace probably this is due to incomplete escaping of the regex here?

Notice that by correctly escaping the * character during search (say \*) the error does not occur, and nor does it against any other special regex wildcard (I tried a few and all seems to work well); as such, this is probably such a minimal case that it may not be even worth looking into it (however I thought I would flag it anyway).

Steps To Reproduce

  1. search for *
  2. the error occurs

Expected Behavior

If I am not mistaken searching for * brings you to the character even if not escaped in standard vim, so I would expect the same behaviour here too (or am I wrong)?

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  { "folke/flash.nvim", opts = {} },
  -- add any other plugins here
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

feature: support remapping ; and ,

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

I personally nnoremap ; : so that I don't have to hold shift to activate the command line. Instead, I like to map ; and , to H and L.

However, flash.nvim does not allow me to do this cleanly (i.e., without worrying about recursive mappings).

Describe the solution you'd like

I'd like to be able to remap the ; and , keys.

Describe alternatives you've considered

I took a look at plugins/char.lua and it seems like the ; and , keys (as well as f/F/t/T) are hard-coded in there.

With sneak.vim, I can do something like:

  map H <Plug>Sneak_;
  map L <Plug>Sneak_,

Additional context

No response

bug: the behavior is weird when search last pattern with `//` or `??`

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.10.0-dev-575+ge59cf3b3a9

Operating system/version

archlinux 6.3.9-arch1-1

Describe the bug

the behavior is weird when search last pattern with // or ??
as the picture shown, it highlight both slash and include(the last pattern)
图片

Steps To Reproduce

  1. search any word
  2. type // to search last word

Expected Behavior

only highlight last pattern with label

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  { "folke/flash.nvim", opts = {} },
  -- add any other plugins here
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

feature: string converting function

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

I would like to configure "string conversion function" for input .
For example, I want to insert a plugin that enumerates Japanese candidates from alphabet between input and search results

(ex. migemo https://github.com/lambdalisue/kensaku.vim)

Describe the solution you'd like

create an option to configure function

Describe alternatives you've considered

hmm

Additional context

No response

feature: Multiple patterns

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

Flash may allow for a more structured navigation through the code, which will be easier to define and more enjoyable to write than treesitter queries.

Defining multiple patterns such as {"local", "function", "for", ...} can facilitate faster movement through the code. In my opinion, it is generally much easier to choose a letter on the screen than to learn thousands of shortcuts for every occasion, like go to next class, and every other [... etc.

Describe the solution you'd like

I would like pattern accept a string[] so that we can define the most important patterns to jump to for language using a keyboard shortcut. An even better option would be to have the ability to configure by language or filetype, but this can be worked around with autocmd.

Describe alternatives you've considered

An alternative is to write it every time by hand like now. Another option may be to finally learn treesitter queries :)

Additional context

No response

feature: add support for jumping/selecting treesitter child and siblings nodes

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

No problem

Describe the solution you'd like

Add support for jumping to or selecting treesitter child or sibling nodes. At the time of writing, only parent nodes are supported.

Describe alternatives you've considered

My current alternative is doing a normal jump into the treesitter node I'm aiming for and using a text object to select it.

Additional context

Thanks for making this plugin, it's great!

Relevant Neovim APIs:

https://github.com/neovim/neovim/blob/cd6458123fb4859e47ffcd144ebbddf389a09610/runtime/lua/vim/treesitter/_meta.lua#L22-L25

A plugin that supports jumping between treesitter sibling nodes for inspiration:
https://github.com/ziontee113/syntax-tree-surfer

feature: Eyeliner integration

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

The character search does not work with eyeliner. One or the other plugin breaks (it seems depending on the order that they are loaded? - i.e I tried uninstalling and reinstalling each and got different results depending on the order).

Describe the solution you'd like

I think having the initial highlighting similar to eyeliner would make this mode fantastic. Most of the time I want to go to a specific word when using f/t and eyeliner does a great job of this. The continued search that this plugin offers could also be fairly useful so if they could play nicely together that would be amazing (either by integrating this feature into flash or figuring out some way of making them work together).

Describe alternatives you've considered

I guess the alternative would be to disable this feature in flash or uninstall eyeliner. These options work as expected afaik.

Additional context

No response

bug: when I scroll to the bottom with G, using flash scrolls to the first search result in the file.

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

0.9.1

Operating system/version

MacOS 13.2

Describe the bug

When I use "/" to search for a pattern, lets say "nvim", everything works as expected unless I see the last line of the file.

Steps To Reproduce

G
/<pattern that appears on the lines that are above the screen\>

Expected Behavior

I see search pattens on the screen without it scrolling to the top of the file.

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  { "folke/flash.nvim", opts = {} },
  -- add any other plugins here
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

feature: Handle searches with no match

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

The FR is concerned with using flash via the search /.

Commonly, search is used for two scenarios:

  1. You search for all occurrences of a string, e.g. you search for "foo" in the entire buffer. In this case you type /foo, followed by one of flash's hints or by <CR>nn…
  2. You already know the exact location you want to go to and use / as quickest method of getting there. You search for a unique term and instinctively type /foobarbaz<CR> knowing you will get to your desired location.

Now the issue is, for scenario 2 I sometimes misremember what the unique string was, e.g. it was actually "foobangbaz", not "foobarbaz". Normally, this is not a big deal, since I get the "no search match found" message, and repeat the search with a shorter search term: /<up><BS><BS>….

However, with flash's modification of the search, misremembering a string can cause some trouble: After typing fooba, no further matches are found, so the next character r is interpreted as a hint character, and jumps you to a location in your buffer with fooba and leaves the command line. The remaining keystrokes baz<CR> are then interpreted as normal mode commands, resulting in jump word backwards, append 'z' and a line break.

By the time I notice that "foobarbaz" actually does not occur in my buffer, I have effectively already jumped to random location and made some unintended changes. In the regular search, when typing /foobarbaz<CR> with no match in the buffer, I'd just get a "no match found" message without jumping to a different location or modifying the buffer.

All in all, the combination of using search for jumping to specific locations, typing quickly, and misremembering the string results in somewhat undesired results when using flash. To prevent that, I kinda have to force myself to slow down when searching, to prevent that I unintentionally type a hint character.

Describe the solution you'd like

One solution could be to introduce a new option for having to press the hint character twice before jumping, i.e. requiring rr to jump instead of a single r. This would make unintended jumps much less likely, wouldn't slow down flash too much, and still require only one letter r as hint character.

But yeah, I could not really think of a good solution for this problem that does not introduce any drawbacks, maybe you or someone else has a better idea? 😕

Describe alternatives you've considered

The only alternatives I can think of is disabling flash for / search or forcing myself to type much more slowly when searching for a string.

The first would be a bummer, since I quickly grew to love flash for /, the latter would be kinda annoying and defeating the purpose of jumping around more quickly.

Additional context

No response

feature: more jump pos options

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

I want to use jump to simulate bidirectional f-and-t-like behaviors with labels.

Describe the solution you'd like

For t-like behavior, I need a jump pos that is one character before the start pos.

For backward jumps, I need reversed start and end.

So here are the jump pos options needed:

  • far: end for forward jumps, start for backward jumps.
  • near: start for forward jumps, end for backward jumps.
  • until (maybe there's a better name?): start-1 for forward jumps, end+1 for backward jumps.
  • till-start (maybe there's a better name?): start-1 for forward jumps, start+1 for backward jumps.

Describe alternatives you've considered

I can continue using my fork of hop.nvim.

Additional context

No response

feature: Predefined pattern selection

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

I would like to match and jump to treesitter query matches or regex patterns and select the entire match. Flash has the jump.pos = 'range' option which makes immediate selection trivial. The problem is that if I use a pattern in my flash.jump( { search = { mode = 'search' }, pattern = [[ \v\w+ ]], jump = { pos = 'range' } } ) it correctly highlights all the matches but only adds labels to a few matches near the cursor and expects more input to filter the remaining results. Now I can type the characters that follow the desired match to filter and receive a label but upon jump the additional characters are also included in the range selection.

Initial State

image

Start Jump

image

Target string folke and input /

image

Input a to select

image
I wanted to select just folke but selected folke/ since the / became part of the pattern.

Describe the solution you'd like

I would like for all possible matches to be given a label without additional input/filtering. Additionally I would also like to be able to match treesitter queries so that I can search for more complicated patterns.

Describe alternatives you've considered

I've tried using a function as search mode which ignores the string and just returns the initial pattern but it results in the same few matches being labelled.

Additional context

This may be beyond the scope of flash since it tries to have single character labels.
In a scenario where there are more matches than labels those would be inaccessible. This could be solved by having a special character like <space> in leap.nvim to select the next range of matches.

bug: labels are continuation of the search pattern

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

0.9.1

Operating system/version

MacOS 14.0

Describe the bug

It's said:

Labels are guaranteed not to exist as a continuation of the search pattern.

, but I have situations where they are a continuation.

Steps To Reproduce

WezTerm 2023-06-27 at 02-22
WezTerm 2023-06-27 at 02-22

Expected Behavior

I expected it not to be a continuation of the search pattern. I added my plugin options so that you can see when it doesn't work.

I think the issue happens when I combine search.max_length and highlight.label.min_pattern_length properties.

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  {
    "folke/flash.nvim",
    opts = {
      labels = 'setnriaogkfuplwyqbjdhvmcxz',
      search = { max_length = 2 },
      highlight = {
        label = {
          min_pattern_length = 2
        }
      }
    }
  },
  -- add any other plugins here
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

feature: resume/cycle previous search (fF/tT or jump) with `;` `,`

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

Sometimes, it may be hard to go back to previous search state, and cycle through matches or labels. dot-repeat may help, but only until some text-changing operation is performed.

Describe the solution you'd like

;/, remember the last used motion (fF/tT or jump), and will recover that mode and its state once invoked, with same labels. Pressing again will jump through matches forth or back, respectively.

Describe alternatives you've considered

jump previous state could also be recovered with <CR> without any entry (e.g. s<CR>), like leap.
Currently <CR> without a pattern cancel jump mode, same as <esc>.

Additional context

Recovering previous jump state is tricky. Dot-repeat only works if you haven't made a text-changing operation after last jump.

bug: Fuzzy search ranking

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.9.1

Operating system/version

MAC OS 13.4 Beta (22F5027f)

Describe the bug

Fuzzy search ranking is not perfect:

Screenshot 2023-06-27 at 11 04 20

In this screenshot, I did "s + space" and my keybinding is mapped to:

  {
      "s",
      mode = { "n", "x", "o" },
      function()
          -- default options: multi window, all directions, with a backdrop
          require("flash").jump()
      end,
      desc = "Flash",
  }

Steps To Reproduce

See screenshot

Expected Behavior

s.normal_mode["<C-space"] is found. instead of that should be ranked first.
I believe the fuzzy is "too much fuzzy" or maybe, if there is collision between two matches, we shoud choose the "more exact"

feature: inclue text objects in ("flash").treesitter()

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

Not a problem

Describe the solution you'd like

Support selecting text object in("flash").treesitter()

Describe alternatives you've considered

Now the ("flash").treesitter() only select TS nodes and works like https://github.com/mfussenegger/nvim-treehopper.
Can we let the candidates also include user defined text objects like https://github.com/gcmt/wildfire.vim?

For example, user can set a list of text objects, say ["i'", 'i"', "i)", "i]", "i}", "ip", "it"], then flash include them when activate ("flash").treesitter() (skip overlap)

Additional context

No response

bug: Label are not shown in some case

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.9.1

Operating system/version

MAC OS 13.4 Beta (22F5027f)

Describe the bug

No label shown in some case (see steps)

Steps To Reproduce

Take that buffer as an example

GET http://localhost:7001/Profil/GetKycInfo
Command :curl -sSL --compressed -X 'GET' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIwMDYzZWYyYy0zNWU5LTRlMTUtOWE1Yi01ZjNiNGNlYzljOWYiLCJhY2NvdW50X3Rva2VuIjoiVDFKTUMiLCJyb2xlcyI6IltdIiwic2Vzc2lvbklkIjoiYTA1YmU0N2MtNmI0MC00YjczLTllOWQtYjJiNmVkZmY4OTUwIiwiYmlydGhkYXRlIjoiMTk5NC0wMi0xMVQwMDowMDowMCIsImVtYWlsIjoidGl0b3Vhbi5jcmVhY2hAZ21haWwuY29tIiwiZ2l2ZW5fbmFtZSI6IlRpdG91YW4iLCJmYW1pbHlfbmFtZSI6IkNSRUFDSCIsIm5iZiI6MTY4Nzg3MjcyMCwiZXhwIjoxNjkwNDY0NzIwLCJpYXQiOjE2ODc4NzI3MjAsImlzcyI6Imh0dHBzOi8vYXBpLmhvdXNlYmFzZS5iemgiLCJhdWQiOiJob3VzZWJhc2UifQ.dSHlmqPw9RmSkLIlancCVArH4Ic00lwGO0beO2Wql7I' --data-raw 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIwMDYzZWYyYy0zNWU5LTRlMTUtOWE1Yi01ZjNiNGNlYzljOWYiLCJhY2NvdW50X3Rva2VuIjoiVDFKTUMiLCJyb2xlcyI6IltdIiwic2Vzc2lvbklkIjoiYTA1YmU0N2MtNmI0MC00YjczLTllOWQtYjJiNmVkZmY4OTUwIiwiYmlydGhkYXRlIjoiMTk5NC0wMi0xMVQwMDowMDowMCIsImVtYWlsIjoidGl0b3Vhbi5jcmVhY2hAZ21haWwuY29tIiwiZ2l2ZW5fbmFtZSI6IlRpdG91YW4iLCJmYW1pbHlfbmFtZSI6IkNSRUFDSCIsIm5iZiI6MTY4Nzg3MjcyMCwiZXhwIjoxNjkwNDY0NzIwLCJpYXQiOjE2ODc4NzI3MjAsImlzcyI6Imh0dHBzOi8vYXBpLmhvdXNlYmFzZS5iemgiLCJhdWQiOiJob3VzZWJhc2UifQ.dSHlmqPw9RmSkLIlancCVArH4Ic00lwGO0beO2Wql7I' 'http://localhost:7001/Profil/GetKycInfo'
#+END
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Tue, 27 Jun 2023 13:45:39 GMT
Server: Kestrel
Content-Encoding: gzip
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-MiniProfiler-Ids: ["5824757f-8b7d-4f70-8a88-554802809c02"]

#+RESPONSE
{
  "error": null,
  "data": {
    "userId": "635b269a-7585-44db-829d-616c6d16170a",
    "status": "CLEAR",
    "addressCreated": true,
    "clientCreated": true,
    "checks": [
      {
        "type": "document_check",
        "status": null
      },
      {
        "type": "extensive_screening_check",
        "status": "CLEAR"
      },
      {
        "type": "identity_check",
        "status": "CLEAR"
      }
    ]
  },
  "correlationId": "0HMRN2J5JLPB9:00000001"
}
#+END

And that config:

         "folke/flash.nvim",
        event = "VeryLazy",
        ---@type Flash.Config
        opts = {
            search = {
                mode = "fuzzy"
            }
        },
        keys = {
            {
                "s",
                mode = { "n", "x", "o" },
                function()
                    -- default options: exact mode, multi window, all directions, with a backdrop
                    require("flash").jump()
                end,
                desc = "Flash",
            },
            {
                "S",
                mode = { "n", "o", "x" },
                function()
                    require("flash").treesitter()
                end,
                desc = "Flash Treesitter",
            },
            {
                "r",
                mode = "o",
                function()
                    require("flash").remote()
                end,
                desc = "Remote Flash",
            },
        },

The labels when I search for "clear" (s + clear) are not shown.

I believe this is because a very long string appears in the windows (jwt token)

Expected Behavior

Label should show up

Repro

No response

feature: f,F,T,t - with labels - make first label same as typed in motion letter

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

When using f, t, F, T with labels (from exaples), I thought it would be cool
if first label would be same as motion. For example when using:
dty - it will label all y - with various letters - but it could mark first occurrence of y with "y" label.
This way you if u know the searched letter is first in line - u could just do:
dtyy - auto jump to first y.

Describe the solution you'd like

some option to make first label same as motion character

Describe alternatives you've considered

I do not think any other plugin has this feature.

Additional context

Maybe it could be used for other jumps?
Lets say we search for word 'example'
we type '/exaa' - it would jump to first match of word 'exa' .

bug: Doesn't work in "vscode-neovim" extension of vs code

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

0.9.1

Operating system/version

MacOS 13.4.1

Describe the bug

-Doesn't work in "vscode-neovim" extension(https://github.com/vscode-neovim/vscode-neovim) environment of vs code

Steps To Reproduce

  1. install vs code
  2. install vscode-neovim extension
  3. Install neovim 0.8.0 or greater
  4. install flash.nvim and setup
  5. run vs code
  6. enter / to search

Expected Behavior

The label should appear when you search. Label and highlight do not work properly

bug: wrong labe positioning on double-width chars

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.10.0-dev-585+g2e055e49a

Operating system/version

Manjaro Linux

Describe the bug

When patteren has double-width chars, label is placed on a next character of the matches.

Below is an example to search from あxあxあxあxあxあx.
You can see labels are placed on x

image

Steps To Reproduce

  1. Prepare buffer
あxあxあxあxあxあx
あxあxあxあxあxあx
  1. Do flash
require("flash").jump({pattern = "あ", search = { wrap = false }})

Expected Behavior

labels should be placed on

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  { "folke/flash.nvim", opts = {} },
  -- add any other plugins here
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

bug: Flash remains active after `{action}{motion — 't'/'T', 'f/F'}` is completed

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

0.9.1

Operating system/version

MacOS 12.2.1

Describe the bug

When using {action}{motion — 't'/'T', 'f/F'} — eg. yank until opening parentheses yt(, flash.nvim remains active after motion is completed.

Steps To Reproduce

  1. Open new buffer and paste:
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
  1. Go to first character
  2. Execute {action}{motion}: yt,
  3. "Lorem ipsum dolor sit amet" is yanked to register
  4. 🐛 flash.nvim remains "active" like when it is invoked with 't'/'T', 'f/F' alone

Expected Behavior

When using {action}{motion — 't'/'T', 'f/F'}, flash.nvim is not active after motion is completed.

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  { "folke/flash.nvim", opts = {} },
  -- add any other plugins here
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here
vim.cmd.set("clipboard=unnamedplus")

feature: Support keymaps (Ctrl+^).

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

When I write a blogpost in my native language, I use my native keyboard layout (utilizing keymaps). If I use search (/) with Flash, lables are provided in English, and I can't type them (as my layout is not English at the moment).

f and F don't work as well.

Describe the solution you'd like

lables are provided in the language that is currently set.
f and F also work (both of them work without Flash with other layouts).

Describe alternatives you've considered

🤷

Additional context

Here is the code I use to switch between layouts.

set keymap=russian-jcukenmac
set iminsert=0
set imsearch=0

function! s:SetLangCmd(langName)
    let n = (a:langName == "en_US") ? 0 : 1
    execute "set iminsert=" . n . " imsearch=" . n
    execute "lang " . a:langName . ".UTF-8"
endfunction

function! s:ToggleKeyboard()
    call <SID>SetLangCmd(&iminsert == 0 ? "ru_RU" : "en_US")
endfunction

xnoremap <C-6> :call <SID>ToggleKeyboard()<CR>
nnoremap <C-6> :call <SID>ToggleKeyboard()<CR>

feature: always label the 3rd character in jump mode

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

if I want to jump to 'mappings', I would press 's' then 'ma'.
Right after pressing 'm', flash puts a label 'f' on the 2nd character:
image
Right after pressing 'a', it puts a label 'f' on the 3rd character:
image

My problem is that this causes the label character to move around when I'm typing, and this causes some cognitive load which slows me down.

Describe the solution you'd like

Always put the label on the 3rd character, like leap.nvim

Describe alternatives you've considered

.

Additional context

No response

feature: clever-f like repeat motion with the same

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

Both flit.nvim and clever-f.vim allow repeating the f/F/tT motion with the same key instead of ; and , usage.

Describe the solution you'd like

Allow remapping keys that go to the next match or repeat the motion character.

No response

feature: jump to first match

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

It would be great if I don't have to press enter to jump to the first match.

Describe the solution you'd like

This would be a feature similar to auto_jump when there is a unique match, but this time it would jump to the first match, and the user can stop at that point.

Describe alternatives you've considered

.

Additional context

No response

feature: Better coloring as `eyelilner.nvim`

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

no, but kinda of for autism

Describe the solution you'd like

use eyeliner IDEA of making things POP more , by adding RAINBOW 🌈 colors
having Plain colors isn't that good and its boring :(

Describe alternatives you've considered

no

Additional context

thx for the plugin tho

bug: opts.modes table being ignored

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.10.0-dev-541+g96b94f8d7

Operating system/version

Pop!_OS 22.04 LTS

Describe the bug

Any custom options that I add in opts.mode.<mode> are not overriding the default options. Additionally, the docs seem to say you can define custom modes that are used if we use jump{mode = "<mode>"}, which doesn't work either.

It seems the line in question is here:
https://github.com/folke/flash.nvim/blob/de34c832af2498c6954e34d3c08cf143f92f3d6b/lua/flash/config.lua#LL136C31-L136C31

Should this be options.modes[opts.mode]?

Steps To Reproduce

  1. try to override the treesitter labels treesitter = { labels = "zyx" },
  2. Invoke vS and see that the default labels are used
  3. try to create a custom mode fuzzy = { search = { mode = "fuzzy" } }, and keymapping require("flash").jump({ mode = "fuzzy" })
  4. Invoke sab and see that exact matching is used instead of fuzzy

Expected Behavior

Being able to override the options and create modes

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
	vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
	vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
	"folke/tokyonight.nvim",
	{
		"folke/flash.nvim",
		opts = { modes = { treesitter = { labels = "zyx" }, fuzzy = { search = { mode = "fuzzy" } } } },
		keys = {
			{
				"s",
				mode = { "n", "x", "o" },
				function()
					-- default options: exact mode, multi window, all directions, with a backdrop
					require("flash").jump({ mode = "fuzzy" })
				end,
			},
			{
				"S",
				mode = { "o", "x" },
				function()
					require("flash").treesitter()
				end,
			},
		},
	},
	-- add any other plugins here
}
require("lazy").setup(plugins, {
	root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

bug: Dot-repeat blocks standard usage

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

v0.9.1

Operating system/version

kubuntu

Describe the bug

Flash.nvim dot-repeat blocks standard dot-repeat usage (see reproducer).

Steps To Reproduce

  1. Let's have a file with simple content:
"one.lua"
"two.lua"
"three.lua"
  1. you are at line 1 and column 1
  2. start / search: :/\.lua<cr>
  3. you are on first line on the character .
  4. remove extension .lua by pressing dt"
  5. press n to get to next search result on line 2
  6. press . to repeat extension remove - ups, it is not removed as expected.

Expected Behavior

In the step 7, the extension .lua on the line 2 should be removed - just as in the case without this plugin.

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  { "folke/flash.nvim", opts = {} },
  -- add any other plugins here
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

bug: Label Conflict with Multi-Window Same Buffer

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

0.9.0

Operating system/version

Ubuntu 22.10

Describe the bug

When the same buffer is open in two windows, with overlapping visible text in both windows, flash.nvim generates the same label in both windows upon invoking a jump command. This creates a situation where it's not possible to select a specific window to jump to. It's possible this is an unintended consequence of the current design when dealing with this particular use case. If I am missing a configuration somewhere or if this is the intended behavior, I apologize.

Thank you for your work on flash.nvim. It's a fantastic plugin, and even in its early stages, it's already the best I have used.

Steps To Reproduce

  1. Open the same buffer in two separate windows.
  2. Ensure some portion of the visible text is the same in both windows.
  3. Invoke a jump command.

Expected Behavior

The labels generated for jumps should be unique to each window, even when the same buffer is open in two windows. This should allow a user to select a specific window to jump to.

Repro

No response

feature: Disallow capital labels

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

Love this! Though I find it a little cumbersome to have to type capital letters. Would it be possible to disallow capitals from the label list?

For example, if you have the labels set up as:
labels = "abcdefghijklmnopqrstuvwxyz"

You will get labels such as A or B show up when there are lots of matches, and I would like to only allow a or b.

In the event that there are more than 26 matches, I would prefer to have to be more specific with my search, rather than use capitals.

Describe the solution you'd like

Could an option like this be added?

restrict_case: 'lowercase' -- options: 'lowercase' | 'uppercase' | false

Describe alternatives you've considered

You could also make the option a simple boolean, since I doubt anyone would want uppercase only:

lowercase_only: true

Or alternatively, you could do something like this to allow all alphas:
labels = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

Or this to only allow lowercase:
labels = "abcdefghijklmnopqrstuvwxyz"

Or indeed this to only allow uppercase:
labels = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

Additional context

No response

bug: flash.treesitter preselects "a" label even if the user has defined custom labels

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.10.0-dev-541+g96b94f8d7

Operating system/version

Pop!_OS 22.04 LTS

Describe the bug

This line basically assumes that a is the first label:

https://github.com/folke/flash.nvim/blob/455ba61cd0e48b9e3a28e9e1fa1a3364d57e7538/lua/flash/plugins/treesitter.lua#LL66C30-L66C31

Steps To Reproduce

  1. config.modes.treesitter.labels = "fdsajkl"
  2. vS and see the labels and selection

Expected Behavior

The inner most treesitter node should be preselected (now labelled by f). Instead the node labelled a is selected.

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
	vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
	vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
	"folke/tokyonight.nvim",
	{
		"folke/flash.nvim",
		opts = {
			modes = {
				treesitter = { labels = "zayx" },
			},
		},
		keys = {
			{
				"S",
				mode = { "o", "x" },
				function()
					require("flash").treesitter()
				end,
			},
		},
	},
	-- add any other plugins here
}
require("lazy").setup(plugins, {
	root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

feature: exclusive operator

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

When doing directional jumps in an operator pending mode, like this:

require("flash").jump {
  search = { forward = true, wrap = false, multi_window = false },
}

You sometimes want to exclude the target from the operation, similar to operations like dtw

Describe the solution you'd like

An option to make the jump behave like an exclusive operator.

Describe alternatives you've considered

Currently, I don't think there's an option that can simulate this behavior.

Additional context

No response

feature: Uppercase-only labels and possibly double-character labels

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

Is it possible to provide uppercase-only labels that are activated by lowercase keys on the keyboard? I find lowercase labels are harder to read as they often blend in with none label characters in the buffer.

Describe the solution you'd like

Hop solves this problem by allowing users to display labels in uppercase only. When uppercase labels run out, Hop then shows double-character uppercase labels.

Even though the labels are displayed in uppercase they're activated using lowercase keys on the keyboard. No shift key is needed.

In addition, Hop provides highlight colors for each character in a label, be it single or double, to allow even easier and quicker identification and separation.

Describe alternatives you've considered

Currently, I modify highlight colors to make labels pop and stand out a little more. However, I still have to spend an extra moment or so verifying labels are not just characters in the buffer. This is a problem I never had with Hop.

Additional context

See the screenshot below for HopWord in action.

hop_example

bug: Node ends in column 0 throws an error for flash.treesitter()

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.10.0-dev-546+g3bf887f6e

Operating system/version

Ubuntu 22.04 lts

Describe the bug

When using flash.treesitter(), if the node selected ends in column 0 (i.e it ends in a newline character, I think), the function fails with the following error:

E5108: Error executing lua: ...ons/.local/share/nvim/lazy/flash.nvim/lua/flash/jump.lua:37: Column value outside range
stack traceback:
        [C]: in function 'nvim_win_set_cursor'
        ...ons/.local/share/nvim/lazy/flash.nvim/lua/flash/jump.lua:37: in function 'jump'
        ...ns/.local/share/nvim/lazy/flash.nvim/lua/flash/state.lua:112: in function 'jump'
        ...re/nvim/lazy/flash.nvim/lua/flash/plugins/treesitter.lua:93: in function <...re/nvim/lazy/flash.nvim/lua/flash/plugins/treesitter.lua:58>

Steps To Reproduce

  1. use the repro.lua below
  2. Wait for tree-sitter install & close Lazy
  3. type sb to select the paragraph node

Expected Behavior

The node should be selected without throwing an error

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  'folke/tokyonight.nvim',
  { 'folke/flash.nvim', opts = {}, keys = { { 's', function() require 'flash'.treesitter() end } } },
  {
    'nvim-treesitter/nvim-treesitter',
    config = function()
      require 'nvim-treesitter.parsers'.get_parser_configs().org = {
        install_info = {
          url = 'https://github.com/milisims/tree-sitter-org',
          branch = 'flatten-expr',
          files = { 'src/parser.c', 'src/scanner.c' },
        },
        filetype = 'org',
      }

      require 'nvim-treesitter.configs'.setup { ensure_installed = 'org' }
    end,
  },

  -- add any other plugins here
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

vim.api.nvim_buf_call(1, function() vim.cmd.setfiletype('org') end)
vim.api.nvim_buf_set_lines(1, 0, -1, false, {'foo', '', 'bar'})

bug: treesitter_search does not select the last character if selection is "exclusive"

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

0.9.1

Operating system/version

MacOS

Describe the bug

When using require("flash").treesitter_search() with set selection=exclusive the last character of the treesitter search is not selected.

Steps To Reproduce

  1. set selection=exclusive
  2. require("flash").treesitter_search()
  3. Select a node
  4. Observe that the last character is not selected

Expected Behavior

Respect the behaviour of set selection=exclusive.

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  { "folke/flash.nvim", opts = {} },
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
vim.opt.selection = "exclusive"

bug: better handling of folds

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

currently matches inside folds are labeled

Describe the solution you'd like

need to think this through :)

Describe alternatives you've considered

not really

Additional context

No response

bug: Adds the typed pattern rather than the search string to the search register & history

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.10.0-dev-541+g96b94f8d7

Operating system/version

Pop!_OS 22.04 LTS

Describe the bug

I'm not sure if this is a bug or a misunderstand + feature request in some sense. When flash is configured to add to the search register and history, what is added is actually what the user types, not the actual search string that is used (which is different in the case of exact and even moreso in fuzzy mode)

It would seem the use case of the option is to make it easily repeatable. If the search string were added to the search register than n, N should just work afaict. But as it is it doesn't

I think this should be state.pattern.search?

-- add the real search pattern to the history

Steps To Reproduce

  1. set opts.jump.register = true and opts.search.mode = "fuzzy"
  2. Use the jump (srg...)
  3. Check the search register with "/p
  4. Try repeating the search with "n"

Expected Behavior

I would expect the search register to be filled with the augmented search string that makes it a fuzzy search.
It would seem the use case of the option is to make it easily repeatable. If the search string were added to the search register than n, N should just work afaict. But as it is i'm not sure how to easily repeat fuzzy search.

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
	vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
	vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
	"folke/tokyonight.nvim",
	{
		"folke/flash.nvim",
		opts = {
			search = {
				mode = "fuzzy",
			},
			jump = {
				register = true,
				history = true,
			},
		},
		keys = {
			{
				"s",
				mode = { "n", "x", "o" },
				function()
					-- default options: exact mode, multi window, all directions, with a backdrop
					require("flash").jump()
				end,
			},
		},
	},
	-- add any other plugins here
}
require("lazy").setup(plugins, {
	root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

bug: treesitter_search with NvimTree causes catastrophic failure

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

v0.9.1

Operating system/version

macOS 13.4.1

Describe the bug

I tried the new treesitter_search by pasting the config section from the docs.

            {
                "R",
                mode = { "o", "x" },
                function()
                    require("flash").treesitter_search()
                end,
                desc = "Flash Treesitter Search",
            },

After invoking the mode, if NvimTree is open, any keystroke throws an error:

E5108: Error executing lua: ...0.9.1/share/nvim/runtime/lua/vim/treesitter/language.lua:94: no parser for 'NvimTree' language, see :help treesitter-parsers

At this point, every keystroke is an error and the only way to continue is to kill the editor. It happens only if NvimTree is open. Minimal repro.lua included below.

Steps To Reproduce

  1. Add the config section and restart nvim.
  2. Open NvimTree (:NvimTreeToggle), then focus back on the editor window.
  3. Do vR or yR, etc. The flash mode is entered.
  4. Type any character.

Expected Behavior

Behold the wonder of treesitter_search

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
     {
        'folke/flash.nvim',
        config = function()
            require('flash').setup {}
        end,
        keys = {
            {
                "R",
                mode = { "o", "x" },
                function()
                    require("flash").treesitter_search()
                end,
                desc = "Flash Treesitter Search",
            },
        },
    },
    {
        'nvim-tree/nvim-tree.lua',
        config = true,
    },
}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

feature: Allow configuring optional search separator

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

Currently when jumping you usually have a target in sight that you are typing for. However, when searching for a word, you may not know if that word is there within a long file.

For example, if I am searching for the word stationary in this current scenario, and the word is not in the file:
flash-example
I will essentially end up moving to the station with the a label and then replace the character with ry.

Describe the solution you'd like

I would like to be able to specify a 1 char separator before triggering the "jump" to the label. This is essentially the feature "separator" from https://github.com/woosaaahh/sj.nvim.

So if I specify

...
  separator = ";",
...

Then in the same scenario:
flash-example
I would need to press ;a to go to the station with the a label, and entering stationary would not jump to it.

This basically makes for a slightly more deterministic behavior when searching words in a long file, and you don't know if the word is there (prevents accidental jumping).

Default behavior could be simply empty separator:

...
  separator = "",
...

which would act as it does right now.

Describe alternatives you've considered

Not quite sure which alternative could be possible, I could probably keep using sj.nvim for the search part.

Additional context

No response

bug: `<C-f>` keymap conflicts with `f`

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

0.9.1

Operating system/version

Arch Linux 6.3.9-arch1-1

Describe the bug

<C-f> is currently used by karb94/neoscroll.nvim to scroll forward but f conflicts with it yet it's only mapped to just f. Thanks.

Steps To Reproduce

  1. add karb94/neoscroll.nvim
  2. use the default configs
  3. reload and try scrolling through a long file with <C-f>

Expected Behavior

f to still work as it does but should not be triggered by <C-f>

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
  vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
  "folke/tokyonight.nvim",
  { "folke/flash.nvim", opts = {} },
  -- add any other plugins here
	{
		"karb94/neoscroll.nvim",
		event = "VeryLazy",
		config = function()
			local ok, neoscroll = pcall(require, "neoscroll")

			if not ok then
				return
			end

			neoscroll.setup({})
		end,
	},

}
require("lazy").setup(plugins, {
  root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

feature: Only show the labels after `n` characters

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

Sometimes when searching (with /) I either mistype or am mistaken and the thing im searching for doesn't exist. My cursor ends up jumping to a random location, or worse still because I was still typing in a search pattern some random edit happens.

Describe the solution you'd like

I think one way to reduce mistakes is to have a config option where labels are not shown and you cant jump until n characters typed. Then the workflow for searching would be /abc with the first few characters I am searching for and then pausing to see if the thing I am searching for exists and then I can continue the search pattern or hit a jump key.

Describe alternatives you've considered

As it is, this is kind of forcing me to slow down while using /. Atleast with the minimum characters I can bang out those, and while typing that probably the buffer has already moved around and been highlighted and labelled so I wouldn't actually have to slow down very much.

Additional context

No response

feature: multi-character labels

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

When using max_length = 1 and there are many matches, it seems impossible to jump to the farthest ones.

Describe the solution you'd like

Use multi-character labels when single-character labels are not enough.

Describe alternatives you've considered

Don't use max_length = 1 and type more characters for far matches.

Additional context

No response

feature: Custom modes inheriting from other custom modes

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

I like to define my custom action jumps using custom modes, so everything is in the config table, and the keymaps are just .jump({mode = "diagnostics"}), or something like that. There is a lot of repetitiveness here, the search and jump configs are the same across a lot of these (mainly 2 kinds of jumping, either fuzzy, or exact with max_length = 2).

Describe the solution you'd like

It would be nice if config.modes.diagnostics.mode = "fuzzy" would mean that diagnostics mode inherits from fuzzy mode.

Describe alternatives you've considered

Just copy-pasting, or using local variables and vim.tbl_deep_extend myself. The latter approach breaks the nice almost declarative looking configuration with lazy.nvims opts key

Additional context

No response

bug: regular search won't update label in other window when the pattern matchs nothing in current window

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

0.9.1

Operating system/version

MacOS 13.2.1

Describe the bug

In regular search mode, if the pattern matches nothing in current window, then it won't show the correct labels in others windows.

Steps To Reproduce

image image

Expected Behavior

Labels will be shown in other windows correctly even the pattern match nothing in current window.

Repro

{
  "folke/flash.nvim",
  event = "VeryLazy",
  keys = {
    {
      ";",
      mode = { "n", "x" },
      function()
        -- default options: exact mode, multi window, all directions, with a backdrop
        require("flash").jump()
      end,
      desc = "jump by multiple keys",
    },
    {
      "t",
      mode = { "n", "o", "x" },
      function()
        require("flash").treesitter()
      end,
      desc = "select by Treesitter node",
    },
    {
      "r",
      mode = "o",
      function()
        require("flash").remote()
      end,
      desc = "Remote Flash",
    },
  },
  opts = {
    modes = {
      char = {
        enabled = false,
      },
    }
  },
}

feature: Allow '/' search to continue even with no matches

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

When using the '/' character to search the whole file for a potentially existing word. If the word doesn't exist it will automatically exit the search mode once it fails to match any words on the file.
This can be annoying when you have a very large file and just want to check to see if a word is in the file and then all of a sudden you are adding text into the buffer since it quit searching partway through your search.

Describe the solution you'd like

The search doesn't auto return to normal mode once no matches have been found before hitting Enter/Escape.

Describe alternatives you've considered

Have a setting in the config file to allow current behavior or potential updated behavior.
Have a more obvious indication such as a screen flash or something once the search has been terminated due to no results.

Additional context

No response

bug: ReplaceWithRegister <Plug>ReplaceWithRegisterOperator doesn't work with `remote`

Did you check docs and existing issues?

  • I have read all the flash.nvim docs
  • I have searched the existing issues of flash.nvim
  • I have searched the existing issues of plugins related to this issue

Neovim version (nvim -v)

NVIM v0.9.1 Build type: RelWithDebInfo

Operating system/version

Ubuntu 22.04.2 LTS

Describe the bug

Using require("flash").remote() with <Plug>ReplaceWithRegisterOperator from ReplaceWithRegister doesn't work as expected. The text that is suppossed to be inserted in the selected location is also inserted at the starting location.

Steps To Reproduce

  1. nvim -u repro.lua
  2. Open example.txt with the following code:
remote

starting

foo

3.Put the cursor on foo and highlight the word (yiw).
4. Put the cursor at the beggining of starting
5. Press the keys <leader>r to start a replace
6. Press r to execute require("flash").remote()
7. Press re and select the label next to re on the word remote
8. Press iw

The result is the following:

foo

foostarting

foo

The text was replaced on the remote location, but it was also inserted at the starting location.

Expected Behavior

The result should be the following

foo

starting

foo

Repro

-- DO NOT change the paths and don't remove the colorscheme
local root = vim.fn.fnamemodify("./.repro", ":p")

-- set stdpaths to use .repro
for _, name in ipairs({ "config", "data", "state", "cache" }) do
	vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end

-- bootstrap lazy
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
	vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath })
end
vim.opt.runtimepath:prepend(lazypath)

-- install plugins
local plugins = {
	"folke/tokyonight.nvim",
	{
		"folke/flash.nvim",
		opts = {},
		keys = {
			{
				"r",
				mode = "o",
				function()
					require("flash").remote()
				end,
				desc = "Remote Flash",
			},
		},
	},
	-- add any other plugins here
	{
		"vim-scripts/ReplaceWithRegister",
		keys = {
			{ "<leader>r", "<Plug>ReplaceWithRegisterOperator", mode = "n" },
		},
	},
}
require("lazy").setup(plugins, {
	root = root .. "/plugins",
})

vim.cmd.colorscheme("tokyonight")
-- add anything else here

feature: allow jump label on left hand side

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

it's quite a small thing but it would make things just that little bit more efficient

when I use the jump() function there are labels that appear as soon as you start typing
and they also stay the same while you're typing
so the brain has like time to process the shortcut label while you're typing a second or third character
but this process it a little bit blocked by the fact that the label is on the right side of the already typed text. this means it shift over as you type more things

Describe the solution you'd like

there should be an option for the label to be on the left side of the matched text

Describe alternatives you've considered

just accept it the way it is

Additional context

No response

feature: autoselect

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

When I use the search with s and I type 2-3 characters often I already have a unique result. it's annoying that I still have to press <cr> to actually jump to that result.

Describe the solution you'd like

autojump if there is only one result left

Describe alternatives you've considered

press <cr> :(

Additional context

No response

feature: Allow to 'preload' pattern

Did you check the docs?

  • I have read all the flash.nvim docs

Is your feature request related to a problem? Please describe.

I want to be able to create a version of */# but with labels. I think this could reuse most of the existing code by activating flash.jump with the word under the cursor (vim.fn.expand("<cword>")) as the pattern already.

Describe the solution you'd like

A config option config.search.pattern which if given is preloaded into the state so the labels would already appear. Perhaps another config option to control whether any further keypresses would add to the pattern or not. This config option really only makes sense in the modes table or being provided in the keymapping so maybe it should be an error to put it in the global config.

Describe alternatives you've considered

search.mode = function() return vim.fn.expand("<cword>") end is close to working, I have to type one dummy character to get the labels to show up though. Perhaps instead this should be called once with an empty string when entering flash.

Additional context

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.