Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto highlight selected - opened in error #396

Closed
wants to merge 89 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
ccf5e1c
feat: the basic list for harpoons
ThePrimeagen Nov 3, 2023
2aa20a8
chore: moved types around
ThePrimeagen Nov 3, 2023
9e60c39
feat: config add now produces a correct HarpoonFileListItem
ThePrimeagen Nov 3, 2023
543f3a1
feat: I am going to marry that data and that list
ThePrimeagen Nov 3, 2023
c1f49fe
feat: list adding now works but duplicates are a problem
ThePrimeagen Nov 3, 2023
734d10b
fix: rename and small lint/bug fix and dedupe add
ThePrimeagen Nov 4, 2023
65d652d
fix: dedupe prepend
ThePrimeagen Nov 4, 2023
ab45ad2
feat: good ass testing going on here
ThePrimeagen Nov 4, 2023
362b79f
feat: resolve_display now works
ThePrimeagen Nov 4, 2023
e080204
partial: i don't know if the splits ackshually work
ThePrimeagen Nov 4, 2023
eafaec8
feat: key for indexing
ThePrimeagen Nov 9, 2023
90bcfeb
feat: changing buffers updates list positions
ThePrimeagen Nov 21, 2023
2fdac4f
feat: brought over the old ui. need to get this upgrade to new api
ThePrimeagen Nov 21, 2023
5d7ee0d
checkpoint: i must sleep with my beautiful wife, but f... its borked
ThePrimeagen Nov 27, 2023
b22cb4a
feat: toggling menu now works!
ThePrimeagen Nov 28, 2023
6fdff8b
feat: listeners for list actions
ThePrimeagen Nov 29, 2023
b58e3db
chore: format
ThePrimeagen Nov 29, 2023
5d6a39c
fix: lint
ThePrimeagen Nov 29, 2023
b6800cb
checkpoint: working through a ui test for removing from display
ThePrimeagen Nov 29, 2023
d98c514
fix: use save instead of toggle
ThePrimeagen Nov 29, 2023
5ec7f92
feat: adding and removing buffers from list
ThePrimeagen Nov 29, 2023
5471588
feat: select navigation
ThePrimeagen Nov 29, 2023
f84bf55
feat: more tests, slowly updating readme
ThePrimeagen Nov 30, 2023
0bb8e5e
did i get the style right?
ThePrimeagen Nov 30, 2023
c692925
TOC
ThePrimeagen Nov 30, 2023
fc35ba1
TOC
ThePrimeagen Nov 30, 2023
ac9cbed
feat: harpoon2 -> harpoon
ThePrimeagen Nov 30, 2023
1d7ea57
fix: vertical and horizontal split
ThePrimeagen Nov 30, 2023
0904ae0
fix: harpoon2 -> harpoon
ThePrimeagen Nov 30, 2023
7d5d141
fix: leaving the window now destroys both border and content win
ThePrimeagen Nov 30, 2023
d044315
fix: closing window
ThePrimeagen Nov 30, 2023
6522b48
fix: wq would cause the editor to exit
ThePrimeagen Nov 30, 2023
d867a33
feat: README.md update
ThePrimeagen Nov 30, 2023
8501bfe
fix: nice branch name jerk
ThePrimeagen Nov 30, 2023
d4edc91
This fixes selecting file 2, 3, 4 for me
jeffrydegrande Dec 1, 2023
95c0478
Merge pull request #344 from jeffrydegrande/fix-maybe-bug-in-setup-in…
ThePrimeagen Dec 1, 2023
574adeb
fix: small fixes
ThePrimeagen Dec 1, 2023
047cd66
fix: addresses #346 and #345
ThePrimeagen Dec 1, 2023
574a642
chore: style
ThePrimeagen Dec 1, 2023
588ede1
chore: lint
ThePrimeagen Dec 1, 2023
7a356bf
feat: more extensive read me and `add` now comes with `config` ref
ThePrimeagen Dec 1, 2023
b8d690f
chore: formatting and lint
ThePrimeagen Dec 1, 2023
1092e6f
Change logo
ryanwinchester Dec 1, 2023
4bb6637
add self.config default item in remove function
zachlankton Dec 1, 2023
901e58c
Merge pull request #349 from zachlankton/harpoon2-fix-list-remove-bug
ThePrimeagen Dec 1, 2023
9b09f72
Merge pull request #347 from ryanwinchester-forks/logo
ThePrimeagen Dec 1, 2023
a539f66
fix: save_on_toggle
ThePrimeagen Dec 1, 2023
23fb000
fix: broken unit tests
ThePrimeagen Dec 1, 2023
689778b
chore: style and lint
ThePrimeagen Dec 1, 2023
1e041f1
feat: removed some duplicate tests that are present in the ui.
ThePrimeagen Dec 1, 2023
01bce04
chore: style
ThePrimeagen Dec 1, 2023
0db652a
fix: removed jump_to settings def
ThePrimeagen Dec 1, 2023
e8cd1ee
fix: settings section
ThePrimeagen Dec 1, 2023
5bb4d59
fix: license and deleting of non useful file
ThePrimeagen Dec 1, 2023
7e37a12
feat: readme
ThePrimeagen Dec 1, 2023
33b03bc
feat: expanding the problems
ThePrimeagen Dec 1, 2023
ced172d
fix: more moar maoare
ThePrimeagen Dec 1, 2023
245875a
readme: contributions
ThePrimeagen Dec 1, 2023
c131b4b
feat: select with nil
ThePrimeagen Dec 1, 2023
8dd3d90
test: select with nil
ThePrimeagen Dec 1, 2023
61406ca
feat: select gets `list` added to its call. for #350
ThePrimeagen Dec 1, 2023
2d5e344
fix: update highlight groups
trimclain Dec 2, 2023
c5f2d71
Merge pull request #356 from trimclain/fix-highlight-groups
ThePrimeagen Dec 2, 2023
97ddd6f
docs: add information about highlight groups
trimclain Dec 2, 2023
6455448
Merge pull request #357 from trimclain/highlight-groups-readme
ThePrimeagen Dec 2, 2023
b2a2405
docs: update README
trimclain Dec 2, 2023
d9dc3bf
fix: telescope integration
roeeyn Dec 2, 2023
f4a3a1e
Merge pull request #363 from roeeyn/fix/telescope-integration
ThePrimeagen Dec 2, 2023
d3f4fe9
Merge pull request #360 from trimclain/patch-1
ThePrimeagen Dec 2, 2023
581da79
chore: style
ThePrimeagen Dec 2, 2023
84e2eb7
feat: link harpoon highlights to default groups
trimclain Dec 4, 2023
0a4c318
Merge pull request #365 from trimclain/link-default-highlights
ThePrimeagen Dec 4, 2023
b546ffe
feat: borders are now customizable
ThePrimeagen Dec 4, 2023
80a4288
fix: #354
ThePrimeagen Dec 4, 2023
68b3223
feat: logger
ThePrimeagen Dec 4, 2023
6041c60
readme: update for logger
ThePrimeagen Dec 4, 2023
c53305c
feat: logging more details about how you moved through harpoon
ThePrimeagen Dec 4, 2023
dfcb848
fix: tests were breaking due to logging
ThePrimeagen Dec 4, 2023
ec03b3c
fix: active list caused nil access error
ThePrimeagen Dec 5, 2023
e2e582e
fix: navigation
ThePrimeagen Dec 5, 2023
23fe641
feat: #372 -- configurable fallback width and width ratio
ThePrimeagen Dec 5, 2023
c24c711
chore: lint and fmt
ThePrimeagen Dec 5, 2023
e9d18fc
feat: logging and rename.
ThePrimeagen Dec 6, 2023
f426523
small logger changes + spec
ThePrimeagen Dec 6, 2023
d8fa264
logger: max lines to prevent things taking too much memory
ThePrimeagen Dec 6, 2023
05edc3e
If out_data is empty then write empty json to harpoon.json. Then read…
mwishoff Dec 6, 2023
b66e92d
Merge pull request #378 from mwishoff/harpoon2
ThePrimeagen Dec 6, 2023
07cca27
feat: better logging for toggle
ThePrimeagen Dec 6, 2023
90a17f1
feat: select_current option
tris203 Dec 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
337 changes: 176 additions & 161 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,208 +4,223 @@
##### Getting you where you want with the fewest keystrokes.

[![Lua](https://img.shields.io/badge/Lua-blue.svg?style=for-the-badge&logo=lua)](http://www.lua.org)
[![Neovim](https://img.shields.io/badge/Neovim%200.5+-green.svg?style=for-the-badge&logo=neovim)](https://neovim.io)
</div>

![Harpoon](harpoon.png)
-- image provided by **Bob Rust**


## ⇁ 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!
[![Neovim](https://img.shields.io/badge/Neovim%200.8+-green.svg?style=for-the-badge&logo=neovim)](https://neovim.io)

<img alt="Harpoon Man" height="280" src="/assets/harpoon-icon.png" />
</div>

## ⇁ The Problems:
## ⇁ TOC
* [The Problems](#-The-Problems)
* [The Solutions](#-The-Solutions)
* [Installation](#-Installation)
* [Getting Started](#-Getting-Started)
* [API](#-API)
* [Config](#config)
* [Settings](#settings)
* [Contribution](#-Contribution)
* [Social](#-Social)
* [Note to legacy Harpoon 1 users](#-Note-to-legacy-Harpoon-1-users)

## ⇁ 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.
1. 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.
1. Unlimited terminals and navigation.
1. You want to execute some project specific commands, have any number of
persistent terminals that can be easily navigated to, send commands to other
tmux windows, or dream up your own custom action and execute with a single key

## ⇁ The Solutions
1. Specify either by altering a ui or by adding via hot key files
1. Unlimited lists and items within the lists

## ⇁ Installation
* neovim 0.5.0+ required
* install using your favorite plugin manager (`vim-plug` in this example)
```vim
Plug 'nvim-lua/plenary.nvim' " don't forget to add this one if you don't have it yet!
Plug 'ThePrimeagen/harpoon'
* neovim 0.8.0+ required
* install using your favorite plugin manager (i am using `packer` in this case)
```lua
use "nvim-lua/plenary.nvim" -- don't forget to add this one if you don't have it yet!
use {
"ThePrimeagen/harpoon",
branch = "harpoon2",
requires = { {"nvim-lua/plenary.nvim"} }
}
```

## ⇁ Harpooning
here we'll explain how to wield the power of the harpoon:
## ⇁ Getting Started

### Quick Note
You will want to add your style of remaps and such to your neovim dotfiles with
the shortcuts you like. My shortcuts are for me. Me alone. Which also means
they are designed with dvorak in mind (My layout btw, I use dvorak btw).

### Marks
you mark files you want to revisit later on
```lua
:lua require("harpoon.mark").add_file()
```
### harpoon:setup() IS REQUIRED
it is a requirement to call `harpoon:setup()`. This is required due to
autocmds setup.

### File Navigation
view all project marks with:
```lua
: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
### Basic Setup
Here is my basic setup

you also can switch to any mark without bringing up the menu, use the below with the desired mark index
```lua
:lua require("harpoon.ui").nav_file(3) -- navigates to file 3
```
you can also cycle the list in both directions
```lua
:lua require("harpoon.ui").nav_next() -- navigates to next mark
:lua require("harpoon.ui").nav_prev() -- navigates to previous mark
```
local harpoon = require("harpoon")

### Terminal Navigation
this works like file navigation except that if there is no terminal at the specified index
a new terminal is created.
```lua
lua require("harpoon.term").gotoTerminal(1) -- navigates to term 1
```
-- REQUIRED
harpoon:setup()
-- REQUIRED

### Commands to Terminals
commands can be sent to any terminal
```lua
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
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
vim.keymap.set("n", "<leader>a", function() harpoon:list():append() end)
vim.keymap.set("n", "<C-e>", function() harpoon.ui:toggle_quick_menu(harpoon:list()) end)

```lua
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
vim.keymap.set("n", "<C-h>", function() harpoon:list():select(1) end)
vim.keymap.set("n", "<C-t>", function() harpoon:list():select(2) end)
vim.keymap.set("n", "<C-n>", function() harpoon:list():select(3) end)
vim.keymap.set("n", "<C-s>", function() harpoon:list():select(4) end)
```

`sendCommand` and `goToTerminal` also accept any valid [tmux pane identifier](https://man7.org/linux/man-pages/man1/tmux.1.html#COMMANDS).
```lua
lua require("harpoon.tmux").gotoTerminal("{down-of}") -- focus the pane directly below
lua require("harpoon.tmux").sendCommand("%3", "ls") -- send a command to the pane with id '%3'
```
## ⇁ API
You can define custom behavior of a harpoon list by providing your own calls.

Once you switch to a tmux window you can always switch back to neovim, this is a
little bash script that will switch to the window which is running neovim.
Here is a simple example where i create a list named `cmd` that takes the
current line in the editor and adds it to harpoon menu. When
`list:select(...)` is called, we take the contents of the line and execute it
as a vim command

In your `tmux.conf` (or anywhere you have keybinds), add this
```bash
bind-key -r G run-shell "path-to-harpoon/harpoon/scripts/tmux/switch-back-to-nvim"
```
I don't think this is a great use of harpoon, but its meant to show how to add
your own custom lists. You could imagine that a terminal list would be just as
easy to create.

### Telescope Support
1st register harpoon as a telescope extension
```lua
require("telescope").load_extension('harpoon')
```
currently only marks are supported in telescope
```
:Telescope harpoon marks
```
local harpoon = require("harpoon")

harpoon:setup({
-- Setting up custom behavior for a list named "cmd"
"cmd" = {

-- When you call list:append() this function is called and the return
-- value will be put in the list at the end.
--
-- which means same behavior for prepend except where in the list the
-- return value is added
--
-- @param possible_value string only passed in when you alter the ui manual
add = function(possible_value)
-- get the current line idx
local idx = vim.fn.line(".")

-- read the current line
local cmd = vim.api.nvim_buf_get_lines(0, idx - 1, idx, false)[1]
if cmd == nil then
return nil
end

return {
value = cmd,
context = { ... any data you want ... },
}
end,

--- This function gets invoked with the options being passed in from
--- list:select(index, <...options...>)
--- @param list_item {value: any, context: any}
--- @param list { ... }
--- @param option any
select = function(list_item, list, option)
-- WOAH, IS THIS HTMX LEVEL XSS ATTACK??
vim.cmd(list_item.value)
end

}
})

## ⇁ Configuration
if configuring harpoon is desired it must be done through harpoons setup function
```lua
require("harpoon").setup({ ... })
```

### Global Settings
here are all the available global settings with their default values
```lua
global_settings = {
-- sets the marks upon calling `toggle` on the ui, instead of require `:w`.
save_on_toggle = false,
### Config
There is quite a bit of behavior you can configure via `harpoon:setup()`

-- saves the harpoon file upon every change. disabling is unrecommended.
save_on_change = true,
* `settings`: is the global settings. as of now there isn't a global setting in use, but once we have some custom behavior i'll put them here
* `default`: the default configuration for any list. it is simply a file harpoon
* `[name] = HarpoonPartialConfigItem`: any named lists config. it will be merged with `default` and override any behavior

-- sets harpoon to run the command immediately as it's passed to the terminal when calling `sendCommand`.
enter_on_sendcmd = false,
**HarpoonPartialConfigItem Definition**
```
---@class HarpoonPartialConfigItem
---@field encode? (fun(list_item: HarpoonListItem): string)
---@field decode? (fun(obj: string): any)
---@field display? (fun(list_item: HarpoonListItem): string)
---@field select? (fun(list_item?: HarpoonListItem, list: HarpoonList, options: any?): nil)
---@field equals? (fun(list_line_a: HarpoonListItem, list_line_b: HarpoonListItem): boolean)
---@field add? fun(item: any?): HarpoonListItem
---@field BufLeave? fun(evt: any, list: HarpoonList): nil
---@field VimLeavePre? fun(evt: any, list: HarpoonList): nil
---@field get_root_dir? fun(): string
```

-- closes any tmux windows harpoon that harpoon creates when you close Neovim.
tmux_autoclose_windows = false,
**Detailed Definitions**
* `encode`: how to encode the list item to the harpoon file. if encode is `false`, then the list will not be saved to disk (think terminals)
* `decode`: how to decode the list
* `display`: how to display the list item in the ui menu
* `select`: the action taken when selecting a list item. called from `list:select(idx, options)`
* `equals`: how to compare two list items for equality
* `add`: called when `list:append()` or `list:prepend()` is called. called with an item, which will be a string, when adding through the ui menu
* `BufLeave`: this function is called for every list on BufLeave. if you need custom behavior, this is the place
* `VimLeavePre`: this function is called for every list on VimLeavePre.
* `get_root_dir`: used for creating relative paths. defaults to `vim.loop.cwd()`

-- filetypes that you want to prevent from adding to the harpoon list menu.
excluded_filetypes = { "harpoon" },
### Settings
Settings can alter the experience of harpoon

**Definition**
```lua
---@class HarpoonSettings
---@field save_on_toggle boolean defaults to true
---@field select_current boolean defalts to false
---@field key (fun(): string)

-- set marks specific to each git branch inside git repository
mark_branch = false,
}
```

**Descriptions**
* `save_on_toggle`: any time the ui menu is closed then we will sync the state back to the backing list
* `select_current`: when the ui menu is opened, if the current file is present on the list, select it
* `border_chars`: the ui's border characters to be displayed
* `key` how the out list key is looked up. This can be useful when using worktrees and using git remote instead of file path

### Preconfigured Terminal Commands
to preconfigure terminal commands for later use
**Defaults**
```lua
projects = {
-- Yes $HOME works
["$HOME/personal/vim-with-me/server"] = {
term = {
cmds = {
"./env && npx ts-node src/index.ts"
}
}
}
}
settings = {
save_on_toggle = false,
select_current = false,
border_chars = { "─", "│", "─", "│", "╭", "╮", "╯", "╰" },
key = function()
return vim.loop.cwd()
end,
},
```

## ⇁ 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 serve a similar purpose however harpoon marks differ in a few key ways:
1. They auto update their position within the file
1. They are saved _per project_.
1. 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 <c-w>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).
1. 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.
1. 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).

#### Use a dynamic width for the Harpoon popup menu
Sometimes the default width of `60` is not wide enough.
The following example demonstrates how to configure a custom width by setting
the menu's width relative to the current window's width.
### Highlight Groups
Currently available highlight groups are
`HarpoonWindow`, `HarpoonBorder`, and `HarpoonTitle`.

```lua
require("harpoon").setup({
menu = {
width = vim.api.nvim_win_get_width(0) - 4,
}
})
```
### Logger
This can help debug issues on other's computer. To get your debug log please do the following.

1. open up a new instance of vim
1. perform exact operation to cause bug
1. execute vim command `:lua require("harpoon").logger:show()` and copy the buffer
1. paste the buffer as part of the bug creation

## ⇁ Contribution
This project is officially open source, not just public source. If you wish to
contribute start with an issue and I am totally willing for PRs, but I will be
very conservative on what I take. I don't want Harpoon _solving_ specific
issues, I want it to create the proper hooks to solve any problem

## ⇁ Social
For questions about Harpoon, there's a #harpoon channel on [the Primagen's Discord](https://discord.gg/theprimeagen) server.
For questions about Harpoon, there's a #harpoon channel on [the Primeagen's Discord](https://discord.gg/theprimeagen) server.
* [Discord](https://discord.gg/theprimeagen)
* [Twitch](https://www.twitch.tv/theprimeagen)
* [Twitter](https://twitter.com/ThePrimeagen)

## ⇁ Note to legacy Harpoon 1 users
Original Harpoon will remain in a frozen state and i will merge PRs in with _no
code review_ for those that wish to remain on that. Harpoon 2 is significantly
better and allows for MUCH greater control. Please migrate to that (will
become `master` within the next few months).

Binary file added assets/harpoon-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
2 changes: 2 additions & 0 deletions lua/harpoon/autocmd.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
local augroup = vim.api.nvim_create_augroup
return augroup("Harpoon", {})
Loading