{"id":26738882,"url":"https://github.com/jacktuck/harpoon","last_synced_at":"2025-03-28T03:38:45.425Z","repository":{"id":233190324,"uuid":"700629378","full_name":"jacktuck/harpoon","owner":"jacktuck","description":null,"archived":false,"fork":false,"pushed_at":"2023-10-05T01:12:09.000Z","size":2304,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-04-14T12:44:20.451Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jacktuck.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":"theprimeagen"}},"created_at":"2023-10-05T01:11:12.000Z","updated_at":"2024-04-14T12:44:25.557Z","dependencies_parsed_at":"2024-04-14T12:44:25.255Z","dependency_job_id":"f6655a55-2e4e-41b4-a811-fe9c57b175fc","html_url":"https://github.com/jacktuck/harpoon","commit_stats":null,"previous_names":["jacktuck/harpoon"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jacktuck%2Fharpoon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jacktuck%2Fharpoon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jacktuck%2Fharpoon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jacktuck%2Fharpoon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jacktuck","download_url":"https://codeload.github.com/jacktuck/harpoon/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245966926,"owners_count":20701759,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-28T03:38:44.875Z","updated_at":"2025-03-28T03:38:45.418Z","avatar_url":"https://github.com/jacktuck.png","language":"Lua","funding_links":["https://github.com/sponsors/theprimeagen"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Harpoon\n##### Getting you where you want with the fewest keystrokes.\n\n[![Lua](https://img.shields.io/badge/Lua-blue.svg?style=for-the-badge\u0026logo=lua)](http://www.lua.org)\n[![Neovim](https://img.shields.io/badge/Neovim%200.5+-green.svg?style=for-the-badge\u0026logo=neovim)](https://neovim.io)\n\u003c/div\u003e\n\n![Harpoon](harpoon.png)\n-- image provided by **Bob Rust**\n\n\n## ⇁  WIP\nThis is not fully baked, though used by several people. If you experience any\nissues, see some improvement you think would be amazing, or just have some\nfeedback for harpoon (or me), make an issue!\n\n\n## ⇁ The Problems:\n1. You're working on a codebase. medium, large, tiny, whatever. You find\nyourself frequenting a small set of files and you are tired of using a fuzzy finder,\n`:bnext` \u0026 `:bprev` are getting too repetitive, alternate file doesn't quite cut it, etc etc.\n1. You want to execute some project specific commands or have any number of\npersistent terminals that can be easily navigated to.\n\n\n## ⇁  The Solutions:\n1. The ability to specify, or on the fly, mark and create persisting key strokes\nto go to the files you want.\n1. Unlimited terminals and navigation.\n\n\n## ⇁ Installation\n* neovim 0.5.0+ required\n* install using your favorite plugin manager (`vim-plug` in this example)\n```vim\nPlug 'nvim-lua/plenary.nvim' \" don't forget to add this one if you don't have it yet!\nPlug 'ThePrimeagen/harpoon'\n```\n\n## ⇁ Harpooning\nhere we'll explain how to wield the power of the harpoon:\n\n\n### Marks\nyou mark files you want to revisit later on\n```lua\n:lua require(\"harpoon.mark\").add_file()\n```\n\n### File Navigation\nview all project marks with:\n```lua\n:lua require(\"harpoon.ui\").toggle_quick_menu()\n```\nyou can go up and down the list, enter, delete or reorder. `q` and `\u003cESC\u003e` exit and save the menu\n\nyou also can switch to any mark without bringing up the menu, use the below with the desired mark index\n```lua\n:lua require(\"harpoon.ui\").nav_file(3)                  -- navigates to file 3\n```\nyou can also cycle the list in both directions\n```lua\n:lua require(\"harpoon.ui\").nav_next()                   -- navigates to next mark\n:lua require(\"harpoon.ui\").nav_prev()                   -- navigates to previous mark\n```\nfrom the quickmenu, open a file in: \na vertical split with control+v,\na horizontal split with control+x, \na new tab with control+t\n\n### Terminal Navigation\nthis works like file navigation except that if there is no terminal at the specified index\na new terminal is created.\n```lua\nlua require(\"harpoon.term\").gotoTerminal(1)             -- navigates to term 1\n```\n\n### Commands to Terminals\ncommands can be sent to any terminal\n```lua\nlua require(\"harpoon.term\").sendCommand(1, \"ls -La\")    -- sends ls -La to tmux window 1\n```\nfurther more commands can be stored for later quick\n```lua\nlua require('harpoon.cmd-ui').toggle_quick_menu()       -- shows the commands menu\nlua require(\"harpoon.term\").sendCommand(1, 1)           -- sends command 1 to term 1\n```\n\n### Tmux Support\ntmux is supported out of the box and can be used as a drop-in replacement to normal terminals\nby simply switching `'term' with 'tmux'` like so\n\n```lua\nlua require(\"harpoon.tmux\").gotoTerminal(1)             -- goes to the first tmux window\nlua require(\"harpoon.tmux\").sendCommand(1, \"ls -La\")    -- sends ls -La to tmux window 1\nlua require(\"harpoon.tmux\").sendCommand(1, 1)           -- sends command 1 to tmux window 1\n```\n\n`sendCommand` and `goToTerminal` also accept any valid [tmux pane identifier](https://man7.org/linux/man-pages/man1/tmux.1.html#COMMANDS).\n```lua\nlua require(\"harpoon.tmux\").gotoTerminal(\"{down-of}\")   -- focus the pane directly below\nlua require(\"harpoon.tmux\").sendCommand(\"%3\", \"ls\")     -- send a command to the pane with id '%3'\n```\n\nOnce you switch to a tmux window you can always switch back to neovim, this is a\nlittle bash script that will switch to the window which is running neovim.\n\nIn your `tmux.conf` (or anywhere you have keybinds), add this\n```bash\nbind-key -r G run-shell \"path-to-harpoon/harpoon/scripts/tmux/switch-back-to-nvim\"\n```\n\n### Telescope Support\n1st register harpoon as a telescope extension\n```lua\nrequire(\"telescope\").load_extension('harpoon')\n```\ncurrently only marks are supported in telescope\n```\n:Telescope harpoon marks\n```\n\n## ⇁ Configuration\nif configuring harpoon is desired it must be done through harpoons setup function\n```lua\nrequire(\"harpoon\").setup({ ... })\n```\n\n### Global Settings\nhere are all the available global settings with their default values\n```lua\nglobal_settings = {\n    -- sets the marks upon calling `toggle` on the ui, instead of require `:w`.\n    save_on_toggle = false,\n\n    -- saves the harpoon file upon every change. disabling is unrecommended.\n    save_on_change = true,\n\n    -- sets harpoon to run the command immediately as it's passed to the terminal when calling `sendCommand`.\n    enter_on_sendcmd = false,\n\n    -- closes any tmux windows harpoon that harpoon creates when you close Neovim.\n    tmux_autoclose_windows = false,\n\n    -- filetypes that you want to prevent from adding to the harpoon list menu.\n    excluded_filetypes = { \"harpoon\" },\n\n    -- set marks specific to each git branch inside git repository\n    mark_branch = false,\n}\n```\n\n\n### Preconfigured Terminal Commands\nto preconfigure terminal commands for later use\n```lua\nprojects = {\n    -- Yes $HOME works\n    [\"$HOME/personal/vim-with-me/server\"] = {\n        term = {\n            cmds = {\n                \"./env \u0026\u0026 npx ts-node src/index.ts\"\n            }\n        }\n    }\n}\n```\n\n## ⇁ Logging\n- logs are written to `harpoon.log` within the nvim cache path (`:echo stdpath(\"cache\")`)\n- available log levels are `trace`, `debug`, `info`, `warn`, `error`, or `fatal`. `warn` is default\n- log level can be set with `vim.g.harpoon_log_level` (must be **before** `setup()`)\n- launching nvim with `HARPOON_LOG=debug nvim` takes precedence over `vim.g.harpoon_log_level`.\n- invalid values default back to `warn`.\n\n## ⇁ Others\n#### How do Harpoon marks differ from vim global marks\nthey serve a similar purpose however harpoon marks differ in a few key ways:\n1. They auto update their position within the file\n1. They are saved _per project_.\n1. They can be hand edited vs replaced (swapping is easier)\n\n#### The Motivation behind Harpoon terminals\n1. I want to use the terminal since I can gF and \u003cc-w\u003egF to any errors arising\nfrom execution that are within the terminal that are not appropriate for\nsomething like dispatch. (not just running tests but perhaps a server that runs\nfor X amount of time before crashing).\n1. I want the terminal to be persistent and I can return to one of many terminals\nwith some finger wizardry and reparse any of the execution information that was\nnot necessarily error related.\n1. I would like to have commands that can be tied to terminals and sent them\nwithout much thinking. Some sort of middle ground between vim-test and just\ntyping them into a terminal (configuring netflix's television project isn't\nquite building and there are tons of ways to configure).\n\n#### Use a dynamic width for the Harpoon popup menu\nSometimes the default width of `60` is not wide enough.\nThe following example demonstrates how to configure a custom width by setting\nthe menu's width relative to the current window's width.\n\n```lua\nrequire(\"harpoon\").setup({\n    menu = {\n        width = vim.api.nvim_win_get_width(0) - 4,\n    }\n})\n```\n\n## ⇁ Social\nFor questions about Harpoon, there's a #harpoon channel on [the Primagen's Discord](https://discord.gg/theprimeagen) server.  \n* [Discord](https://discord.gg/theprimeagen)\n* [Twitch](https://www.twitch.tv/theprimeagen)\n* [Twitter](https://twitter.com/ThePrimeagen)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjacktuck%2Fharpoon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjacktuck%2Fharpoon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjacktuck%2Fharpoon/lists"}