Skip to content

Commit 93f56ca

Browse files
author
jghauser
committed
feat!: rework commands and keymaps
- Papis has now various subcommands (e.g. "Papis reload") - Keymaps run those commands - Commands and keymaps are set by modules (rather than centrally)
1 parent db1ada5 commit 93f56ca

File tree

7 files changed

+159
-309
lines changed

7 files changed

+159
-309
lines changed

README.md

+19-23
Original file line numberDiff line numberDiff line change
@@ -20,50 +20,50 @@ While papis.nvim is likely buggy, it is equally likely unable to mess with your
2020

2121
A number of features (bundled into `modules`) are shipped with papis.nvim. These can be (de)activated as desired.
2222

23-
### 'search' module
23+
### *Search* module
2424

2525
![search (trimmed)](https://user-images.githubusercontent.com/10319377/193468846-327988b0-de69-4484-887f-e294f1ed8ed8.gif)
2626

2727
Papis.nvim integrates with telescope to easily and quickly search one's bibliography. Open the picker and enter the title (or author, year, etc.) of the article you're looking for. Once you've found it, you can insert a citation, open attached files and notes, and edit the `info.yaml` file. When attempting to open a note where none exists, papis.nvim will ask to create a new one.
2828

2929
Commands:
30-
- `:Telescope papis`: Opens the papis.nvim telescope picker
30+
- `:Papis search`: Opens the papis.nvim telescope picker
3131

3232
With the picker open, the following (currently hardcoded) keymaps become available:
3333
- `of` (normal) / `<c-o>f` (insert): Opens files attached to the entry
3434
- `on` (normal) / `<c-o>n` (insert): Opens notes attached to the entry (asks for the creation of a new one if none exists)
3535
- `e` (normal) / `c-e` (insert): Opens the `info.yaml` file
3636
- `f` (normal) / `c-f` (insert): Insert a formatted reference
3737

38-
### 'completion' module
38+
### *Completion* module
3939

4040
![completion (trimmed)](https://user-images.githubusercontent.com/10319377/193469045-4941bb6d-3582-4ad0-9e29-249ddc8aae46.gif)
4141

4242
When editing `tags` in `info.yaml` files, papis.nvim will suggest tags found in the database. This module is implemented as a [nvim-cmp](https://github.com/hrsh7th/nvim-cmp) source.
4343

44-
### 'cursor-actions' module
44+
### *At-cursor* module
4545

46-
![cursor-actions (trimmed)](https://user-images.githubusercontent.com/10319377/193468973-3755f5b9-e2bb-4de9-900c-bf130ea09bad.gif)
46+
![at-cursor (trimmed)](https://user-images.githubusercontent.com/10319377/193468973-3755f5b9-e2bb-4de9-900c-bf130ea09bad.gif)
4747

4848
When the cursor is positioned over a citation key (e.g. `Kant1781Critique`), papis.nvim allows you to interact with the bibliography item referenced by it.
4949

5050
Commands:
51-
- `:PapisShowPopup`: Opens a floating window with information about the entry
52-
- `:PapisOpenFile`: Opens files attached to the entry
53-
- `:PapisOpenNote`: Opens notes attached to the entry (asks for the creation of a new one if none exists)
54-
- `:PapisEditEntry`: Opens the `info.yaml` file
51+
- `:Papis at-cursor show-popup`: Opens a floating window with information about the entry
52+
- `:Papis at-cursor open-file`: Opens files attached to the entry
53+
- `:Papis at-cursor open-note`: Opens notes attached to the entry (asks for the creation of a new one if none exists)
54+
- `:Papis at-cursor edit`: Opens the `info.yaml` file
5555

56-
### 'formatter' module
56+
### *Formatter* module
5757

5858
![formatter_trimmed](https://user-images.githubusercontent.com/10319377/193469179-35e1a3b5-bad6-4289-a9ae-586dc9b3af8a.gif)
5959

60-
When creating new notes (via `:Telescope papis` or `:PapisOpenNote`), papis.nvim can be set up to format the new note with a custom function. You can, for example, give the note a title that corresponds to the entry's title or provide it with a skeleton structure. Below, in the setup section, there's an example suitable for the `markdown` format.
60+
When creating new notes (via `:Papis search` or `:Papis at-cursor open-note`), papis.nvim can be set up to format the new note with a custom function. You can, for example, give the note a title that corresponds to the entry's title or provide it with a skeleton structure. Below, in the setup section, there's an example suitable for the `markdown` format.
6161

6262
## The database
6363

6464
All of papis.nvim's features are made possible by a sqlite database that is created when the plugin is first started. This might take a while, so be patient. From then on, the database is automatically (and very quickly) updated whenever `info.yaml` files are added, changed, or deleted. The database is synchronised when papis.nvim is started and is then kept up-to-date continuously while at least one neovim instance with a running papis.nvim session exists.
6565

66-
Note that fiddling with the plugin's options can leave the database in a messy state. If strange errors appear, use `:PapisReInitData` to re-initialise the database.
66+
Note that fiddling with the plugin's options can leave the database in a messy state. If strange errors appear, use `:Papis reload data` to re-initialise the database.
6767

6868
## Installation
6969

@@ -160,7 +160,7 @@ The `flake.nix` provides an overlay that can be used to install `papis.nvim`. Wi
160160
home-manager.url = "github:nix-community/home-manager";
161161
papis-nvim.url = "github:jghauser/papis.nvim";
162162
};
163-
outputs = { self, nixpkgs, home-manager, neorg, ... }: {
163+
outputs = { self, nixpkgs, home-manager, ... }: {
164164
nixosConfigurations.machine = nixpkgs.lib.nixosSystem {
165165
system = "x86_64-linux";
166166
modules = [
@@ -213,7 +213,7 @@ require("papis").setup({
213213
enable_modules = {
214214
["search"] = true, -- Enables/disables the search module
215215
["completion"] = true, -- Enables/disables the completion module
216-
["cursor-actions"] = true, -- Enables/disables the cursor-actions module
216+
["at-cursor"] = true, -- Enables/disables the at-cursor module
217217
["formatter"] = true, -- Enables/disables the formatter module
218218
["colors"] = true, -- Enables/disables default highlight groups (you
219219
-- probably want this)
@@ -225,7 +225,7 @@ enable_modules = {
225225

226226
-- Defines citation formats for various filetypes. When the value is a table, then
227227
-- the first entry is used to insert citations, whereas the second will be used to
228-
-- find references (e.g. by the `cursor-action` module). `%s` stands for the reference.
228+
-- find references (e.g. by the `at-cursor` module). `%s` stands for the reference.
229229
-- Note that the first entry is a string (where e.g. `\` needs to be excaped as `\\`)
230230
-- and the second a lua pattern (where magic characters need to be escaped with
231231
-- `%`; https://www.lua.org/pil/20.2.html).
@@ -244,10 +244,6 @@ cite_formats_fallback = "plain",
244244
-- Enable default keymaps.
245245
enable_keymaps = false,
246246

247-
-- Enable commands (disabling this still allows you to call the relevant lua
248-
-- functions directly)
249-
enable_commands = true,
250-
251247
-- Whether to enable the file system event watcher. When disabled, the database
252248
-- is only updated on startup.
253249
enable_fs_watcher = true,
@@ -357,10 +353,10 @@ enable_icons = true,
357353
},
358354
},
359355

360-
-- Configuration of the cursor-actions module.
361-
["cursor-actions"] = {
356+
-- Configuration of the at-cursor module.
357+
["at-cursor"] = {
362358

363-
-- The format of the popup shown on `:PapisShowPopup` (equivalent to points 1-3
359+
-- The format of the popup shown on `:Papis at-cursor show-popup` (equivalent to points 1-3
364360
-- of `preview_format`)
365361
popup_format = {
366362
{ "author", "%s", "PapisPopupAuthor" },
@@ -464,7 +460,7 @@ cmp.setup({
464460

465461
## Usage
466462

467-
Papis.nvim will start automatically according to the filetypes defined in `init_filetypes` (see the [setup section](#setup)). When first starting, papis.nvim will import some configuration values from Papis and save them in the database. If you update your Papis configuration, you should re-import the configuration into papis.nvim with `:PapisReInitConfig`.
463+
Papis.nvim will start automatically according to the filetypes defined in `init_filetypes` (see the [setup section](#setup)). When first starting, papis.nvim will import some configuration values from Papis and save them in the database. If you update your Papis configuration, you should re-import the configuration into papis.nvim with `:Papis reload config`.
468464

469465
## Keymaps
470466

lua/papis/commands.lua

+84-85
Original file line numberDiff line numberDiff line change
@@ -4,100 +4,99 @@
44
--
55
-- Sets up default commands.
66
--
7+
-- Adapted from https://github.com/nvim-neorocks/nvim-best-practices
78

89
local config = require("papis.config")
9-
local api = vim.api
1010

11-
local commands = {
12-
["base"] = {
13-
reinit_data = {
14-
name = "PapisReInitData",
15-
command = function()
16-
require("papis.data"):reset_db()
17-
end,
18-
opts = { desc = "Papis: empty and repopulate the sqlite database from disk" },
19-
},
20-
reinit_papis_py_config = {
21-
name = "PapisReInitConfig",
22-
command = function()
11+
---@class PapisSubcommand
12+
---@field impl fun(args:string[], opts: table) The command implementation
13+
---@field complete? fun(subcmd_arg_lead: string): string[] (optional) Command completions callback, taking the lead of the subcommand's arguments
14+
---@type table<string, PapisSubcommand>
15+
local subcommand_tbl = {
16+
reload = {
17+
impl = function(args, _)
18+
-- Implementation (args is a list of strings)
19+
if args[1] == "config" then
2320
config:update_papis_py_conf()
24-
end,
25-
opts = { desc = "Papis: import configuration from Papis" },
26-
},
27-
},
28-
["debug"] = {
29-
stop_fw = {
30-
name = "PapisDebugFWStop",
31-
command = function()
32-
require("papis.fs-watcher").stop()
33-
end,
34-
opts = { desc = "Papis: stop file watching" },
35-
},
36-
start_fw = {
37-
name = "PapisDebugFWStart",
38-
command = function()
39-
require("papis.fs-watcher").start()
40-
end,
41-
opts = { desc = "Papis: start file watching" },
42-
},
43-
get_log_path = {
44-
name = "PapisDebugGetLogPath",
45-
command = function()
46-
require("papis.log").get_path()
47-
end,
48-
opts = { desc = "Papis: get path to the log file" },
49-
},
50-
},
51-
["cursor-actions"] = {
52-
open_file = {
53-
name = "PapisOpenFile",
54-
command = function()
55-
return require("papis.cursor-actions").open_file()
56-
end,
57-
opts = { desc = "Papis: open the files attached to entry under cursor" },
58-
},
59-
open_note = {
60-
name = "PapisOpenNote",
61-
command = function()
62-
return require("papis.cursor-actions").open_note()
63-
end,
64-
opts = { desc = "Papis: open the note of the entry under cursor" },
65-
},
66-
edit_entry = {
67-
name = "PapisEditEntry",
68-
command = function()
69-
return require("papis.cursor-actions").edit_entry()
70-
end,
71-
opts = { desc = "Papis: edit the entry under cursor" },
72-
},
73-
show_popup = {
74-
name = "PapisShowPopup",
75-
command = function()
76-
return require("papis.cursor-actions").show_popup()
77-
end,
78-
opts = { desc = "Papis: show popup of the entry under cursor" },
79-
},
21+
elseif args[1] == "data" then
22+
require("papis.data"):reset_db()
23+
end
24+
end,
25+
complete = function(subcmd_arg_lead)
26+
-- Simplified example
27+
local reload_args = {
28+
"config",
29+
"data",
30+
}
31+
return vim.iter(reload_args)
32+
:filter(function(install_arg)
33+
-- If the user has typed `:Papis reload co`,
34+
-- this will match 'config'
35+
return install_arg:find(subcmd_arg_lead) ~= nil
36+
end)
37+
:totable()
38+
end,
8039
},
8140
}
8241

83-
local M = {}
42+
---Main Papis command
43+
---@param opts table
44+
local function papis_cmd(opts)
45+
local fargs = opts.fargs
46+
local subcommand_key = fargs[1]
47+
-- Get the subcommand's arguments, if any
48+
local args = #fargs > 1 and vim.list_slice(fargs, 2, #fargs) or {}
49+
local subcommand = subcommand_tbl[subcommand_key]
50+
if not subcommand then
51+
vim.notify("Papis: Unknown command: " .. subcommand_key, vim.log.levels.ERROR)
52+
return
53+
end
54+
-- Invoke the subcommand
55+
subcommand.impl(args, opts)
56+
end
8457

85-
---Sets up either the commands of all enabled modules or of a given module
86-
---@param module? string #Name of the module to be set up
87-
function M.setup(module)
88-
if not module then
89-
for module_name, module_commands in pairs(commands) do
90-
if config["enable_modules"][module_name] then
91-
for _, command in pairs(module_commands) do
92-
api.nvim_buf_create_user_command(0, command["name"], command["command"], command["opts"])
93-
end
58+
---Creates the main Papis command
59+
local function create_command()
60+
-- NOTE: the options will vary, based on your use case.
61+
vim.api.nvim_create_user_command("Papis", papis_cmd, {
62+
nargs = "+",
63+
desc = "Papis main command (with subcommands)",
64+
complete = function(arg_lead, cmdline, _)
65+
-- Get the subcommand.
66+
local subcmd_key, subcmd_arg_lead = cmdline:match("^['<,'>]*Papis[!]*%s(%S+)%s(.*)$")
67+
if subcmd_key
68+
and subcmd_arg_lead
69+
and subcommand_tbl[subcmd_key]
70+
and subcommand_tbl[subcmd_key].complete
71+
then
72+
-- The subcommand has completions. Return them.
73+
return subcommand_tbl[subcmd_key].complete(subcmd_arg_lead)
9474
end
95-
end
96-
else
97-
for _, command in pairs(commands[module]) do
98-
api.nvim_buf_create_user_command(0, command["name"], command["command"], command["opts"])
99-
end
100-
end
75+
-- Check if cmdline is a subcommand
76+
if cmdline:match("^['<,'>]*Papis[!]*%s+%w*$") then
77+
-- Filter subcommands that match
78+
local subcommand_keys = vim.tbl_keys(subcommand_tbl)
79+
return vim.iter(subcommand_keys)
80+
:filter(function(key)
81+
return key:find(arg_lead) ~= nil
82+
end)
83+
:totable()
84+
end
85+
end,
86+
})
87+
end
88+
89+
local M = {}
90+
91+
---Sets up main "Papis" command
92+
function M.setup()
93+
create_command()
94+
end
95+
96+
--- Recursively merges the provided table with the subcommand_tbl table.
97+
---@param module_subcommand table #A table with a module's commands
98+
function M:add_commands(module_subcommand)
99+
subcommand_tbl = vim.tbl_extend("force", subcommand_tbl, module_subcommand)
101100
end
102101

103102
return M

lua/papis/config.lua

+2-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
-- default configuration values
99
local default_config = {
1010
enable_modules = {
11-
["cursor-actions"] = true,
11+
["at-cursor"] = true,
1212
["search"] = true,
1313
["completion"] = true,
1414
["formatter"] = true,
@@ -28,7 +28,6 @@ local default_config = {
2828
cite_formats_fallback = "plain",
2929
always_use_plain = false,
3030
enable_keymaps = false,
31-
enable_commands = true,
3231
enable_fs_watcher = true,
3332
data_tbl_schema = { -- only "text" and "luatable" are allowed
3433
id = { "integer", pk = true },
@@ -104,7 +103,7 @@ local default_config = {
104103
return table.concat(reference_data)
105104
end,
106105
},
107-
["cursor-actions"] = {
106+
["at-cursor"] = {
108107
popup_format = {
109108
{ "author", "%s", "PapisPopupAuthor" },
110109
{ "year", "%s", "PapisPopupYear" },

0 commit comments

Comments
 (0)