Code Monkey home page Code Monkey logo

arrow.nvim's Introduction

arrow.nvim

Arrow.nvim is a plugin made to bookmarks files (like harpoon) using a single UI (and single keymap).

Arrow can be customized for everyone needs.

Arrow also provides per buffer bookmarks that will can quickly jump to them. (And their position is automatically updated / persisted while you modify the file)

Per Project / Global bookmarksL:

arrow.nvim arrow.nvim_gif arrow_buffers

Installation

Lazy

return {
  "otavioschwanck/arrow.nvim",
  opts = {
    show_icons = true,
    leader_key = ';', -- Recommended to be a single key
    buffer_leader_key = 'm', -- Per Buffer Mappings
  }
}

Packer

use { 'otavioschwanck/arrow.nvim', config = function()
  require('arrow').setup({
    show_icons = true,
    leader_key = ';' -- Recommended to be a single key
    buffer_leader_key = 'm', -- Per Buffer Mappings
  })
end }

Usage

Just press the leader_key set on setup and follow you heart. (Is that easy)

Differences from harpoon:

  • Single keymap needed
  • Different UI to manage the bookmarks
  • Statusline helpers
  • Show only the filename (show path only when needed: same filename twice or too generic filename, like create, index, etc)
  • Has colors and icons <3
  • Has the delete mode to quickly delete items
  • Files can be opened vertically or horizontally
  • Still has the option to edit file

Advanced Setup

{
  show_icons = true,
  always_show_path = false,
  separate_by_branch = false, -- Bookmarks will be separated by git branch
  hide_handbook = false, -- set to true to hide the shortcuts on menu.
  save_path = function()
    return vim.fn.stdpath("cache") .. "/arrow"
  end,
  mappings = {
    edit = "e",
    delete_mode = "d",
    clear_all_items = "C",
    toggle = "s", -- used as save if separate_save_and_remove is true
    open_vertical = "v",
    open_horizontal = "-",
    quit = "q",
    remove = "x", -- only used if separate_save_and_remove is true
    next_item = "]",
    prev_item = "["
  },
  custom_actions = {
    open = function(target_file_name, current_file_name) end, -- target_file_name = file selected to be open, current_file_name = filename from where this was called
    split_vertical = function(target_file_name, current_file_name) end,
    split_horizontal = function(target_file_name, current_file_name) end,
  },
  window = { -- controls the appearance and position of an arrow window (see nvim_open_win() for all options)
    width = "auto",
    height = "auto",
    row = "auto",
    col = "auto",
    border = "double",
  },
  per_buffer_config = {
    lines = 4, -- Number of lines showed on preview.
    sort_automatically = true, -- Auto sort buffer marks.
    satellite = { -- defualt to nil, display arrow index in scrollbar at every update
      enable = false,
      overlap = true,
      priority = 1000,
    },
    zindex = 10, --default 50
    treesitter_context = nil, -- it can be { line_shift_down = 2 }, currently not usable, for detail see https://github.com/otavioschwanck/arrow.nvim/pull/43#issue-2236320268
  },
  separate_save_and_remove = false, -- if true, will remove the toggle and create the save/remove keymaps.
  leader_key = ";",
  save_key = "cwd", -- what will be used as root to save the bookmarks. Can be also `git_root`.
  global_bookmarks = false, -- if true, arrow will save files globally (ignores separate_by_branch)
  index_keys = "123456789zxcbnmZXVBNM,afghjklAFGHJKLwrtyuiopWRTYUIOP", -- keys mapped to bookmark index, i.e. 1st bookmark will be accessible by 1, and 12th - by c
  full_path_list = { "update_stuff" } -- filenames on this list will ALWAYS show the file path too.
}

You can also map previous and next key:

vim.keymap.set("n", "H", require("arrow.persist").previous)
vim.keymap.set("n", "L", require("arrow.persist").next)
vim.keymap.set("n", "<C-s>", require("arrow.persist").toggle)

Statusline

You can use require('arrow.statusline') to access the statusline helpers:

local statusline = require('arrow.statusline')
statusline.is_on_arrow_file() -- return nil if current file is not on arrow.  Return the index if it is.
statusline.text_for_statusline() -- return the text to be shown in the statusline (the index if is on arrow or "" if not)
statusline.text_for_statusline_with_icons() -- Same, but with an bow and arrow icon ;D

statusline

NvimTree

Show arrow marks in front of filename

aaaaaaaaaa

A small patch is needed.

Click to expand

In nvim-tree.lua/lua/nvim-tree/renderer/builder.lua change function formate_line to

function Builder:format_line(indent_markers, arrows, icon, name, node)
  local added_len = 0
  local function add_to_end(t1, t2)
    if not t2 then
      return
    end
    for _, v in ipairs(t2) do
      if added_len > 0 then
        table.insert(t1, { str = M.opts.renderer.icons.padding })
      end
      table.insert(t1, v)
    end

    -- first add_to_end don't need padding
    -- hence added_len is calculated at the end to be used next time
    added_len = 0
    for _, v in ipairs(t2) do
      added_len = added_len + #v.str
    end
  end

  local line = { indent_markers, arrows }

  local arrow_index = 1
  local arrow_filenames = vim.g.arrow_filenames
  if arrow_filenames then
    for i, filename in ipairs(arrow_filenames) do
      if string.sub(node.absolute_path, -#filename) == filename then
        local statusline = require "arrow.statusline"
        arrow_index = statusline.text_for_statusline(_, i)
        line[1].str = string.sub(line[1].str, 1, -3)
        line[2].str = "(" .. arrow_index .. ") "
        line[2].hl = { "ArrowFileIndex" }
        break
      end
    end
  end

  add_to_end(line, { icon })

  for i = #M.decorators, 1, -1 do
    add_to_end(line, M.decorators[i]:icons_before(node))
  end

  add_to_end(line, { name })

  for i = #M.decorators, 1, -1 do
    add_to_end(line, M.decorators[i]:icons_after(node))
  end

  return line
end

Highlights

  • ArrowFileIndex
  • ArrowCurrentFile
  • ArrowAction
  • ArrowDeleteMode

Working with sessions plugins

If you have any error using arrow with a session plugin, like on mini.sessions, add this to the post load session hook:

require("arrow.git").refresh_git_branch() -- only if separated_by_branch is true
require("arrow.persist").load_cache_file()

Obs: persistence.nvim works fine with arrow.

Special Contributors

  • xzbdmw - Had the idea of per buffer bookmarks and helped me to implement it.

Do you like my work? Please, buy me a coffee

https://www.buymeacoffee.com/otavioschwanck

arrow.nvim's People

Contributors

chrisgrieser avatar hosaka avatar larssonmartin1998 avatar nfrid avatar oonamo avatar otavioschwanck avatar petersid2022 avatar pheon-dev avatar rasulomaroff avatar sqve avatar tingey21 avatar wolfecub avatar xzbdmw avatar ysirobs 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

arrow.nvim's Issues

Bug: global_bookmarks not working since commit f88767f6

Hello,

I use arrow.nvim just for global bookmark support, my Lazy configuration is:

  {
    "otavioschwanck/arrow.nvim",
    opts = {
      global_bookmarks = true,
    },
  },

Loading global bookmarks now results in a blank buffer (in my case). This used to work until commit f88767f6.

Replicate issue:

  • set global_bookmarks
  • Save a couple global bookmarks
  • Exit Neovim
  • Start Neovim
  • Load a global bookmark

I get blank buffer, however, I expect the global bookmark file to be loaded as occurred prior to commit f88767f6.

Many thanks.

allow custom actions on buffers

It would be nice if we could have custom actions for the buffers in the buffer list. Maybe just a function that passes in the buffer number?

For example, I would love to be able to use https://github.com/s1n7ax/nvim-window-picker when splitting or opening a buffer, which I can do in both neo-tree and telescope. Example of what it looks like:
image
and code I use to make it work with telescope:

local pick_window = function(prompt_bufnr, direction)
  -- Use nvim-window-picker to choose the window by dynamically attaching a function
  local picker = action_state.get_current_picker(prompt_bufnr)
  picker.get_selection_window = function(pickr, _)
    local picked_window_id = require("window-picker").pick_window({ autoselect_one = true, include_current_win = true })
      or vim.api.nvim_get_current_win()
    -- Unbind after using so next instance of the picker acts normally
    pickr.get_selection_window = nil
    return picked_window_id
  end

  action_set.select(prompt_bufnr, direction)
  vim.cmd("stopinsert")
end

local pick_vertical = function(prompt_bufnr)
  pick_window(prompt_bufnr, "vertical")
end
local pick_horizontal = function(prompt_bufnr)
  pick_window(prompt_bufnr, "horizontal")
end
local pick_default = function(prompt_bufnr)
  pick_window(prompt_bufnr, "default")
end

Typo on the statusline helper?

One of the statusline helper function name has a typo. I'm not sure which was the intended name between is_on_arrow_file in the README OR in_on_arrow_file in the actual code.

Using 'd' as index key introduces a delay

Hello,

First of all thank you for this plugin. It is amazing! 🙂

I want to use the keys "asdfjkl;" as index keys as this is my habit when using marks too but the key 'd' introduces a delay before finally moving to the file. I assume this is because the action for 'd' as delete is active in the 'arrow' window and it is waiting for a text object. Is there a way to disable this for the arrow buffer so I can use it?

[Bug] persist buffer-local bookmarks on lazy load

Hello, thanks for the plugin!

I'm wondering if there's a way to persist buffer-local bookmarks across Neovim instances. I'd like to implement this but not sure where to begin.
Any guidance, @xzbdmw, would be greatly appreciated.

arrow.nvim fails on leader key call

STR:

  1. use neovim nightly
  2. press leader key
Error  10:55:48 msg_show.emsg E5108: Error executing lua: vim/keymap.lua:0: lhs: expected string, got nil
stack traceback:
	[C]: in function 'error'
	vim/shared.lua: in function 'validate'
	vim/keymap.lua: in function 'set'
	...etkov/.local/share/nvim/lazy/arrow.nvim/lua/arrow/ui.lua:448: in function <.../.local/share/nvim/lazy/arrow.nvim/lua/arrow/ui.lua:415>

AR:

arrow.nvim crashes while opening window that cannot be closed nor user

Feat: Add bookmark icons to statuscol?

Is there any way to do this currently? I couldn’t find a way. It would be handy to see an icon in the status ok that shows me a line that’s bookmarked

Possible performance issue?

I noticed a gradual slowdown when changing buffers over time while using arrow.nvim. Although I haven't thoroughly investigated the issue, a quick workaround of commenting out these lines seems to alleviate the problem. Could you please take a look?

Steps to reproduce

  • Save some bookmarks using arrow.nvim.
  • Open a session with multiple buffers.
  • Use arrow.nvim to navigate very quickly between buffers. For example, I have set leader_key='r', rapidly spam something like the following sequence: r1r1r1r2r2r2r2r3r3r3r3r3r1r1r1r1.
  • Change to a different buffer. The buffer change becomes noticeably slower compared to when started. The slowdown becomes more apparent as you continue to navigate and change.

Please let me know if you need any further information or clarification to investigate this issue. Thanks!

Getting empty buffer only when selecting bookmarks by index key

I installed arrow via the default installation via lazy but I am getting a rather weird bug. When loading a saved bookmark via the index key, the buffer appears blank even though the filename is correct on the status line. However if I were use "[" or "]" to cycle to the bookmark it shows up perfectly fine. Any idea what might be causing this?

below is the exact same book mark, the first one access via the index key and the latter accessed via next item
image

image

Feat: allow mapping `next` in the ui

I'd like to map ' to next from within the UI (so ;' goes to the next file), but this doesn't seem to be possible from the current implementation.

How do I call custom_actions entry?

How do I call my detour function via binding?

this is my config


function config.arrow()
  local mappings = {
    edit = "e",
    delete_mode = "d",
    clear_all_items = "C",
    toggle = "a", -- used as save if separate_save_and_remove is true
    open_vertical = "v",
    open_horizontal = "-",
    quit = "q",
    remove = "x", -- only used if separate_save_and_remove is true
    next_item = "]",
    prev_item = "[",
  }

  local detour_file = function(target_file_name, current_file_name)
  print("detour")
    local ok = require('detour').Detour() -- open a detour popup
    if not ok then
        return
    end

    vim.api.nvim_command("e " .. target_file_name)
  end

  local opts = {
    mappings = mappings,
    show_icons = true,
    separate_by_branch = false,
    separate_save_and_remove = true,
    leader_key = "J", -- Recommended to be a single key
    buffer_leader_key = "mj", -- Recommended to be a single key
    window = { -- controls the appearance and position of an arrow window (see nvim_open_win() for all options)
      width = "auto",
      height = "auto",
      row = "auto",
      col = "auto",
      border = "double",
    },
    per_buffer_config = {
      lines = 4, -- Number of lines showed on preview.
      sort_automatically = true, -- Auto sort buffer marks.
      treesitter_context = nil, -- it can be { line_shift_down = 2 }
    },
    save_key = "cwd", -- what will be used as root to save the bookmarks. Can be also `git_root`.
    global_bookmarks = false, -- if true, arrow will save files globally (ignores separate_by_branch)
    index_keys = "123456789zxcbnmZXVBNM,afghjklAFGHJKLwrtyuiopWRTYUIOP", -- keys mapped to bookmark index, i.e. 1st bookmark will be accessible by 1, and 12th - by c
    full_path_list = { "init" }, -- filenames on this list will ALWAYS show the file path too.
    custom_actions = {
      detour = detour_file,
    }
  }
  require("arrow").setup(opts)
end

I've tried adding mappings.detour but it doesnt do anything. I tried reading the code and the docs but I can't figure it out

prev_buffer_bookmark implementation is incorrect

Set 3 marks. Now bind the following:

require("arrow.commands").commands.next_buffer_bookmark()
and
require("arrow.commands").commands.prev_buffer_bookmark()

Execute the keybind for next until you're at the 3rd mark. Now execute the prev keybind. You'll see it jumps to mark 1 instead of mark 2.

The fix is to change buffer_ui.prev_item to use:

	local sorted_by_line_bookmarks = vim.fn.sort(bookmarks, function(a, b)
		return b.line - a.line
	end)

See the examples provided in the sort() docs:
https://neovim.io/doc/user/builtin.html#sort()

(next_item sort func is also incorrect but just happens to work)

FR: add option for global bookmarks

Adding an option to make all bookmarks global or make specific bookmarks global would be really useful as I tend to work in multiple multiple directories.

Inconsistency in UI Display for Subdirectories in Different Projects

Hey,

I wanted to say thanks for the awesome plugin! I've got a question about the UI. In one of my projects, the UI displays the subdirectory along with the file, which is exactly what I want.
Screenshot 2024-03-20 at 2 31 34 AM

But in some other projects, also Go projects, it doesn't show anything related to the subdirectory.

Screenshot 2024-03-20 at 2 31 49 AM

I'm a bit confused about why this is inconsistent. Thanks for any help you can offer!

thank you

BUG - is on arrowfile check isnt working correctly

This is the snippet for heirline

  local arrow_statusline = require("arrow.statusline")
  local arrow = {
    cond = arrow_statusline.is_on_arrow_file(),
    update = {
      "BufRead",
    },
    {
      provider = function()
        return "[" .. arrow_statusline.text_for_statusline_with_icons() .. "] "
      end,
      hl = { fg = colors.fg_01, bold = true },
    },
  }

When in arrow:
Screenshot 2024-04-21 at 15 01 45

When in a saved file:
Screenshot 2024-04-21 at 15 02 50

When in a completely new empty buffer:
Screenshot 2024-04-21 at 15 03 10

is_on_arrow_file seems to return true when in a completely new buffer, but text_for_statusline_with_icons returns an empty string which according to the docs should only be true if not on an arrow file?

statusline.text_for_statusline() -- return the text to be shown in the statusline (the index if is on arrow or "" if not)

Feat: allow save_key to be a function

I'd like to assign a function that returns the root to save_key.
This would allow me to use LSP to return the root instead of only cwd and git_root.
The new type of save_key would be

---@type string|fun(): string?

if the function returns nil, use the CWD as the root, else use the returned value

Bug: icon highlights apply to actions after deleting a few items from the modal

Thanks for this great plugin!

I just noticed that when icons are enabled, in the arrow modal, highlights accidentally apply to action hints after you remove a few items.

Steps to reproduce

  1. Add 3 files
  2. Go into delete mode (d)
  3. Remove 2 files
Kapture.2024-04-11.at.13.51.26.mp4

Notice that the Remove Current File action description has Rem highlighted in red, which was the highlight used to highlight the package-lock.json file.

No support for directories?

Expected behavior

api . modules
api . development/eu-central-1
api . production/eu-central-1

Actual behavior

. modules/api
. development/eu-central-1/api
. production/eu-central-1/api

I'm guessing the name that matches is no name and then it puts the paths as qualifier for that.

Aside from the rendering issue it works fine with directories. (in my case paired with oil.nvim)

image

Provide action to add buffer to list without toggling/improve mapping configuration

Currently the s key toggles between adding and removing items from the list. The issue is that I often want to quickly add a bunch of different files without checking if they are already there and I end up removing them.

I see that the save

function M.save(filename)
function already exists. However:

  1. is it safe to use that exposed function?
  2. it would be nice to provide an 'on_attach' function where we can set local bindings to the arrow buffer instead of global ones

Bug: Does not work when changing project during a session

When I start neovim in directory-a, and then change project (cd directory-b), then arrow still shows me the bookmarks from directory-a. If I quit and start in directory-b, arrow correctly shows me the bookmarks from directory-b.

It seems the bookmark-loading only happens one during initialization and does not monitor changes in the directory.

I think this could be fixed by triggering bookmark-loading via the DirChanged event.

strange leader_key behaviour when updating

Hi!

first of all big thank you because I really love this Plugin, and it is much better than Harpoon imo.

Just a small bug that I have noticed with the following config

return { "otavioschwanck/arrow.nvim", opts = { show_icons = true, leader_key = 'm', } }

If I press 'm' in a buffer I get the menu for the 'per buffer marks' but when I have the following config

return { "otavioschwanck/arrow.nvim", opts = { show_icons = true, leader_key = 'm', buffer_leader_key = 'M', } }

And I press the 'm' key now I get the global menu.
I think this behaviour is very confusing and annoyed me quite a bit when I updated the plugin because of course I was using the first version and when pressing my usual hot keys I get the (at first) confusing per buffer marks menu.

But now that I know what it is I think this new menu is a very cool addition

Bug: `persist.next` fails when not in root

persist.next opens the wrong file when used outside of the root (note: the UI doesn't have this issue)

Repo:

> mkdir repro
> cd repro
> git init # Using root_key = "git_root"!
> mkdir dir
> echo "dir/file" >| "dir/file"
> nvim
  1. :lua require("arrow.persist").clear()
  2. :lua require("arrow.persist").save("dir/file")
  3. :cd dir/ -- We're no longer under the root!
  4. Press leader_key then 1 - it works!
  5. :lua require('arrow.persist').next() -- it opens dir/dir/file

Bug: not working with mini.sessions

Hello, I just installed this plugin and it looks great. However, when I started it I got the following error.

E5108: Error executing lua: .../.local/share/nvim/lazy/arrow.nvim/lua/arrow/ui.lua:50: bad argument #1 to 'ipairs' (table expected, got number)
stack traceback:
        [C]: in function 'ipairs'
        .../.local/share/nvim/lazy/arrow.nvim/lua/arrow/ui.lua:50: in function 'format_file_names'
        .../.local/share/nvim/lazy/arrow.nvim/lua/arrow/ui.lua:300: in function <.../.local/share/nvim/lazy/arrow.nvim/lua/arrow/ui.lua:285>

After wondering a while, I realized that it opens the UI normally and works as expected if I open a file directly from command line and I do not load a session with mini.sessions.

I was doing a little bit of research myself, and it seems that the parameter to function format_file_names seems to be 0 in my case. And it seems to come from file persist.lua function load_cache_file, though I am not exactly sure.

feature request: git branch scoped marks

Harpoon has a similar option, that the marks are scoped to the current git branch. I love this feature personally. Would it be possible to bring this to this great little plugin? Otherwise I love arrow.nvim. 😊

Handbook hint cut off

First of all: Loving the plugin and it replaced harpoon for me <3.

I just noticed that the handbook hint is cut off for my setup.
Wanted to ask whether it is something I have in my setup or whether this could be a known problem:
image

Config is pretty default:

{
  "otavioschwanck/arrow.nvim",
  opts = {
    show_icons = true,
    leader_key = ";",
  },
},

Using most recent master:
"arrow.nvim": { "branch": "master", "commit": "79527117368995b81aa1a77714b49d0d7535274b" },

Feature request: save bookmarks based on git root

Hey, 👋

I have a feature request that would immensely improve my workflow. I primarily work in large monorepos and often open subdirectories within a repository to make things easier to find. However, this is a bit awkward when using arrow.nvim, as it doesn't resolve my bookmarks based on the git repository but rather on the current working directory.

It would be great if we could be provided with an option on how we want to resolve the working directory that arrow will associate the bookmarks with. That way, I could execute a command like git rev-parse --show-toplevel to get the path of the git repository.

🍻

Feature: Toggle betwen recent files

Description

Arrow.nvim is great for navigating a list of bookmarks, but I often find myself switching back and forth between two recently used files. This requires navigating the full arrow.nvim interface or invoking the next and previous keymaps multiple times.

Proposed solution

Implement a dedicated function to toggle between the currently active file and the previously active file. The function could be called something like require('arrow.persist').toggle_recent.

Example

Mark four files:

  1. file-1
  2. file-2
  3. file-3
  4. file-4

Open file-1, then open file-3. Executing toggle_recent() should switch from file-3 to file-1. Executing toggle_recent() again should switch from file-1 back to file-3.

Note: I love this plugin. It's better than harpoon in my opinion!

feature request: add a per buffer bookmark supprt

It will be cool to jump to buffer and then jump to bookmarks(narrowing scope to line) within this buffer in the same UI, mapped to a different toggle key, or just type ; and type any key to enter bookmark mode, since deleting, editing, and choosing bookmarks can have the same experience:)
If you are interested I can try to make a pr!

The `separate_by_branch = true` option does not separate

Hey, 👋

Most importantly, thank you for you an excellent plugin! ❤️

I'm trying to separate my bookmarks between branches, and having troubles getting it to work. Setting the separate_by_branch option to either false or true does nothing.

🍻

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.