Warning
Breaking change comming:
if you don't want any breakding changes and avoid this warning,
please pin your version to v1.4.2
.
- Simple: Add, Rename and Remove bookmarks with only one command, less shortcuts more productivity.
- Persistent: save your bookmarks into a human readable json file, which you can manipulate manually.
- Accessible: Find your bookmark by telescope or Treeview with ease.
- Informative: mark with a description, so you can record more information.
- Visibility: display icon and name at the marked lines, and highlight marked lines.
- Groups: arrange your bookmarks in groups, so keep you away from noises.
- Portable: Easily share your bookmarks across devices or with others by modifying the project path in the JSON file.
- Simple version: everything should work out of the box if you are ok with the default config.
-- with lazy.nvim
return {
"LintaoAmons/bookmarks.nvim",
-- tag = "v0.5.4", -- optional, pin the plugin at specific version for stability
dependencies = {
{"nvim-telescope/telescope.nvim"},
{"stevearc/dressing.nvim"} -- optional: to have the same UI shown in the GIF
}
}
Detailed config
return {
"LintaoAmons/bookmarks.nvim",
-- recommand, pin the plugin at specific version for stability
-- backup your db.json file when you want to upgrade the plugin
tag = "v1.4.1",
dependencies = {
{ "nvim-telescope/telescope.nvim" },
{ "stevearc/dressing.nvim" }, -- optional: to have the same UI shown in the GIF
},
config = function()
local opts = {
-- where you want to put your bookmarks db file (a simple readable json file, which you can edit manually as well)
json_db_path = vim.fs.normalize(vim.fn.stdpath("config") .. "/bookmarks.db.json"),
-- This is how the sign looks.
signs = {
mark = { icon = "", color = "red", line_bg = "#572626" },
},
picker = {
-- choose built-in sort logic by name: string, find all the sort logics in `bookmarks.adapter.sort-logic`
-- or custom sort logic: function(bookmarks: Bookmarks.Bookmark[]): nil
sort_by = "last_visited",
},
-- optional, backup the json db file when a new neovim session started and you try to mark a place
-- you can find the file under the same folder
enable_backup = true,
-- optional, show the result of the calibration when you try to calibrate the bookmarks
show_calibrate_result = true,
-- optional, auto calibrate the current buffer when you enter it
auto_calibrate_cur_buf = true,
-- treeview options
treeview = {
bookmark_format = function(bookmark)
if bookmark.name ~= "" then return bookmark.name else return "[No Name]" end
end,
keymap = {
quit = { "q", "<ESC>" },
refresh = "R",
create_folder = "a",
tree_cut = "x",
tree_paste = "p",
collapse = "o",
delete = "d",
active = "s",
copy = "c",
},
},
-- do whatever you like by hooks
hooks = {
{
---a sample hook that change the working directory when goto bookmark
---@param bookmark Bookmarks.Bookmark
---@param projects Bookmarks.Project[]
callback = function(bookmark, projects)
local project_path
for _, p in ipairs(projects) do
if p.name == bookmark.location.project_name then
project_path = p.path
end
end
if project_path then
vim.cmd("cd " .. project_path)
end
end,
},
},
}
require("bookmarks").setup(opts)
end,
}
There's two key concepts in this plugin: BookmarkList
and Bookmark
.
You can look into the code to find the structure of those two domain objects.
Command | Description |
---|---|
BookmarksMark |
Mark current line into active BookmarkList. Rename existing bookmark under cursor. Toggle it off if the new name is an empty string |
BookmarksGoto |
Go to bookmark at current active BookmarkList |
BookmarksCommands |
Find and trigger a bookmark command. |
BookmarksGotoRecent |
Go to latest visited/created Bookmark |
BookmarksEditJsonFile |
An shortcut to edit bookmark jsonfile |
BookmarksTree |
Display all bookmarks with tree-view, and use "cut", "paste", "create folder" to edit the tree. |
BookmarksCommands(subcommands) we have right now
just because I don't know how to write Telescope extension, so I somehow do it this way.
Command | Description |
---|---|
[List] new | create a new BookmarkList and set it to active and mark current line into this BookmarkList |
[List] rename | rename a BookmarkList |
[List] delete | delete a bookmark list |
[List] set active | set a BookmarkList as active |
[List] Browsing all lists | |
[Mark] mark to list | bookmark current line and add it to specific bookmark list |
[Mark] rename bookmark | rename selected bookmark |
[Mark] Browsing all marks | |
[Mark] Bookmarks of current project | |
[Mark] grep the marked files | grep in all the files that contain bookmarks |
[Mark] delete bookmark | delete selected bookmarks |
Also if you want to bind a shortcut to those commands, you can do it by writing some code....
local function call_bookmark_command()
local commands = require("bookmarks.adapter.commands").commands
local command
for _, c in ipairs(commands) do
if c.name == "[Mark] Bookmarks of current project" then -- change it to one of the command above
command = c
end
end
if command then
command.callback()
end
end
vim.keymap.set("n", "<leader>ll", call_bookmark_command)
Check the tree section in the config to find out all the actions you can use.
This plugin doesn't provide any default keybinding. I recommend you to have these four keybindings.
vim.keymap.set({ "n", "v" }, "mm", "<cmd>BookmarksMark<cr>", { desc = "Mark current line into active BookmarkList." })
vim.keymap.set({ "n", "v" }, "mo", "<cmd>BookmarksGoto<cr>", { desc = "Go to bookmark at current active BookmarkList" })
vim.keymap.set({ "n", "v" }, "ma", "<cmd>BookmarksCommands<cr>", { desc = "Find and trigger a bookmark command." })
vim.keymap.set({ "n", "v" }, "mg", "<cmd>BookmarksGotoRecent<cr>", { desc = "Go to latest visited/created Bookmark" })
Don't hesitate to ask me anything about the codebase if you want to contribute.
By telegram or 微信: CateFat
- How to get started:
plugin/bookmarks.lua
the entry point of the pluginlua/bookmarks/domain
where the main objects/concepts live- code layers: user -->
lua/bookmarks/adapter
-->lua/bookmarks/api
-->lua/bookmarks/repo
--> json db
- BookmarksMark's input box as a command line. Text start with
!
considered as command.-
!newlist [listname]
bookmark current line into a newly created bookmark list and set the list as current active list.
-
- remove parse commands, prefer BookmarkCommands instead
-
BookmarkCommands
commands picker, a picker allow user to trigger any bookmark command. - more useful information when dealing with corrupted json db (no issues report yet)
- telescope enhancement (use specific command instead)
- A new command to create bookmark and put it into specific bookmark list (instead current active one)
- Project
- Add a project field
- relative path. (project_path/relative_path can make the bookmarks portable, share your bookmarks to another people or your second laptop)
- bookmarks of current project
- Hooks: Gotobookmark can trigger function like switch project automatically
- Grep content in files that contains bookmarks
- picker
- refactor: extract picker module and remove unused modules
- get bookmarks in active list --> filter --> sort --> telescope/fzflua
- filetree-like BookmarkList and Bookmark browsing.
- MVP thx! @shanlihou
- action alias or rename some of the actions to make it more readable for users
- bookmark filter
- Add top level bookmark list
- sort/modify by bookmark.order field
- floating preview window
- better default bookmark render format(string format, then better UI)
-
u
undo. Expecially for unexpectedd
delete
-
Recent files as bookmarks: record all the buffer the user recently opened and sort by the visited_at- just use
smart-open.nvim
- just use
- goto next/prev bookmark in the current buffer
- smart location calibration according to bookmark content
- Init and calibrate by full match of the line content
- A match algorithm that can tolerate small changes of the line content
- auto generate bookmark name by AI (Sent request to openai api, etc)
- Sequance diagram out of bookmarks: Pattern
[actor] -->actor sequance_number :: desc