/harpoon

Primary LanguageLuaMIT LicenseMIT

Harpoon

Getting you where you want with the fewest keystrokes.

Lua Neovim

Harpoon -- image provided by Liberty_DevCap

⇁ WIP

This is not fully baked, though used by several people. If you experience any issues, see some improvement you think would be amazing, or just have some feedback for harpoon (or me), make an issue!

⇁ The Problems:

  1. You're working on a codebase. medium, large, tiny, whatever. You find yourself frequenting a small set of files and you are tired of using a fuzzy finder, :bnext & :bprev are getting too repetitive, alternate file doesn't quite cut it, etc etc.
  2. You want to execute some project specific commands or have any number of persistent terminals that can be easily navigated to.

⇁ The Solutions:

  1. The ability to specify, or on the fly, mark and create persisting key strokes to go to the files you want.
  2. Unlimited terminals and navigation.

⇁ Installation

  • neovim 0.5.0+ required
  • install using your favorite plugin manager (vim-plug in this example)
Plug 'nvim-lua/plenary.nvim' " don't forget to add this one if you don't have it yet!
Plug 'ThePrimeagen/harpoon'

⇁ Harpooning

here we'll explain how to wield the power of the harpoon:

Marks

you mark files you want to revisit later on

:lua require("harpoon.mark").add_file()

File Navigation

view all project marks with:

:lua require("harpoon.ui").toggle_quick_menu()

you can go up and down the list, enter, delete or reorder. q and <ESC> exit and save the menu

you also can switch to any mark without bringing up the menu, use the below with the desired mark index

:lua require("harpoon.ui").nav_file(3)                  -- navigates to file 3

you can also cycle the list in both directions

:lua require("harpoon.ui").nav_next()                   -- navigates to next mark
:lua require("harpoon.ui").nav_prev()                   -- navigates to previous mark

Terminal Navigation

this works like file navigation except that if there is no terminal at the specified index a new terminal is created.

lua require("harpoon.term").gotoTerminal(1)             -- navigates to term 1

Commands to Terminals

commands can be sent to any terminal

lua require("harpoon.term").sendCommand(1, "ls -La")    -- sends ls -La to tmux window 1

further more commands can be stored for later quick

lua require('harpoon.cmd-ui').toggle_quick_menu()       -- shows the commands menu
lua require("harpoon.term").sendCommand(1, 1)           -- sends command 1 to term 1

Tmux Support

tmux is supported out of the box and can be used as a drop-in replacement to normal terminals by simply switching 'term' with 'tmux' like so

lua require("harpoon.tmux").gotoTerminal(1)             -- goes to the first tmux window
lua require("harpoon.tmux").sendCommand(1, "ls -La")    -- sends ls -La to tmux window 1
lua require("harpoon.tmux").sendCommand(1, 1)           -- sends command 1 to tmux window 1

Telescope Support

1st register harpoon as a telescope extension

require("telescope").load_extension('harpoon')

currently only marks are supported in telescope

:Telescope harpoon marks

⇁ Configuration

if configuring harpoon is desired it must be done through harpoons setup function

require("harpoon").setup({ ... })

Global Settings

here are all the available global settings with their default values

global_settings = {
    -- sets the marks upon calling `toggle` on the ui, instead of require `:w`.
    save_on_toggle = false,

    -- saves the harpoon file upon every change. disabling is unrecommended.
    save_on_change = true,

    -- sets harpoon to run the command immediately as it's passed to the terminal when calling `sendCommand`.
    enter_on_sendcmd = false,

    -- closes any tmux windows harpoon that harpoon creates when you close Neovim.
    tmux_autoclose_windows = false,

    -- filetypes that you want to prevent from adding to the harpoon list menu.
    excluded_filetypes = { "harpoon" }
}

Preconfigured Terminal Commands

to preconfigure terminal commands for later use

projects = {
    -- Yes $HOME works
    ["$HOME/personal/vim-with-me/server"] = {
        term = {
            cmds = {
                "./env && npx ts-node src/index.ts"
            }
        }
    }
}

⇁ Logging

  • logs are written to harpoon.log within the nvim cache path (:echo stdpath("cache"))
  • available log levels are trace, debug, info, warn, error, or fatal. warn is default
  • log level can be set with vim.g.harpoon_log_level (must be before setup())
  • launching nvim with HARPOON_LOG=debug nvim takes precedence over vim.g.harpoon_log_level.
  • invalid values default back to warn.

⇁ Others

How do Harpoon marks differ from vim global marks

they seve a similar purpose however harpoon marks differs in a few key ways:

  1. They auto update their position within the file
  2. They are saved per project.
  3. They can be hand edited vs replaced (swapping is easier)

The Motivation behind Harpoon terminals

  1. I want to use the terminal since I can gF and gF to any errors arising from execution that are within the terminal that are not appropriate for something like dispatch. (not just running tests but perhaps a server that runs for X amount of time before crashing).
  2. I want the terminal to be persistent and I can return to one of many terminals with some finger wizardry and reparse any of the execution information that was not necessarily error related.
  3. I would like to have commands that can be tied to terminals and sent them without much thinking. Some sort of middle ground between vim-test and just typing them into a terminal (configuring netflix's television project isn't quite building and there are tons of ways to configure).