Inline queries, documentation updates (#11)

pull/12/head
Karim Abou Zeid 2 years ago committed by GitHub
parent c1e7520eb9
commit 8605ff475f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -21,6 +21,7 @@ Using [vim-plug](https://github.com/junegunn/vim-plug)
```viml
Plug "mickael-menu/zk-nvim"
Plug "neovim/nvim-lspconfig"
Plug 'nvim-telescope/telescope.nvim' " optional
Plug 'nvim-lua/plenary.nvim' " optional, dependency for Telescope
```
@ -32,19 +33,13 @@ require("telescope").load_extension("zk")
```
> :warning: This plugin will setup and start the LSP server for you, do *not* call `require("lspconfig").zk.setup()`.
#### Default configuration
**Default configuration**
```lua
require("zk").setup({
-- create user commands such as :ZkNew
create_user_commands = true,
lsp = {
-- automatically attach buffers in a zk notebook that match the given filetypes
auto_attach = {
enabled = true,
filetypes = { "markdown" },
},
-- `config` is passed to `vim.lsp.start_client(config)`
config = {
cmd = { "zk", "lsp" },
@ -53,24 +48,98 @@ require("zk").setup({
-- on_attach = ...
-- etc, see `:h vim.lsp.start_client()`
},
-- automatically attach buffers in a zk notebook that match the given filetypes
auto_attach = {
enabled = true,
filetypes = { "markdown" },
},
},
})
```
### Notebook Directory Discovery
When you run a notebook command, this plugin will look for a notebook in the following places and order:
1. the current buffer path (i.e. the file you are currently editing),
2. the current working directory,
3. the `$ZK_NOTEBOOK_DIR` environment variable.
We recommend you to export the `$ZK_NOTEBOOK_DIR` environment variable, so that a notebook can always be found.
It is worth noting that for some notebook commands you can explicitly specify a notebook by providing a path to any file or directory within the notebook.
An explicitly provided path will always take precedence and override the automatic notebook discovery.
However, this is always optional, and usually not necessary.
## Commands
### VimL
```vim
" Indexes the notebook
:ZkIndex
" Creates and opens a new note
" params
" (optional) directory for the new note, relative to the notebook root
:ZkNew [<directory>]
" Opens a Telescope picker
" params
" (optional) additional options, see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist
:ZkList [<options>]
" Opens a Telescope picker
" params
" (optional) additional options, see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zktaglist
:ZkTagList [<options>]
```
or via Lua
where `options` can be any valid *Lua* expression that evaluates to a table.
*Examples:*
```vim
:ZkNew daily
:ZkList { createdAfter = "3 days ago", tags = { "work" } }
```
### Lua
```lua
require("zk").index(path, args) -- path and args are optional
require("zk").new(path, args) -- path and args are optional
---Indexes the notebook
--
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zkindex
require("zk").index(path, options)
---Creates and opens a new note
--
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zknew
require("zk").new(path, options)
---Opens a Telescope picker
--
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist
require("zk").list(path, options)
---Opens a Telescope picker
--
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zktaglist
require("zk").tag.list(path, options)
```
### Telescope
*Examples:*
```lua
require("zk").new(nil, { dir = "daily" })
require("zk").list(nil, { createdAfter = "3 days ago", tags = { "work" } })
```
As you can see, the `path` is optional, and can usually be omitted; see [Notebook Directory Discovery](#notebook-directory-discovery).
### Telescope
```vim
:Telescope zk notes
:Telescope zk orphans
@ -88,27 +157,42 @@ require('telescope').extensions.zk.links()
require('telescope').extensions.zk.related()
require('telescope').extensions.zk.tags()
```
By default, this plugin will use the path of the current buffer to determine the location of your notebook.
Note that if the current buffer does not belong to a notebook, `$ZK_NOTEBOOK_DIR` will be used to locate your notebook.
If you want, you can also explicitly specify a notebook by providing the path to any file or folder within the notebook like so `:Telescope zk notes path=/foo/bar` or so `require('telescope').extensions.zk.notes({ path = '/foo/bar'})`.
The Telescope pickers also allow you to explicitly specify a notebook like so `:Telescope zk notes path=/foo/bar` or so `require('telescope').extensions.zk.notes({ path = '/foo/bar'})`.
However, specifing a `path` is optional, and is usually not necessary; see [Notebook Directory Discovery](#notebook-directory-discovery).
You can even pass the same additional options to the Telescope pickers as described in [list and tag list commands](#commands).
*Example VimL:*
```vim
:Telescope zk notes createdAfter=3\ days\ ago
```
*Example Lua:*
```lua
require('telescope').extensions.zk.notes({ createdAfter = "3 days ago", tags = { "work" } })
```
As you can see, the VimL API is a bit constrained. Whitespace must be escaped and lists and dictionaries are not supported.
It is therefore recommended to use the `:ZkList` and `:ZkTagList` [commands](#commands) instead.
## API
The difference between e.g. `require("zk").api.new` and `require("zk").new` is that the former lets you handle the API results yourself for more flexibility.
The functions in the API module give you maximum flexibility and provide only a thin Lua friendly layer around zk's API.
You can use it to write your own specialized functions for interacting with zk.
```lua
-- https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zkindex
-- path and args are optional
require("zk").api.index(path, args, function(stats)
-- path and options are optional
require("zk").api.index(path, options, function(stats)
-- do something with the stats
end)
```
```lua
-- https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zknew
-- path and args are optional
require("zk").api.new(path, args, function(res)
-- path and options are optional
require("zk").api.new(path, options, function(res)
file_path = res.path
-- do something with the new file path
end)
@ -116,17 +200,17 @@ end)
```lua
-- https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist
-- path is optional, args.select is required
-- args = { select = { "title", "absPath", "rawContent" }, sort = { "created" } }
require("zk").api.list(path, args, function(notes)
-- path is optional, options.select is required
-- options = { select = { "title", "absPath", "rawContent" }, sort = { "created" } }
require("zk").api.list(path, options, function(notes)
-- do something with the notes
end)
```
```lua
-- https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zktaglist
-- path and args are optional
require("zk").api.tag.list(path, args, function(tags)
-- path and options are optional
require("zk").api.tag.list(path, options, function(tags)
-- do something with the tags
end)
```

@ -1,46 +1,54 @@
local util = require("telescope.zk.util")
local zk = require("zk")
---@param opts table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist
local function show_notes(opts)
opts = vim.tbl_extend("keep", opts or {}, { prompt_title = "Zk Notes" })
zk.api.list(opts.path, util.wrap_note_args({}), function(notes)
zk.api.list(opts.path, util.wrap_note_options(opts), function(notes)
util.show_note_picker(opts, notes)
end)
end
---@param opts table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist
local function show_orphans(opts)
opts = vim.tbl_extend("keep", opts or {}, { prompt_title = "Zk Orphans" })
zk.api.list(opts.path, util.wrap_note_args({ orphan = true }), function(notes)
util.show_note_picker(opts, notes)
end)
opts = vim.tbl_deep_extend("force", opts, { orphan = true })
show_notes(opts)
end
---@param opts table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist
local function show_backlinks(opts)
opts = vim.tbl_extend("keep", opts or {}, { prompt_title = "Zk Backlinks" })
zk.api.list(opts.path, util.wrap_note_args({ linkTo = { vim.api.nvim_buf_get_name(0) } }), function(notes)
util.show_note_picker(opts, notes)
end)
opts = vim.tbl_deep_extend("force", opts, { linkTo = { vim.api.nvim_buf_get_name(0) } })
show_notes(opts)
end
---@param opts table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist
local function show_links(opts)
opts = vim.tbl_extend("keep", opts or {}, { prompt_title = "Zk Links" })
zk.api.list(opts.path, util.wrap_note_args({ linkedBy = { vim.api.nvim_buf_get_name(0) } }), function(notes)
util.show_note_picker(opts, notes)
end)
opts = vim.tbl_deep_extend("force", opts, { linkedBy = { vim.api.nvim_buf_get_name(0) } })
show_notes(opts)
end
---@param opts table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist
local function show_related(opts)
opts = vim.tbl_extend("keep", opts or {}, { prompt_title = "Zk Related" })
zk.api.list(opts.path, util.wrap_note_args({ related = { vim.api.nvim_buf_get_name(0) } }), function(notes)
util.show_note_picker(opts, notes)
end)
opts = vim.tbl_deep_extend("force", opts, { related = { vim.api.nvim_buf_get_name(0) } })
show_notes(opts)
end
---@param opts table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zktaglist
local function show_tags(opts)
opts = vim.tbl_extend("keep", opts or {}, { prompt_title = "Zk Tags" })
zk.api.tag.list(opts.path, util.wrap_tag_args({}), function(tags)
zk.api.tag.list(opts.path, util.wrap_tag_options({}), function(tags)
util.show_tag_picker(opts, tags, function(selected_tags)
zk.api.list(opts.path, util.wrap_note_args({ tags = selected_tags }), function(notes)
zk.api.list(opts.path, util.wrap_note_options({ tags = selected_tags }), function(notes)
opts.prompt_title = "Zk Notes for tag(s) " .. vim.inspect(selected_tags)
util.show_note_picker(opts, notes)
end)

@ -10,7 +10,7 @@ local previewers = require("telescope.previewers")
local M = {}
function M.wrap_note_args(opts)
function M.wrap_note_options(opts)
return vim.tbl_deep_extend(
"force",
{ select = { "title", "absPath", "rawContent" }, sort = { "created" } },
@ -18,7 +18,7 @@ function M.wrap_note_args(opts)
)
end
function M.wrap_tag_args(opts)
function M.wrap_tag_options(opts)
return vim.tbl_deep_extend("force", { sort = { "note-count" } }, opts or {})
end
@ -66,7 +66,6 @@ function M.make_note_previewer()
end
function M.show_note_picker(opts, notes)
-- zk.api.list(opts.path, zk_args, function(notes)
opts = opts or {}
pickers.new(opts, {
finder = finders.new_table({
@ -76,11 +75,9 @@ function M.show_note_picker(opts, notes)
sorter = conf.file_sorter(opts),
previewer = M.make_note_previewer(),
}):find()
-- end)
end
function M.show_tag_picker(opts, tags, cb)
-- zk.api.tag.list(opts.path, make_tag_args(), function(tags)
opts = opts or {}
pickers.new(opts, {
finder = finders.new_table({
@ -101,13 +98,11 @@ function M.show_tag_picker(opts, tags, cb)
actions.close(prompt_bufnr)
-- _list_notes(opts, { prompt_title = "Zk Notes for tag(s) " .. vim.inspect(selection) }, { tags = selection })
cb(selection)
end)
return true
end,
}):find()
-- end)
end
return M

@ -7,6 +7,8 @@ M.api = require("zk.api")
M.lsp = require("zk.lsp")
---The entry point of the plugin
---@param options? table user configuration options
function M.setup(options)
config.options = vim.tbl_deep_extend("force", config.defaults, options or {})
@ -16,22 +18,71 @@ function M.setup(options)
if config.options.create_user_commands then
vim.cmd("command! ZkIndex lua require('zk').index()")
vim.cmd("command! -nargs=? ZkNew lua require('zk').new(nil, { dir = [=[<args>]=]})")
vim.cmd("command! -nargs=? ZkNew lua require('zk').new(nil, { dir = <q-args> })") -- the command arg (directory) is interpreted relative to the notebook root
-- vim.cmd("command! -nargs=? -complete=dir ZkNew lua require('zk').new(nil, { dir = vim.fn.fnamemodify(<q-args>, ':p') })") -- this would interpret the command arg (dir) relative to the cwd instead
vim.cmd(
"command! -nargs=? -complete=lua ZkList lua require('zk').list(nil, assert(loadstring('return ' .. <q-args>))())"
)
vim.cmd(
"command! -nargs=? -complete=lua ZkTagList lua require('zk').tag.list(nil, assert(loadstring('return ' .. <q-args>))())"
)
end
end
-- Commands
function M.index(path, args)
M.api.index(path, args, function(stats)
---Indexes the notebook
--
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zkindex
function M.index(path, options)
M.api.index(path, options, function(stats)
vim.notify(vim.inspect(stats))
end)
end
function M.new(path, args)
M.api.new(path, args, function(res)
---Creates and opens a new note
--
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zknew
function M.new(path, options)
M.api.new(path, options, function(res)
vim.cmd("edit " .. res.path)
end)
end
---Opens a Telescope picker
--
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist
function M.list(path, options)
-- NOTE: this does not have to be telescope specific.
-- In the future consider exposing something like config.options.picker = 'telescope'|'fzf'|'builtin'.
-- Obviously the same applies to the `M.tag.list` function.
if path then
options = options or {}
options.path = path
end
-- `h: telescope.command`
require("telescope._extensions.zk").exports.notes(options)
end
M.tag = {}
---Opens a Telescope picker
--
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zktaglist
function M.tag.list(path, options)
if path then
options = options or {}
options.path = path
end
require("telescope._extensions.zk").exports.tags(options)
end
return M

@ -3,27 +3,48 @@ local util = require("zk.util")
local M = {}
---Try to resolve the notebook directory by checking the following locations in that order
---1. current buffer path
---2. current working directory
---3. `$ZK_NOTEBOOK_DIR` environment variable
--
---@param bufnr number?
local function resolve_notebook_dir(bufnr)
local path = vim.api.nvim_buf_get_name(bufnr)
-- if the buffer has no name, use the current working directory
local cwd = vim.fn.getcwd(0)
-- if the buffer has no name (i.e. it is empty), set the current working directory as it's path
if path == "" then
path = vim.fn.getcwd(0)
path = cwd
end
-- if the buffer doesn't belong to a notebook, use $ZK_NOTEBOOK_DIR as fallback if available
if not util.is_notebook_path(path) and vim.env.ZK_NOTEBOOK_DIR then
path = vim.env.ZK_NOTEBOOK_DIR
if not util.notebook_root(path) then
if not util.notebook_root(cwd) then
-- if neither the buffer nor the cwd belong to a notebook, use $ZK_NOTEBOOK_DIR as fallback if available
if vim.env.ZK_NOTEBOOK_DIR then
path = vim.env.ZK_NOTEBOOK_DIR
end
else
-- the buffer doesn't belong to a notebook, but the cwd does!
path = cwd
end
end
-- at this point, the buffer either belongs to a notebook, or everything else failed
return path
end
local function execute_command(path, cmd, args, cb)
---Executes the given command via LSP
--
---@param cmd string
---@param path string?
---@param options table?
---@param cb function?
local function execute_command(cmd, path, options, cb)
local bufnr = 0
lsp.start()
lsp.client().request("workspace/executeCommand", {
command = "zk." .. cmd,
arguments = {
path or resolve_notebook_dir(bufnr),
args,
options,
},
}, function(err, res)
assert(not err, tostring(err))
@ -33,26 +54,38 @@ local function execute_command(path, cmd, args, cb)
end, bufnr)
end
--- https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zkindex
function M.index(path, args, cb)
execute_command(path, "index", args, cb)
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@param cb function callback function
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zkindex
function M.index(path, options, cb)
execute_command("index", path, options, cb)
end
--- https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zknew
function M.new(path, args, cb)
execute_command(path, "new", args, cb)
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@param cb function callback function
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zknew
function M.new(path, options, cb)
execute_command("new", path, options, cb)
end
--- https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist
function M.list(path, args, cb)
execute_command(path, "list", args, cb)
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@param cb function callback function
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zklist
function M.list(path, options, cb)
execute_command("list", path, options, cb)
end
M.tag = {}
--- https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zktaglist
function M.tag.list(path, args, cb)
execute_command(path, "tag.list", args, cb)
---@param path? string path to explicitly specify the notebook
---@param options table additional options
---@param cb function callback function
---@see https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md#zktaglist
function M.tag.list(path, options, cb)
execute_command("tag.list", path, options, cb)
end
return M

@ -3,14 +3,14 @@ local M = {}
M.defaults = {
create_user_commands = true,
lsp = {
auto_attach = {
enabled = true,
filetypes = { "markdown" },
},
config = {
cmd = { "zk", "lsp" },
name = "zk",
},
auto_attach = {
enabled = true,
filetypes = { "markdown" },
},
},
}

@ -4,21 +4,22 @@ local client_id = nil
local M = {}
--- Starts an LSP client if necessary
---Starts an LSP client if necessary
function M.start()
if not client_id then
client_id = vim.lsp.start_client(config.options.lsp.config)
end
end
--- Starts an LSP client if necessary, and attaches the given buffer.
---Starts an LSP client if necessary, and attaches the given buffer.
---@param bufnr number
function M.buf_add(bufnr)
bufnr = bufnr or 0
M.start()
vim.lsp.buf_attach_client(bufnr, client_id)
end
--- Stops the LSP client managed by this plugin
---Stops the LSP client managed by this plugin
function M.stop()
local client = M.client()
if client then
@ -27,7 +28,7 @@ function M.stop()
client_id = nil
end
--- Gets the LSP client managed by this plugin, might be nil
---Gets the LSP client managed by this plugin, might be nil
function M.client()
return vim.lsp.get_client_by_id(client_id)
end

@ -15,18 +15,21 @@ function M.setup_lsp_auto_attach()
vim.api.nvim_command(string.format("autocmd %s lua require'zk.util'.lsp_buf_auto_add(0)", trigger))
end
function M.is_notebook_path(path)
-- check that we got a match on the .zk root directory
return require("lspconfig.util").root_pattern(".zk")(path) ~= nil
---Checks whether the given path belongs to a notebook
---@param path string
---@return string? root
function M.notebook_root(path)
return require("lspconfig.util").root_pattern(".zk")(path)
end
--- NOTE: No need to manually call this. Automatically called via an |autocmd| if lsp.auto_attach is enabled.
---Automatically called via an |autocmd| if lsp.auto_attach is enabled.
---@param bufnr number
function M.lsp_buf_auto_add(bufnr)
if vim.api.nvim_buf_get_option(bufnr, "buftype") == "nofile" then
return
end
if not M.is_notebook_path(vim.api.nvim_buf_get_name(bufnr)) then
if not M.notebook_root(vim.api.nvim_buf_get_name(bufnr)) then
return
end

Loading…
Cancel
Save