diff --git a/README.md b/README.md index 2698d3c..dc2f298 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,16 @@ Try out different [commands](#built-in-commands) such as `:ZkNotes` or `:ZkNew`, :ZkLinks [{options}] ``` +```vim +" Inserts a link at the cursor location or around the selected text. +" params +" (optional) additional options, see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist +" One additional option is `matchSelected` (boolean) which is only applicable to inserting a link around selected text. If `true`, the note picker will search for notes similar to the selected text. Otherwise, the note picker will load all notes to filter through. +" e.g. :'<'>ZkInsertLinkAtSelection {matchSelected = true} +:ZkInsertLink +:'<,'>ZkInsertLinkAtSelection [{options}] +``` + ```vim " Opens a notes picker, filters for notes that match the text in the last visual selection " params diff --git a/lua/zk/api.lua b/lua/zk/api.lua index 025ad66..aa70e78 100644 --- a/lua/zk/api.lua +++ b/lua/zk/api.lua @@ -41,6 +41,18 @@ function M.new(path, options, cb) execute_command("new", path, options, cb) end +---@param target string path to note you want to link to +---@param location table LSP location at current caret +---@param path? string path to explicitly specify the notebook +---@param options? table Extra options; table in form {title: string} +---@param cb? function callback function +---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklink +function M.link(target, location, path, options, cb) + options = vim.tbl_extend("force", { path = target, location = location }, options or {}) + + execute_command("link", path, options, cb) +end + ---@param path? string path to explicitly specify the notebook ---@param options table additional options ---@param cb function callback function diff --git a/lua/zk/commands/builtin.lua b/lua/zk/commands/builtin.lua index 833d0ac..8a1962f 100644 --- a/lua/zk/commands/builtin.lua +++ b/lua/zk/commands/builtin.lua @@ -1,4 +1,5 @@ local zk = require("zk") +local api = require("zk.api") local util = require("zk.util") local commands = require("zk.commands") @@ -70,6 +71,41 @@ commands.add("ZkLinks", function(options) zk.edit(options, { title = "Zk Links" }) end) +local function insert_link(selected, opts) + opts = vim.tbl_extend("force", {}, opts or {}) + + local location = util.get_lsp_location_from_selection() + local selected_text = util.get_text_in_range(util.get_selected_range()) + + if not selected then + location = util.get_lsp_location_from_caret() + else + if opts['matchSelected'] then + opts = vim.tbl_extend("force", { match = { selected_text } }, opts or {}) + end + end + + zk.pick_notes(opts, { multi_select = false }, function(note) + assert(note ~= nil, "Picker failed before link insertion: note is nil") + + local link_opts = {} + + if selected and selected_text ~= nil then + link_opts.title = selected_text + end + + api.link(note.path, location, nil, link_opts, function(err, res) + if not res then + error(err) + end + end) + end) +end + +commands.add('ZkInsertLink', function(opts) insert_link(false, opts) end, { title = 'Insert Zk link' }) +commands.add('ZkInsertLinkAtSelection', function(opts) insert_link(true, opts) end, + { title = 'Insert Zk link', needs_selection = true }) + commands.add("ZkMatch", function(options) local selected_text = util.get_text_in_range(util.get_selected_range()) assert(selected_text ~= nil, "No selected text") diff --git a/lua/zk/util.lua b/lua/zk/util.lua index ec26517..8834bd0 100644 --- a/lua/zk/util.lua +++ b/lua/zk/util.lua @@ -51,6 +51,29 @@ function M.get_lsp_location_from_selection() } end +---Fix to correct cursor location +-- +---When working on link insertion, it was discovered that there may be +---an off-by-one error for single point locations in glsp. This function +---corrects that error. +---@param location table An LSP location object representing a single cell +---@return table The LSP location corrected one row up and one column right +---@internal +local function fix_cursor_location(location) + -- Cursor LSP position is a little weird. + -- It inserts one line down. Seems like an off by one error somewhere + local pos = location['range']['start'] + + pos['line'] = pos['line'] - 1 + pos['character'] = pos['character'] + 1 + + location['range']['start'] = pos + location['range']['end'] = pos + + return location +end + + ---Makes an LSP location object from the caret position in the current buffer. -- ---@return table LSP location object @@ -58,15 +81,15 @@ end function M.get_lsp_location_from_caret() local params = vim.lsp.util.make_given_range_params() - local row,col = unpack(vim.api.nvim_win_get_cursor(0)) + local row, col = unpack(vim.api.nvim_win_get_cursor(0)) local position = { line = row, character = col } - return { + return fix_cursor_location({ uri = params.textDocument.uri, range = { start = position, ["end"] = position } - } + }) end ---Gets the text in the given range of the current buffer.