Compare commits

...

2 Commits

@ -3,8 +3,9 @@ Neovim extension for the [`zk`](https://github.com/mickael-menu/zk) plain text n
## Requirements
* Neovim >= 0.6.0
* `zk` >= 0.9.0
| `zk-nvim` | `zk` | Neovim |
|-----------|--------|--------|
| latest | 0.13.0 | 0.8.0 |
## Installation
@ -18,6 +19,18 @@ Via [vim-plug](https://github.com/junegunn/vim-plug)
Plug 'mickael-menu/zk-nvim'
```
Via [lazy.nvim](https://github.com/folke/lazy.nvim)
```lua
{
"mickael-menu/zk-nvim",
config = function()
require("zk").setup({
-- See Setup section below
})
end
}
```
To get the best experience, it's recommended to also install either [Telescope](https://github.com/nvim-telescope/telescope.nvim) or [fzf](https://github.com/junegunn/fzf).
## Setup

@ -67,8 +67,8 @@ function M.new(options)
api.new(options.notebook_path, options, function(err, res)
assert(not err, tostring(err))
if options and options.dryRun ~= true and options.edit ~= false then
-- neovim does not yet support window/showDocument, therefore we handle options.edit locally
vim.cmd("edit " .. res.path)
-- neovim does not yet support window/showDocument, therefore we handle options.edit locally
vim.cmd("edit " .. res.path)
end
end)
end
@ -80,7 +80,9 @@ end
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zkindex
function M.index(options, cb)
options = options or {}
cb = cb or function(stats) vim.notify(vim.inspect(stats)) end
cb = cb or function(stats)
vim.notify(vim.inspect(stats))
end
api.index(options.notebook_path, options, function(err, stats)
assert(not err, tostring(err))
cb(stats)

@ -80,7 +80,7 @@ local function insert_link(selected, opts)
if not selected then
location = util.get_lsp_location_from_caret()
else
if opts['matchSelected'] then
if opts["matchSelected"] then
opts = vim.tbl_extend("force", { match = { selected_text } }, opts or {})
end
end
@ -102,9 +102,12 @@ local function insert_link(selected, opts)
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("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())

@ -2,45 +2,14 @@ local M = {}
local name_fn_map = {}
-- NOTE: remove this once `vim.api.nvim_add_user_command` is officially released
M._name_command_map = {}
-- NOTE: remove this helper once `vim.api.nvim_add_user_command` is officially released
local function nvim_add_user_command(name, command, opts)
if vim.api.nvim_add_user_command then
vim.api.nvim_add_user_command(name, command, opts)
else
assert(type(command) == "function", "Not supported in this version of Neovim.")
M._name_command_map[name] = command
vim.cmd(table.concat({
"command" .. (opts.force and "!" or ""),
opts.range and "-range" or "",
opts.nargs and ("-nargs=" .. opts.nargs) or "",
opts.complete and ("-complete=" .. opts.complete) or "",
name,
string.format("lua require('zk.commands')._name_command_map['%s']({ args = <q-args>, range = <range> })", name),
}, " "))
end
end
-- NOTE: remove this helper once `vim.api.nvim_del_user_command` is officially released
local function nvim_del_user_command(name)
if vim.api.nvim_add_user_command then
vim.api.nvim_del_user_command(name)
else
M._name_command_map[name] = nil
vim.cmd("delcommand " .. name)
end
end
---A thin wrapper around `vim.api.nvim_add_user_command` which parses the `params.args` of the command as a Lua table and passes it on to `fn`.
---A thin wrapper around `vim.api.nvim_create_user_command` which parses the `params.args` of the command as a Lua table and passes it on to `fn`.
---@param name string
---@param fn function
---@param opts? table {needs_selection} makes sure the command is called with a range
---@see vim.api.nvim_add_user_command
---@see vim.api.nvim_create_user_command
function M.add(name, fn, opts)
opts = opts or {}
nvim_add_user_command(name, function(params) -- vim.api.nvim_add_user_command
vim.api.nvim_create_user_command(name, function(params) -- vim.api.nvim_add_user_command
if opts.needs_selection then
assert(
params.range == 2,
@ -58,10 +27,10 @@ end
---Wrapper around `vim.api.nvim_del_user_command`
---@param name string
---@see vim.api.nvim_add_user_command
---@see vim.api.nvim_del_user_command
function M.del(name)
name_fn_map[name] = nil
nvim_del_user_command(name) -- vim.api.nvim_del_user_command
vim.api.nvim_del_user_command(name)
end
return M

@ -11,21 +11,20 @@ function M.external_client()
client_name = "zk"
end
local active_clients = vim.lsp.get_active_clients({name=client_name})
local active_clients = vim.lsp.get_active_clients({ name = client_name })
if active_clients == {} then
return nil
end
-- return first lsp server that is actually in use
for _,v in ipairs(active_clients) do
if v.attached_buffers ~= {} then
return v.id
end
for _, v in ipairs(active_clients) do
if v.attached_buffers ~= {} then
return v.id
end
end
end
---Starts an LSP client if necessary
function M.start()
if not client_id then

@ -4,7 +4,6 @@ local conf = require("telescope.config").values
local actions = require("telescope.actions")
local action_state = require("telescope.actions.state")
local action_utils = require("telescope.actions.utils")
local putils = require("telescope.previewers.utils")
local entry_display = require("telescope.pickers.entry_display")
local previewers = require("telescope.previewers")
@ -50,11 +49,10 @@ end
function M.make_note_previewer()
return previewers.new_buffer_previewer({
define_preview = function(self, entry)
conf.buffer_previewer_maker(
entry.value.absPath,
self.state.bufnr,
{ bufname = entry.value.title or entry.value.path }
)
conf.buffer_previewer_maker(entry.value.absPath, self.state.bufnr, {
bufname = entry.value.title or entry.value.path,
winid = self.state.winid,
})
end,
})
end
@ -63,64 +61,68 @@ function M.show_note_picker(notes, options, cb)
options = options or {}
local telescope_options = vim.tbl_extend("force", { prompt_title = options.title }, options.telescope or {})
pickers.new(telescope_options, {
finder = finders.new_table({
results = notes,
entry_maker = M.create_note_entry_maker(options),
}),
sorter = conf.file_sorter(options),
previewer = M.make_note_previewer(),
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
if options.multi_select then
local selection = {}
action_utils.map_selections(prompt_bufnr, function(entry, _)
table.insert(selection, entry.value)
end)
if vim.tbl_isempty(selection) then
selection = { action_state.get_selected_entry().value }
pickers
.new(telescope_options, {
finder = finders.new_table({
results = notes,
entry_maker = M.create_note_entry_maker(options),
}),
sorter = conf.file_sorter(options),
previewer = M.make_note_previewer(),
attach_mappings = function(prompt_bufnr)
actions.select_default:replace(function()
if options.multi_select then
local selection = {}
action_utils.map_selections(prompt_bufnr, function(entry, _)
table.insert(selection, entry.value)
end)
if vim.tbl_isempty(selection) then
selection = { action_state.get_selected_entry().value }
end
actions.close(prompt_bufnr)
cb(selection)
else
actions.close(prompt_bufnr)
cb(action_state.get_selected_entry().value)
end
actions.close(prompt_bufnr)
cb(selection)
else
actions.close(prompt_bufnr)
cb(action_state.get_selected_entry().value)
end
end)
return true
end,
}):find()
end)
return true
end,
})
:find()
end
function M.show_tag_picker(tags, options, cb)
options = options or {}
local telescope_options = vim.tbl_extend("force", { prompt_title = options.title }, options.telescope or {})
pickers.new(telescope_options, {
finder = finders.new_table({
results = tags,
entry_maker = M.create_tag_entry_maker(options),
}),
sorter = conf.generic_sorter(options),
attach_mappings = function(prompt_bufnr, _)
actions.select_default:replace(function()
if options.multi_select then
local selection = {}
action_utils.map_selections(prompt_bufnr, function(entry, _)
table.insert(selection, entry.value)
end)
if vim.tbl_isempty(selection) then
selection = { action_state.get_selected_entry().value }
pickers
.new(telescope_options, {
finder = finders.new_table({
results = tags,
entry_maker = M.create_tag_entry_maker(options),
}),
sorter = conf.generic_sorter(options),
attach_mappings = function(prompt_bufnr, _)
actions.select_default:replace(function()
if options.multi_select then
local selection = {}
action_utils.map_selections(prompt_bufnr, function(entry, _)
table.insert(selection, entry.value)
end)
if vim.tbl_isempty(selection) then
selection = { action_state.get_selected_entry().value }
end
actions.close(prompt_bufnr)
cb(selection)
else
cb(action_state.get_selected_entry().value)
end
actions.close(prompt_bufnr)
cb(selection)
else
cb(action_state.get_selected_entry().value)
end
end)
return true
end,
}):find()
end)
return true
end,
})
:find()
end
return M

@ -9,7 +9,7 @@ local M = {}
-- Some path utilities
M.path = (function()
local is_windows = uv.os_uname().version:match 'Windows'
local is_windows = uv.os_uname().version:match("Windows")
local function exists(filename)
local stat = uv.fs_stat(filename)
@ -18,31 +18,31 @@ M.path = (function()
local function is_fs_root(path)
if is_windows then
return path:match '^%a:$'
return path:match("^%a:$")
else
return path == '/'
return path == "/"
end
end
local function dirname(path)
local strip_dir_pat = '/([^/]+)$'
local strip_sep_pat = '/$'
local strip_dir_pat = "/([^/]+)$"
local strip_sep_pat = "/$"
if not path or #path == 0 then
return
end
local result = path:gsub(strip_sep_pat, ''):gsub(strip_dir_pat, '')
local result = path:gsub(strip_sep_pat, ""):gsub(strip_dir_pat, "")
if #result == 0 then
if is_windows then
return path:sub(1, 2):upper()
else
return '/'
return "/"
end
end
return result
end
local function path_join(...)
return table.concat(vim.tbl_flatten { ... }, '/')
return table.concat(vim.tbl_flatten({ ... }), "/")
end
-- Iterate the path until we find the rootdir.
@ -70,7 +70,7 @@ M.path = (function()
end)()
function M.search_ancestors(startpath, func)
validate { func = { func, 'f' } }
validate({ func = { func, "f" } })
if func(startpath) then
return startpath
end
@ -89,7 +89,7 @@ function M.search_ancestors(startpath, func)
end
function M.root_pattern(...)
local patterns = vim.tbl_flatten { ... }
local patterns = vim.tbl_flatten({ ... })
local function matcher(path)
for _, pattern in ipairs(patterns) do
for _, p in ipairs(vim.fn.glob(M.path.join(path, pattern), true, true)) do

@ -8,11 +8,8 @@ local M = {}
---@param options? table containing {picker}, {title}, {multi_select} keys
---@param cb function
function M.pick_notes(notes, options, cb)
options = vim.tbl_extend(
"force",
{ title = "Zk Notes", picker = config.options.picker, multi_select = true },
options or {}
)
options =
vim.tbl_extend("force", { title = "Zk Notes", picker = config.options.picker, multi_select = true }, options or {})
require("zk.pickers." .. options.picker).show_note_picker(notes, options, cb)
end
@ -22,11 +19,8 @@ end
---@param options? table containing {picker}, {title}, {multi_select} keys
---@param cb function
function M.pick_tags(tags, options, cb)
options = vim.tbl_extend(
"force",
{ title = "Zk Tags", picker = config.options.picker, multi_select = true },
options or {}
)
options =
vim.tbl_extend("force", { title = "Zk Tags", picker = config.options.picker, multi_select = true }, options or {})
require("zk.pickers." .. options.picker).show_tag_picker(tags, options, cb)
end

@ -47,7 +47,7 @@ function M.get_lsp_location_from_selection()
local params = vim.lsp.util.make_given_range_params()
return {
uri = params.textDocument.uri,
range = M.get_selected_range() -- workaround for neovim 0.6.1 bug (https://github.com/mickael-menu/zk-nvim/issues/19)
range = M.get_selected_range(), -- workaround for neovim 0.6.1 bug (https://github.com/mickael-menu/zk-nvim/issues/19)
}
end
@ -62,18 +62,17 @@ end
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']
local pos = location["range"]["start"]
pos['line'] = pos['line'] - 1
pos['character'] = pos['character'] + 1
pos["line"] = pos["line"] - 1
pos["character"] = pos["character"] + 1
location['range']['start'] = pos
location['range']['end'] = pos
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
@ -87,8 +86,8 @@ function M.get_lsp_location_from_caret()
uri = params.textDocument.uri,
range = {
start = position,
["end"] = position
}
["end"] = position,
},
})
end
@ -105,7 +104,7 @@ function M.get_text_in_range(range)
if vim.tbl_isempty(lines) then
return nil
end
local MAX_STRING_SUB_INDEX = 2^31 - 1 -- LuaJIT only supports 32bit integers for `string.sub` (in block selection B.character is 2^31)
local MAX_STRING_SUB_INDEX = 2 ^ 31 - 1 -- LuaJIT only supports 32bit integers for `string.sub` (in block selection B.character is 2^31)
lines[#lines] = string.sub(lines[#lines], 1, math.min(B.character, MAX_STRING_SUB_INDEX))
lines[1] = string.sub(lines[1], math.min(A.character + 1, MAX_STRING_SUB_INDEX))
return table.concat(lines, "\n")

Loading…
Cancel
Save