Skip to content

Commit c17ba5d

Browse files
feat(capture): Add date prompt expansions
1 parent 913545d commit c17ba5d

File tree

7 files changed

+247
-142
lines changed

7 files changed

+247
-142
lines changed

Diff for: DOCS.md

+8
Original file line numberDiff line numberDiff line change
@@ -487,9 +487,17 @@ Variables:
487487
* `%F`: Like `%f` but inserts the full path
488488
* `%n`: Inserts the current `$USER`
489489
* `%t`: Prints current date (Example: `<2021-06-10 Thu>`)
490+
* `%^t`: Prompt for current date (Example: `<2021-06-10 Thu>`)
491+
* `%^{Name}t`: Prompt for current date for given `Name` (visible in calendar title) (Example: `<2021-06-10 Thu>`)
490492
* `%T`: Prints current date and time (Example: `<2021-06-10 Thu 12:30>`)
493+
* `%^T`: Prompt for current date and time (Example: `<2021-06-10 Thu 12:30>`)
494+
* `%^{Name}T`: Prompt for current date and time for given `Name` (visible in calendar title) (Example: `<2021-06-10 Thu 12:30>`)
491495
* `%u`: Prints current date in inactive format (Example: `[2021-06-10 Thu]`)
496+
* `%^u`: Prompt for current date in inactive format (Example: `[2021-06-10 Thu]`)
497+
* `%^{Name}u`: Prompt for current date in inactive format for given `Name` (visible in calendar title) (Example: `[2021-06-10 Thu]`)
492498
* `%U`: Prints current date and time in inactive format (Example: `[2021-06-10 Thu 12:30]`)
499+
* `%^U`: Prompt for current date and time in inactive format (Example: `[2021-06-10 Thu 12:30]`)
500+
* `%^{Name}U`: Prompt for current date and time in inactive format for given `Name` (visible in calendar title) (Example: `[2021-06-10 Thu 12:30]`)
493501
* `%a`: File and line number from where capture was initiated (Example: `[[file:/home/user/projects/myfile.txt +2]]`)
494502
* `%<FORMAT>`: Insert current date/time formatted according to [lua date](https://www.lua.org/pil/22.1.html) format (Example: `%<%Y-%m-%d %A>` produces '2021-07-02 Friday')
495503
* `%x`: Insert content of the clipboard via the "+" register (see :help clipboard)

Diff for: lua/orgmode/agenda/init.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,9 @@ function Agenda:goto_date()
220220
return utils.echo_error('No available views to jump to date.')
221221
end
222222

223-
return Calendar.new({ date = Date.now() }).open():next(function(date)
223+
return Calendar.new({ date = Date.now(), title = 'Go to agenda date' }):open():next(function(date)
224224
if not date then
225-
return
225+
return nil
226226
end
227227
for _, view in ipairs(views) do
228228
view:goto_date(date)

Diff for: lua/orgmode/api/headline.lua

+4-4
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ function OrgHeadline:set_deadline(date)
145145
local headline = org.files:get_closest_headline()
146146
local deadline_date = headline:get_deadline_date()
147147
if not date then
148-
return Calendar.new({ date = deadline_date or Date.today(), clearable = true })
149-
.open()
148+
return Calendar.new({ date = deadline_date or Date.today(), clearable = true, title = 'Set deadline' })
149+
:open()
150150
:next(function(new_date, cleared)
151151
if cleared then
152152
return headline:remove_deadline_date()
@@ -185,8 +185,8 @@ function OrgHeadline:set_scheduled(date)
185185
local headline = org.files:get_closest_headline()
186186
local scheduled_date = headline:get_scheduled_date()
187187
if not date then
188-
return Calendar.new({ date = scheduled_date or Date.today(), clearable = true })
189-
.open()
188+
return Calendar.new({ date = scheduled_date or Date.today(), clearable = true, title = 'Set schedule' })
189+
:open()
190190
:next(function(new_date, cleared)
191191
if cleared then
192192
return headline:remove_scheduled_date()

Diff for: lua/orgmode/capture/template/init.lua

+95-35
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,71 @@ local Calendar = require('orgmode.objects.calendar')
55
local Promise = require('orgmode.utils.promise')
66

77
local expansions = {
8-
['%f'] = function()
8+
['%%f'] = function()
99
return vim.fn.expand('%')
1010
end,
11-
['%F'] = function()
11+
['%%F'] = function()
1212
return vim.fn.expand('%:p')
1313
end,
14-
['%n'] = function()
14+
['%%n'] = function()
1515
return os.getenv('USER')
1616
end,
17-
['%x'] = function()
17+
['%%x'] = function()
1818
return vim.fn.getreg('+')
1919
end,
20-
['%t'] = function()
20+
['%%t'] = function()
2121
return string.format('<%s>', Date.today():to_string())
2222
end,
23-
['%T'] = function()
23+
['%%%^t'] = function()
24+
return Calendar.new({ date = Date.today() }):open():next(function(date)
25+
return date and string.format('<%s>', date:to_string()) or nil
26+
end)
27+
end,
28+
['%%%^%{([^%}]*)%}t'] = function(title)
29+
return Calendar.new({ date = Date.today(), title = title }):open():next(function(date)
30+
return date and string.format('<%s>', date:to_string()) or nil
31+
end)
32+
end,
33+
['%%T'] = function()
2434
return string.format('<%s>', Date.now():to_string())
2535
end,
26-
['%u'] = function()
36+
['%%%^T'] = function()
37+
return Calendar.new({ date = Date.now() }):open():next(function(date)
38+
return date and string.format('<%s>', date:to_string()) or nil
39+
end)
40+
end,
41+
['%%%^%{([^%}]*)%}T'] = function(title)
42+
return Calendar.new({ date = Date.now(), title = title }):open():next(function(date)
43+
return date and string.format('<%s>', date:to_string()) or nil
44+
end)
45+
end,
46+
['%%u'] = function()
2747
return string.format('[%s]', Date.today():to_string())
2848
end,
29-
['%U'] = function()
49+
['%%%^u'] = function()
50+
return Calendar.new({ date = Date.today() }):open():next(function(date)
51+
return date and string.format('[%s]', date:to_string()) or nil
52+
end)
53+
end,
54+
['%%%^%{([^%}]*)%}u'] = function(title)
55+
return Calendar.new({ date = Date.today(), title = title }):open():next(function(date)
56+
return date and string.format('[%s]', date:to_string()) or nil
57+
end)
58+
end,
59+
['%%U'] = function()
3060
return string.format('[%s]', Date.now():to_string())
3161
end,
32-
['%a'] = function()
62+
['%%%^U'] = function()
63+
return Calendar.new({ date = Date.now() }):open():next(function(date)
64+
return date and string.format('[%s]', date:to_string()) or nil
65+
end)
66+
end,
67+
['%%%^%{([^%}]*)%}U'] = function(title)
68+
return Calendar.new({ date = Date.now(), title = title }):open():next(function(date)
69+
return date and string.format('[%s]', date:to_string()) or nil
70+
end)
71+
end,
72+
['%%a'] = function()
3373
return string.format('[[file:%s::%s]]', utils.current_file_path(), vim.api.nvim_win_get_cursor(0)[1])
3474
end,
3575
}
@@ -210,11 +250,10 @@ end
210250
---@return OrgPromise<string | nil>
211251
function Template:_compile(content, content_type)
212252
content = self:_compile_dates(content)
213-
content = self:_compile_prompts(content)
214253
content = self:_compile_expressions(content)
215254
if self._compile_hooks then
216255
for _, hook in ipairs(self._compile_hooks) do
217-
content = hook(content, content_type)
256+
content = hook(content, content_type) --[[@as string]]
218257
if not content then
219258
return Promise.resolve(nil)
220259
end
@@ -224,7 +263,12 @@ function Template:_compile(content, content_type)
224263
if not compiled_content then
225264
return nil
226265
end
227-
return self:_compile_expansions(compiled_content)
266+
return self:_compile_expansions(compiled_content):next(function(cnt)
267+
if not cnt then
268+
return nil
269+
end
270+
return self:_compile_prompts(cnt)
271+
end)
228272
end)
229273
end
230274

@@ -241,7 +285,7 @@ function Template:_compile_datetree(content, content_type)
241285
return Promise.resolve(content)
242286
end
243287

244-
return Calendar.new({ date = Date.now() }):open():next(function(date)
288+
return Calendar.new({ date = Date.now(), title = 'Select datetree date' }):open():next(function(date)
245289
if date then
246290
self.datetree.date = date
247291
return content
@@ -252,34 +296,50 @@ end
252296

253297
---@param content string
254298
---@return OrgPromise<string | nil>
255-
function Template:_compile_expansions(content, found_expansions)
256-
found_expansions = found_expansions or expansions
257-
local promises = {}
299+
function Template:_compile_expansions(content)
300+
local compiled_expansions = {}
258301
local proceed = true
259-
for expansion, compiler in pairs(found_expansions) do
260-
if content:match(vim.pesc(expansion)) then
261-
table.insert(
262-
promises,
263-
Promise.resolve()
264-
:next(function()
265-
return compiler()
266-
end)
267-
:next(function(replacement)
302+
for exp in content:gmatch('%%([^%%]*)') do
303+
for expansion, compiler in pairs(expansions) do
304+
local match = ('%' .. exp):match(expansion)
305+
if match then
306+
table.insert(compiled_expansions, function()
307+
return Promise.resolve(compiler(match)):next(function(replacement)
268308
if not proceed or not replacement then
269-
proceed = false
270-
return
309+
return Promise.reject('canceled')
271310
end
272-
content = content:gsub(vim.pesc(expansion), vim.pesc(replacement))
311+
content = content:gsub(expansion, vim.pesc(replacement))
312+
return content
273313
end)
274-
)
314+
end)
315+
end
275316
end
276317
end
277-
return Promise.all(promises):next(function()
278-
if not proceed then
279-
return nil
280-
end
281-
return content
282-
end)
318+
319+
if #compiled_expansions == 0 then
320+
return Promise.resolve(content)
321+
end
322+
323+
local result = Promise.resolve()
324+
for _, value in ipairs(compiled_expansions) do
325+
result = result:next(function()
326+
return value()
327+
end)
328+
end
329+
330+
return result
331+
:next(function()
332+
if not proceed then
333+
return nil
334+
end
335+
return content
336+
end)
337+
:catch(function(err)
338+
if err == 'canceled' then
339+
return
340+
end
341+
error(err)
342+
end)
283343
end
284344

285345
---@param content string

0 commit comments

Comments
 (0)