-- bookmarks.lua -- Save and jump between named positions in files -- ============================================================================ local bookmarks = {} -- Configuration bookmarks.config = { enabled = true, max_bookmarks = 100, } -- Bookmarks storage: name -> {filepath, line, column} bookmarks.marks = {} -- Quick marks (single character, like Vim marks) bookmarks.quick_marks = {} -- Set a named bookmark at current position function bookmarks.set(name) if not name or name == "" then return {success = false, message = "Bookmark name required"} end local buffer = editor:current_buffer() local filepath = buffer.filepath or buffer.name local pos = editor:cursor_pos() bookmarks.marks[name] = { filepath = filepath, line = pos.line, column = pos.column, created = os.time(), } return {success = true, message = string.format("Bookmark '%s' set at %s:%d", name, filepath, pos.line + 1)} end -- Jump to a named bookmark function bookmarks.jump(name) if not name or name == "" then return {success = false, message = "Bookmark name required"} end local mark = bookmarks.marks[name] if not mark then return {success = false, message = "Bookmark not found: " .. name} end -- Check if we need to switch buffers local buffer = editor:current_buffer() local current_file = buffer.filepath or buffer.name if current_file ~= mark.filepath then -- Try to open the file local result = editor:execute_command("find-file", {mark.filepath}) if not result.success then return {success = false, message = "Cannot open file: " .. mark.filepath} end end -- Move to the bookmark position editor:set_cursor(mark.line, mark.column) return {success = true, message = string.format("Jumped to '%s'", name)} end -- Delete a bookmark function bookmarks.delete(name) if not name or name == "" then return {success = false, message = "Bookmark name required"} end if not bookmarks.marks[name] then return {success = false, message = "Bookmark not found: " .. name} end bookmarks.marks[name] = nil return {success = true, message = "Deleted bookmark: " .. name} end -- List all bookmarks function bookmarks.list() local result = {} for name, mark in pairs(bookmarks.marks) do local display_file = mark.filepath:gsub("^" .. (os.getenv("HOME") or ""), "~") table.insert(result, { name = name, filepath = mark.filepath, display = string.format("%s: %s:%d", name, display_file, mark.line + 1), }) end -- Sort by name table.sort(result, function(a, b) return a.name < b.name end) return result end -- Quick mark (single character, for quick navigation) function bookmarks.set_quick(char) if not char or #char ~= 1 then return {success = false, message = "Quick mark must be a single character"} end local buffer = editor:current_buffer() local filepath = buffer.filepath or buffer.name local pos = editor:cursor_pos() bookmarks.quick_marks[char] = { filepath = filepath, line = pos.line, column = pos.column, } return {success = true, message = string.format("Mark '%s' set", char)} end -- Jump to quick mark function bookmarks.jump_quick(char) if not char or #char ~= 1 then return {success = false, message = "Quick mark must be a single character"} end local mark = bookmarks.quick_marks[char] if not mark then return {success = false, message = "Mark not set: " .. char} end local buffer = editor:current_buffer() local current_file = buffer.filepath or buffer.name if current_file ~= mark.filepath then local result = editor:execute_command("find-file", {mark.filepath}) if not result.success then return {success = false, message = "Cannot open file: " .. mark.filepath} end end editor:set_cursor(mark.line, mark.column) return {success = true, message = string.format("Jumped to mark '%s'", char)} end -- Setup function function bookmarks.setup(opts) opts = opts or {} for k, v in pairs(opts) do bookmarks.config[k] = v end if not bookmarks.config.enabled then return end -- Register commands editor:register_command("bookmark-set", "Set a named bookmark at current position", function(args) if #args == 0 then return {success = true, message = "Usage: bookmark-set "} end return bookmarks.set(args[1]) end, {}, true, "s") editor:register_command("bookmark-jump", "Jump to a named bookmark", function(args) if #args == 0 then -- List available bookmarks local list = bookmarks.list() if #list == 0 then return {success = true, message = "No bookmarks set"} end local displays = {} for _, b in ipairs(list) do table.insert(displays, b.display) end editor:set_echo_area(displays) return {success = true, message = ""} end return bookmarks.jump(args[1]) end, {}, true, "s") editor:register_command("bookmark-delete", "Delete a bookmark", function(args) if #args == 0 then return {success = true, message = "Usage: bookmark-delete "} end return bookmarks.delete(args[1]) end, {}, true, "s") editor:register_command("bookmark-list", "List all bookmarks", function(args) local list = bookmarks.list() if #list == 0 then return {success = true, message = "No bookmarks set"} end local displays = {} for _, b in ipairs(list) do table.insert(displays, b.display) end editor:set_echo_area(displays) return {success = true, message = ""} end) -- Quick marks (Vim-style m and ') editor:register_command("mark-set", "Set a quick mark (single character)", function(args) if #args == 0 then return {success = true, message = "Usage: mark-set "} end return bookmarks.set_quick(args[1]) end, {}, true, "c") editor:register_command("mark-jump", "Jump to a quick mark", function(args) if #args == 0 then return {success = true, message = "Usage: mark-jump "} end return bookmarks.jump_quick(args[1]) end, {}, true, "c") -- Key bindings -- C-x r m - set bookmark (Emacs) -- C-x r b - jump to bookmark (Emacs) -- C-x r l - list bookmarks (Emacs) editor:bind_key("C-x r m", "bookmark-set", "Set bookmark") editor:bind_key("C-x r b", "bookmark-jump", "Jump to bookmark") editor:bind_key("C-x r l", "bookmark-list", "List bookmarks") -- Quick marks with F-keys for convenience editor:bind_key("F2", "mark-set", "Set quick mark") editor:bind_key("S-F2", "mark-jump", "Jump to quick mark") print("[bookmarks] Package loaded") end -- Auto-setup with defaults bookmarks.setup() return bookmarks