Kick start the plugin and Telescope extension (#5)

pull/8/head
Karim Abou Zeid 2 years ago committed by GitHub
parent 88a327ef1c
commit 89179f1949
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,2 +1,157 @@
# zk-nvim
Neovim extension for zk
Neovim extension for [zk](https://github.com/mickael-menu/zk).
## Install
Using [packer.nvim](https://github.com/wbthomason/packer.nvim)
```lua
use {
"mickael-menu/zk-nvim",
requires = { "neovim/nvim-lspconfig" }
}
-- Telescope is optional
use {
'nvim-telescope/telescope.nvim',
requires = { {'nvim-lua/plenary.nvim'} }
}
```
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
```
## Setup
```lua
require("zk").setup()
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
```lua
require("zk").setup({
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" },
name = "zk",
-- init_options = ...
-- on_attach = ...
-- etc, see `:h vim.lsp.start_client()`
},
},
})
```
## Commands
```vim
:ZkIndex
:ZkNew [<directory>]
```
or via Lua
```lua
require("zk").index(path, args) -- path and args are optional
require("zk").new(path, args) -- path and args are optional
```
### Telescope
```vim
:Telescope zk notes
:Telescope zk backlinks
:Telescope zk links
:Telescope zk related
:Telescope zk tags
```
or via Lua
```lua
require('telescope').extensions.zk.notes()
require('telescope').extensions.zk.backlinks()
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'})`.
## 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.
```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)
-- 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)
file_path = res.path
-- do something with the new file path
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)
-- 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)
-- do something with the tags
end)
```
## Example Mappings
```lua
vim.api.nvim_set_keymap(
"n",
"<Leader>zn",
"<cmd>lua require('telescope').extensions.zk.notes()<CR>",
{ noremap = true }
)
vim.api.nvim_set_keymap(
"n",
"<Leader>zb",
"<cmd>lua require('telescope').extensions.zk.backlinks()<CR>",
{ noremap = true }
)
vim.api.nvim_set_keymap(
"n",
"<Leader>zl",
"<cmd>lua require('telescope').extensions.zk.links()<CR>",
{ noremap = true }
)
vim.api.nvim_set_keymap(
"n",
"<Leader>zt",
"<cmd>lua require('telescope').extensions.zk.tags()<CR>",
{ noremap = true }
)
```

@ -0,0 +1,52 @@
local util = require("telescope.zk.util")
local zk = require("zk")
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)
util.show_note_picker(opts, notes)
end)
end
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)
end
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)
end
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)
end
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)
util.show_tag_picker(opts, tags, function(selected_tags)
zk.api.list(opts.path, util.wrap_note_args({ tags = selected_tags }), function(notes)
opts.prompt_title = "Zk Notes for tag(s) " .. vim.inspect(selected_tags)
util.show_note_picker(opts, notes)
end)
end)
end)
end
return require("telescope").register_extension({
exports = {
notes = show_notes,
backlinks = show_backlinks,
links = show_links,
related = show_related,
tags = show_tags,
},
})

@ -0,0 +1,113 @@
local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
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")
local M = {}
function M.wrap_note_args(opts)
return vim.tbl_deep_extend(
"force",
{ select = { "title", "absPath", "rawContent" }, sort = { "created" } },
opts or {}
)
end
function M.wrap_tag_args(opts)
return vim.tbl_deep_extend("force", { sort = { "note-count" } }, opts or {})
end
function M.create_note_entry_maker(_)
return function(note)
return {
value = note,
path = note.absPath,
display = note.title,
ordinal = note.title,
}
end
end
function M.create_tag_entry_maker(opts)
return function(tag)
local displayer = entry_display.create({
separator = " ",
items = {
{ width = opts.note_count_width or 4 },
{ remaining = true },
},
})
local make_display = function(e)
return displayer({
{ e.value.note_count, "TelescopeResultsNumber" },
e.value.name,
})
end
return {
value = tag,
display = make_display,
ordinal = tag.name,
}
end
end
function M.make_note_previewer()
return previewers.new_buffer_previewer({
define_preview = function(self, entry)
vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, vim.split(entry.value.rawContent, "\n"))
putils.highlighter(self.state.bufnr, "markdown")
end,
})
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({
results = notes,
entry_maker = M.create_note_entry_maker(opts),
}),
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({
results = tags,
entry_maker = M.create_tag_entry_maker(opts),
}),
sorter = conf.generic_sorter(opts),
attach_mappings = function(prompt_bufnr, _)
actions.select_default:replace(function()
local selection = {}
action_utils.map_selections(prompt_bufnr, function(entry, _)
table.insert(selection, entry.value.name)
end)
if vim.tbl_isempty(selection) then
selection = { action_state.get_selected_entry().value.name }
end
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

@ -0,0 +1,34 @@
local util = require("zk.util")
local config = require("zk.config")
local M = {}
M.api = require("zk.api")
M.lsp = require("zk.lsp")
function M.setup(options)
config.options = vim.tbl_deep_extend("force", config.defaults, options or {})
if config.options.lsp.auto_attach.enabled then
util.setup_lsp_auto_attach()
end
end
-- Commands
function M.index(path, args)
M.api.index(path, args, function(stats)
vim.notify(vim.inspect(stats))
end)
end
function M.new(path, args)
M.api.new(path, args, function(res)
vim.cmd("edit " .. res.path)
end)
end
vim.cmd("command! ZkIndex lua require('zk').index()")
vim.cmd("command! -nargs=? ZkNew lua require('zk').new(nil, { dir = [=[<args>]=]})")
return M

@ -0,0 +1,58 @@
local lsp = require("zk.lsp")
local util = require("zk.util")
local M = {}
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
if path == "" then
path = vim.fn.getcwd(0)
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
end
return path
end
local function execute_command(path, cmd, args, cb)
local bufnr = 0
lsp.start()
lsp.client().request("workspace/executeCommand", {
command = "zk." .. cmd,
arguments = {
path or resolve_notebook_dir(bufnr),
args,
},
}, function(err, res)
assert(not err, tostring(err))
if res and cb then
cb(res)
end
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)
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)
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)
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)
end
return M

@ -0,0 +1,18 @@
local M = {}
M.defaults = {
lsp = {
auto_attach = {
enabled = true,
filetypes = { "markdown" },
},
config = {
cmd = { "zk", "lsp" },
name = "zk",
},
},
}
M.options = M.defaults
return M

@ -0,0 +1,35 @@
local config = require("zk.config")
local client_id = nil
local M = {}
--- 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.
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
function M.stop()
local client = M.client()
if client then
client.stop()
end
client_id = nil
end
--- Gets the LSP client managed by this plugin, might be nil
function M.client()
return vim.lsp.get_client_by_id(client_id)
end
return M

@ -0,0 +1,36 @@
local lsp = require("zk.lsp")
local config = require("zk.config")
local M = {}
function M.setup_lsp_auto_attach()
--- NOTE: modified version of code in nvim-lspconfig
local trigger
local filetypes = config.options.lsp.auto_attach.filetypes
if filetypes then
trigger = "FileType " .. table.concat(filetypes, ",")
else
trigger = "BufReadPost *"
end
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
end
--- NOTE: No need to manually call this. Automatically called via an |autocmd| if lsp.auto_attach is enabled.
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
return
end
lsp.buf_add(bufnr)
end
return M

@ -0,0 +1 @@
std="vim"

@ -0,0 +1,2 @@
indent_type = "Spaces"
indent_width = 2

@ -0,0 +1,6 @@
[selene]
base = "lua51"
name = "vim"
[vim]
any = true
Loading…
Cancel
Save