Skip to content

Commit

Permalink
feat(capture): Add date prompt expansions (#713)
Browse files Browse the repository at this point in the history
  • Loading branch information
kristijanhusak authored Apr 7, 2024
1 parent 913545d commit 7ea0ca5
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 142 deletions.
8 changes: 8 additions & 0 deletions DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,9 +487,17 @@ Variables:
* `%F`: Like `%f` but inserts the full path
* `%n`: Inserts the current `$USER`
* `%t`: Prints current date (Example: `<2021-06-10 Thu>`)
* `%^t`: Prompt for current date (Example: `<2021-06-10 Thu>`)
* `%^{Name}t`: Prompt for current date for given `Name` (visible in calendar title) (Example: `<2021-06-10 Thu>`)
* `%T`: Prints current date and time (Example: `<2021-06-10 Thu 12:30>`)
* `%^T`: Prompt for current date and time (Example: `<2021-06-10 Thu 12:30>`)
* `%^{Name}T`: Prompt for current date and time for given `Name` (visible in calendar title) (Example: `<2021-06-10 Thu 12:30>`)
* `%u`: Prints current date in inactive format (Example: `[2021-06-10 Thu]`)
* `%^u`: Prompt for current date in inactive format (Example: `[2021-06-10 Thu]`)
* `%^{Name}u`: Prompt for current date in inactive format for given `Name` (visible in calendar title) (Example: `[2021-06-10 Thu]`)
* `%U`: Prints current date and time in inactive format (Example: `[2021-06-10 Thu 12:30]`)
* `%^U`: Prompt for current date and time in inactive format (Example: `[2021-06-10 Thu 12:30]`)
* `%^{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]`)
* `%a`: File and line number from where capture was initiated (Example: `[[file:/home/user/projects/myfile.txt +2]]`)
* `%<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')
* `%x`: Insert content of the clipboard via the "+" register (see :help clipboard)
Expand Down
4 changes: 2 additions & 2 deletions lua/orgmode/agenda/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,9 @@ function Agenda:goto_date()
return utils.echo_error('No available views to jump to date.')
end

return Calendar.new({ date = Date.now() }).open():next(function(date)
return Calendar.new({ date = Date.now(), title = 'Go to agenda date' }):open():next(function(date)
if not date then
return
return nil
end
for _, view in ipairs(views) do
view:goto_date(date)
Expand Down
8 changes: 4 additions & 4 deletions lua/orgmode/api/headline.lua
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ function OrgHeadline:set_deadline(date)
local headline = org.files:get_closest_headline()
local deadline_date = headline:get_deadline_date()
if not date then
return Calendar.new({ date = deadline_date or Date.today(), clearable = true })
.open()
return Calendar.new({ date = deadline_date or Date.today(), clearable = true, title = 'Set deadline' })
:open()
:next(function(new_date, cleared)
if cleared then
return headline:remove_deadline_date()
Expand Down Expand Up @@ -185,8 +185,8 @@ function OrgHeadline:set_scheduled(date)
local headline = org.files:get_closest_headline()
local scheduled_date = headline:get_scheduled_date()
if not date then
return Calendar.new({ date = scheduled_date or Date.today(), clearable = true })
.open()
return Calendar.new({ date = scheduled_date or Date.today(), clearable = true, title = 'Set schedule' })
:open()
:next(function(new_date, cleared)
if cleared then
return headline:remove_scheduled_date()
Expand Down
130 changes: 95 additions & 35 deletions lua/orgmode/capture/template/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,71 @@ local Calendar = require('orgmode.objects.calendar')
local Promise = require('orgmode.utils.promise')

local expansions = {
['%f'] = function()
['%%f'] = function()
return vim.fn.expand('%')
end,
['%F'] = function()
['%%F'] = function()
return vim.fn.expand('%:p')
end,
['%n'] = function()
['%%n'] = function()
return os.getenv('USER')
end,
['%x'] = function()
['%%x'] = function()
return vim.fn.getreg('+')
end,
['%t'] = function()
['%%t'] = function()
return string.format('<%s>', Date.today():to_string())
end,
['%T'] = function()
['%%%^t'] = function()
return Calendar.new({ date = Date.today() }):open():next(function(date)
return date and string.format('<%s>', date:to_string()) or nil
end)
end,
['%%%^%{([^%}]*)%}t'] = function(title)
return Calendar.new({ date = Date.today(), title = title }):open():next(function(date)
return date and string.format('<%s>', date:to_string()) or nil
end)
end,
['%%T'] = function()
return string.format('<%s>', Date.now():to_string())
end,
['%u'] = function()
['%%%^T'] = function()
return Calendar.new({ date = Date.now() }):open():next(function(date)
return date and string.format('<%s>', date:to_string()) or nil
end)
end,
['%%%^%{([^%}]*)%}T'] = function(title)
return Calendar.new({ date = Date.now(), title = title }):open():next(function(date)
return date and string.format('<%s>', date:to_string()) or nil
end)
end,
['%%u'] = function()
return string.format('[%s]', Date.today():to_string())
end,
['%U'] = function()
['%%%^u'] = function()
return Calendar.new({ date = Date.today() }):open():next(function(date)
return date and string.format('[%s]', date:to_string()) or nil
end)
end,
['%%%^%{([^%}]*)%}u'] = function(title)
return Calendar.new({ date = Date.today(), title = title }):open():next(function(date)
return date and string.format('[%s]', date:to_string()) or nil
end)
end,
['%%U'] = function()
return string.format('[%s]', Date.now():to_string())
end,
['%a'] = function()
['%%%^U'] = function()
return Calendar.new({ date = Date.now() }):open():next(function(date)
return date and string.format('[%s]', date:to_string()) or nil
end)
end,
['%%%^%{([^%}]*)%}U'] = function(title)
return Calendar.new({ date = Date.now(), title = title }):open():next(function(date)
return date and string.format('[%s]', date:to_string()) or nil
end)
end,
['%%a'] = function()
return string.format('[[file:%s::%s]]', utils.current_file_path(), vim.api.nvim_win_get_cursor(0)[1])
end,
}
Expand Down Expand Up @@ -210,11 +250,10 @@ end
---@return OrgPromise<string | nil>
function Template:_compile(content, content_type)
content = self:_compile_dates(content)
content = self:_compile_prompts(content)
content = self:_compile_expressions(content)
if self._compile_hooks then
for _, hook in ipairs(self._compile_hooks) do
content = hook(content, content_type)
content = hook(content, content_type) --[[@as string]]
if not content then
return Promise.resolve(nil)
end
Expand All @@ -224,7 +263,12 @@ function Template:_compile(content, content_type)
if not compiled_content then
return nil
end
return self:_compile_expansions(compiled_content)
return self:_compile_expansions(compiled_content):next(function(cnt)
if not cnt then
return nil
end
return self:_compile_prompts(cnt)
end)
end)
end

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

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

---@param content string
---@return OrgPromise<string | nil>
function Template:_compile_expansions(content, found_expansions)
found_expansions = found_expansions or expansions
local promises = {}
function Template:_compile_expansions(content)
local compiled_expansions = {}
local proceed = true
for expansion, compiler in pairs(found_expansions) do
if content:match(vim.pesc(expansion)) then
table.insert(
promises,
Promise.resolve()
:next(function()
return compiler()
end)
:next(function(replacement)
for exp in content:gmatch('%%([^%%]*)') do
for expansion, compiler in pairs(expansions) do
local match = ('%' .. exp):match(expansion)
if match then
table.insert(compiled_expansions, function()
return Promise.resolve(compiler(match)):next(function(replacement)
if not proceed or not replacement then
proceed = false
return
return Promise.reject('canceled')
end
content = content:gsub(vim.pesc(expansion), vim.pesc(replacement))
content = content:gsub(expansion, vim.pesc(replacement))
return content
end)
)
end)
end
end
end
return Promise.all(promises):next(function()
if not proceed then
return nil
end
return content
end)

if #compiled_expansions == 0 then
return Promise.resolve(content)
end

local result = Promise.resolve()
for _, value in ipairs(compiled_expansions) do
result = result:next(function()
return value()
end)
end

return result
:next(function()
if not proceed then
return nil
end
return content
end)
:catch(function(err)
if err == 'canceled' then
return
end
error(err)
end)
end

---@param content string
Expand Down
Loading

0 comments on commit 7ea0ca5

Please sign in to comment.