Skip to content

Commit

Permalink
Add support for 'zk.link', with commands ZkInsertLink and `ZkInsert…
Browse files Browse the repository at this point in the history
…LinkAtSelection` (#97)
  • Loading branch information
psanker authored Feb 6, 2023
1 parent 2fd9f9f commit 0413c52
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 3 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions lua/zk/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
36 changes: 36 additions & 0 deletions lua/zk/commands/builtin.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local zk = require("zk")
local api = require("zk.api")
local util = require("zk.util")
local commands = require("zk.commands")

Expand Down Expand Up @@ -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")
Expand Down
29 changes: 26 additions & 3 deletions lua/zk/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,45 @@ 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
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#location
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.
Expand Down

0 comments on commit 0413c52

Please sign in to comment.