Skip to content

refactor: captures #613

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Oct 26, 2023
68 changes: 52 additions & 16 deletions DOCS.md
Original file line number Diff line number Diff line change
@@ -412,6 +412,16 @@ Variables:
* `%^{PROMPT|DEFAULT|COMPLETION...}`: Prompt for input, if completion is provided an :h inputlist will be used
* `%(EXP)`: Runs the given lua code and inserts the result. NOTE: this will internally pass the content to the lua `load()` function. So the body inside `%()` should be the body of a function that returns a string.

Templates have the following fields:
* `description` (`string`) — description of the template that is displayed in the template selection menu
* `template` (`string|string[]`) — body of the template that will be used when creating capture
* `target` (`string?`) — name of the file to which the capture content will be added. If the target is not specified, the content will be added to the [`org_default_notes_file`](#orgdefaultnotesfile) file
* `headline` (`string?`) — title of the headline after which the capture content will be added. If no headline is specified, the content will be appended to the end of the file
* `properties` (`table?`):
* `empty_lines` (`table|number?`) — if the value is a number, then empty lines are added before and after the content. If the value is a table, then the following fields are expected:
* `before` (`integer?`) — add empty lines to the beginning of the content
* `after` (`integer?`) — add empty lines to the end of the content

Example:<br />
```lua
{ T = {
@@ -423,20 +433,24 @@ Example:<br />

Journal example:<br />
```lua
{ j = {
description = 'Journal',
template = '\n*** %<%Y-%m-%d> %<%A>\n**** %U\n\n%?',
target = '~/sync/org/journal.org'
} }
{
j = {
description = 'Journal',
template = '\n*** %<%Y-%m-%d> %<%A>\n**** %U\n\n%?',
target = '~/sync/org/journal.org'
},
}
```

Journal example with dynamic target, i.e. a separate file per month:<br />
```lua
{ J = {
description = 'Journal',
template = '\n*** %<%Y-%m-%d> %<%A>\n**** %U\n\n%?',
target = '~/sync/org/journal/%<%Y-%m>.org'
} }
{
J = {
description = 'Journal',
template = '\n*** %<%Y-%m-%d> %<%A>\n**** %U\n\n%?',
target = '~/sync/org/journal/%<%Y-%m>.org'
},
}
```

Nested key example:<br />
@@ -456,16 +470,38 @@ Nested key example:<br />
headline = 'one-time'
}
}
-- or
{
e = {
description = 'Event',
subtemplates = {
r = {
description = 'recurring',
template = '** %?\n %T',
target = '~/org/calendar.org',
headline = 'recurring'
},
o = {
description = 'one-time',
template = '** %?\n %T',
target = '~/org/calendar.org',
headline = 'one-time'
},
},
},
}
```

Lua expression example:<br />
```lua
{ j = {
description = 'Journal',
template = '* %(return vim.fn.getreg "w")',
-- get the content of register "w"
target = '~/sync/org/journal.org'
} }
{
j = {
description = 'Journal',
template = '* %(return vim.fn.getreg "w")',
-- get the content of register "w"
target = '~/sync/org/journal.org'
},
}
```

#### **org_agenda_min_height**
216 changes: 146 additions & 70 deletions lua/orgmode/capture/init.lua
Original file line number Diff line number Diff line change
@@ -3,8 +3,18 @@ local config = require('orgmode.config')
local Files = require('orgmode.parser.files')
local File = require('orgmode.parser.file')
local Templates = require('orgmode.capture.templates')
local Template = require('orgmode.capture.template')
local ClosingNote = require('orgmode.capture.closing_note')
local Menu = require('orgmode.ui.menu')
local Range = require('orgmode.parser.range')

---@class CaptureOpts
---@field file string
---@field range Range
---@field lines string[]
---@field template Template?
---@field headline string?
---@field item Section?

---@class Capture
---@field templates Templates
@@ -20,6 +30,8 @@ function Capture:new()
return data
end

---@param base_key string
---@param templates table<string, Template>
function Capture:_get_subtemplates(base_key, templates)
local subtemplates = {}
for key, template in pairs(templates) do
@@ -30,6 +42,7 @@ function Capture:_get_subtemplates(base_key, templates)
return subtemplates
end

---@param templates table<string, Template>
function Capture:_create_menu_items(templates)
local menu_items = {}
for key, template in pairs(templates) do
@@ -42,6 +55,11 @@ function Capture:_create_menu_items(templates)
item.action = function()
self:_create_prompt(self:_get_subtemplates(key, templates))
end
elseif vim.tbl_count(template.subtemplates) > 0 then
item.label = template.description .. '...'
item.action = function()
self:_create_prompt(template.subtemplates)
end
else
item.label = template.description
item.action = function()
@@ -54,6 +72,7 @@ function Capture:_create_menu_items(templates)
return menu_items
end

---@param templates table<string, Template>
function Capture:_create_prompt(templates)
local menu = Menu:new({
title = 'Select a capture template',
@@ -79,8 +98,9 @@ function Capture:open_template(template)
self._close_tmp = utils.open_tmp_org_window(16, config.win_split_mode, config.win_border, on_close)
vim.api.nvim_buf_set_lines(0, 0, -1, true, content)
self.templates:setup()
vim.api.nvim_buf_set_var(0, 'org_template', template)
vim.api.nvim_buf_set_var(0, 'org_capture', true)

vim.b.org_template = template
vim.b.org_capture = true
config:setup_mappings('capture')
end

@@ -97,23 +117,22 @@ end
---@param confirm? boolean
function Capture:refile(confirm)
local is_modified = vim.bo.modified
local file, lines, item, template = self:_get_refile_vars()
if not file then
local opts = self:_get_refile_vars()
if not opts.file then
return
end
local headline_title = template.headline
if confirm and is_modified then
local choice = vim.fn.confirm(string.format('Do you want to refile this to %s?', file), '&Yes\n&No')
local choice = vim.fn.confirm(string.format('Do you want to refile this to %s?', opts.file), '&Yes\n&No')
vim.cmd([[redraw!]])
if choice ~= 1 then
return utils.echo_info('Canceled.')
end
end
vim.defer_fn(function()
if headline_title then
self:refile_to_headline(file, lines, item, headline_title)
if opts.headline then
self:refile_to_headline(opts)
else
self:_refile_to_end(file, lines, item)
self:_refile_to_end(opts)
end

if not confirm then
@@ -124,25 +143,26 @@ end

---Triggered when refiling to destination from capture buffer
function Capture:refile_to_destination()
local file, lines, item = self:_get_refile_vars()
if not file then
local opts = self:_get_refile_vars()
if not opts.file then
return
end
self:_refile_content_with_fallback(lines, file, item)
self:_refile_content_with_fallback(opts)
self:kill()
end

---@private
---@return CaptureOpts
function Capture:_get_refile_vars()
local template = vim.api.nvim_buf_get_var(0, 'org_template') or {}
local template = vim.b.org_template or {}
local target = self.templates:compile_target(template.target or config.org_default_notes_file)
local file = vim.fn.resolve(vim.fn.fnamemodify(target, ':p'))

if vim.fn.filereadable(file) == 0 then
local choice = vim.fn.confirm(('Refile destination %s does not exist. Create now?'):format(file), '&Yes\n&No')
if choice ~= 1 then
utils.echo_error('Cannot proceed without a valid refile destination')
return
return {}
end
vim.fn.mkdir(vim.fn.fnamemodify(file, ':h'), 'p')
vim.fn.writefile({}, file)
@@ -154,48 +174,55 @@ function Capture:_get_refile_vars()
item = org_file:get_headlines()[1]
end

return file, lines, item, template
return {
file = file,
lines = lines,
item = item,
template = template,
headline = template.headline,
}
end

---Triggered from org file when we want to refile headline
function Capture:refile_headline_to_destination()
local destination_file = Files.get_current_file()
local item = destination_file:get_closest_headline()
if not item then
return
end
local lines = destination_file:get_headline_lines(item)
return self:_refile_content_with_fallback(lines, nil, item)
return self:_refile_content_with_fallback({
lines = lines,
item = item,
template = Template:new(),
})
end

---@param file File
---@param item string
---@param archive_file string
---@return string
function Capture:refile_file_headline_to_archive(file, item, archive_file)
local lines = file:get_headline_lines(item)
return self:_refile_to_end(archive_file, lines, item, string.format('Archived to %s', archive_file))
---@param opts CaptureOpts
---@return boolean
function Capture:refile_file_headline_to_archive(opts)
opts.message = string.format('Archived to %s', opts.file)
return self:_refile_to_end(opts)
end

---@private
---@param file string
---@param lines string[]
---@param item? Section
---@param message? string
---@param opts CaptureOpts
---@return boolean
function Capture:_refile_to_end(file, lines, item, message)
local refiled = self:_refile_to(file, lines, item, '$')
function Capture:_refile_to_end(opts)
opts.range = Range.from_line(-1)
local refiled = self:_refile_to(opts)
if not refiled then
return false
end
utils.echo_info(message or string.format('Wrote %s', file))
utils.echo_info(opts.message or string.format('Wrote %s', opts.file))
return true
end

---@private
---@param lines string[]
---@param fallback_file string
---@param item? Section
---@return string
function Capture:_refile_content_with_fallback(lines, fallback_file, item)
local default_file = fallback_file and fallback_file ~= '' and vim.fn.fnamemodify(fallback_file, ':p') or nil
---@param opts CaptureOpts
---@return boolean
function Capture:_refile_content_with_fallback(opts)
local default_file = opts.file and opts.file ~= '' and vim.fn.fnamemodify(opts.file, ':p') or nil

local valid_destinations = {}
for _, file in ipairs(Files.filenames()) do
@@ -210,79 +237,125 @@ function Capture:_refile_content_with_fallback(lines, fallback_file, item)
utils.echo_error(
"'" .. destination[1] .. "' is not a file specified in the 'org_agenda_files' setting. Refiling cancelled."
)
return
return false
end
return self:_refile_to_end(default_file, lines, item)
opts.file = default_file
return self:_refile_to_end(opts)
end

local destination_file = valid_destinations[destination[1]]
local destination_headline = table.concat({ unpack(destination, 2) }, '/')
if not destination_headline or destination_headline == '' then
return self:_refile_to_end(destination_file, lines, item)
opts.file = valid_destinations[destination[1]]
opts.headline = table.concat({ unpack(destination, 2) }, '/')
if not opts.headline or opts.headline == '' then
return self:_refile_to_end(opts)
end
return self:refile_to_headline(destination_file, lines, item, destination_headline)
return self:refile_to_headline(opts)
end

---@param destination_filename string
---@param lines string[]
---@param item? Section
---@param headline_title? string
function Capture:refile_to_headline(destination_filename, lines, item, headline_title)
local destination_file = Files.get(destination_filename)
---@param opts CaptureOpts
function Capture:refile_to_headline(opts)
local destination_file = Files.get(opts.file)
local headline
if headline_title then
headline = destination_file:find_headline_by_title(headline_title, true)
if opts.headline then
headline = destination_file:find_headline_by_title(opts.headline, true)

if not headline then
utils.echo_error(
"headline '" .. headline_title .. "' does not exist in '" .. destination_filename .. "'. Aborted refiling."
)
utils.echo_error("headline '" .. opts.headline .. "' does not exist in '" .. opts.file .. "'. Aborted refiling.")
return false
end
end

local item = opts.item
if item then
-- Refiling in same file just moves the lines from one position
-- to another,so we need to apply demote instantly
local is_same_file = destination_file.filename == item.root.filename
if item.level <= headline.level then
lines = item:demote(headline.level - item.level + 1, true, not is_same_file)
opts.lines = item:demote(headline.level - item.level + 1, true, not is_same_file)
else
lines = item:promote(item.level - headline.level - 1, true, not is_same_file)
opts.lines = item:promote(item.level - headline.level - 1, true, not is_same_file)
end
end

local refiled = self:_refile_to(destination_filename, lines, item, headline.range.end_line)
opts.range = Range.from_line(headline.range.end_line)
local refiled = self:_refile_to(opts)
if not refiled then
return false
end
utils.echo_info(string.format('Wrote %s', destination_filename))
utils.echo_info(string.format('Wrote %s', opts.file))
return true
end

---@param opts CaptureOpts
local function add_empty_lines(opts)
local empty_lines = opts.template.properties.empty_lines

for _ = 1, empty_lines.before do
table.insert(opts.lines, 1, '')
end

for _ = 1, empty_lines.after do
table.insert(opts.lines, '')
end
end

---@param opts CaptureOpts
local function apply_properties(opts)
if opts.template then
add_empty_lines(opts)
end
end

local function remove_buffer_empty_lines(opts)
local line_count = vim.api.nvim_buf_line_count(0)
local range = opts.range

local end_line = range.end_line
if end_line < 0 then
end_line = end_line + line_count + 1
end

local start_line = end_line - 1

local is_line_empty = function(row)
local line = vim.api.nvim_buf_get_lines(0, row, row + 1, true)[1]
line = vim.trim(line)
return #line == 0
end

while start_line >= 0 and is_line_empty(start_line) do
start_line = start_line - 1
end
start_line = start_line + 1

while end_line < line_count and is_line_empty(end_line) do
end_line = end_line + 1
end

range.start_line = start_line
range.end_line = end_line
end

---@private
---@param file string
---@param lines string[]
---@param item? Section
---@param destination_line string|number
---@param opts CaptureOpts
---@return boolean
function Capture:_refile_to(file, lines, item, destination_line)
if not file then
function Capture:_refile_to(opts)
if not opts.file then
return false
end

local is_same_file = file == utils.current_file_path()
apply_properties(opts)

local is_same_file = opts.file == utils.current_file_path()
local cur_win = vim.api.nvim_get_current_win()

local item = opts.item
if is_same_file and item then
vim.cmd(
string.format('silent! %d,%d move %s', item.range.start_line, item.range.end_line, tostring(destination_line))
)
vim.cmd(string.format('silent! %d,%d move %s', item.range.start_line, item.range.end_line, tostring(opts.file)))
return true
end

if not is_same_file then
local bufnr = vim.fn.bufadd(file)
local bufnr = vim.fn.bufadd(opts.file)
vim.api.nvim_open_win(bufnr, true, {
relative = 'editor',
width = 1,
@@ -295,7 +368,10 @@ function Capture:_refile_to(file, lines, item, destination_line)
})
end

vim.fn.append(destination_line, lines)
remove_buffer_empty_lines(opts)

local range = opts.range
vim.api.nvim_buf_set_lines(0, range.start_line, range.end_line, false, opts.lines)

if not is_same_file then
vim.cmd('silent! wq!')
85 changes: 85 additions & 0 deletions lua/orgmode/capture/template.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---@class TemplateEmptyLines
---@field before integer
---@field after integer
local TemplateEmptyLines = {}

function TemplateEmptyLines:new(opts)
opts = opts or {}

vim.validate({
before = { opts.before, 'number', true },
after = { opts.after, 'number', true },
})

local this = {}
this.before = opts.before or 0
this.after = opts.after or 0

setmetatable(this, self)
self.__index = self
return this
end

---@class TemplateProperties
---@field empty_lines TemplateEmptyLines
local TemplateProperties = {}

function TemplateProperties:new(opts)
opts = opts or {}

vim.validate({
empty_lines = { opts.empty_lines, { 'table', 'number' }, true },
})

local empty_lines = opts.empty_lines or {}
if type(empty_lines) == 'number' then
empty_lines = { before = empty_lines, after = empty_lines }
end

local this = {}
this.empty_lines = TemplateEmptyLines:new(empty_lines)

setmetatable(this, self)
self.__index = self
return this
end

---@class Template
---@field description string
---@field template string|string[]
---@field target string?
---@field headline string?
---@field properties TemplateProperties
---@field subtemplates table<string, Template>
local Template = {}

function Template:new(opts)
opts = opts or {}

vim.validate({
description = { opts.description, 'string', true },
template = { opts.template, { 'string', 'table' }, true },
target = { opts.target, 'string', true },
headline = { opts.headline, 'string', true },
properties = { opts.properties, 'table', true },
subtemplates = { opts.subtemplates, 'table', true },
})

local this = {}
this.description = opts.description or ''
this.template = opts.template or ''
this.target = opts.target
this.headline = opts.headline
this.properties = TemplateProperties:new(opts.properties)

this.subtemplates = {}
for key, subtemplate in pairs(opts.subtemplates or {}) do
this.subtemplates[key] = Template:new(subtemplate)
end

setmetatable(this, self)
self.__index = self
return this
end

return Template
22 changes: 18 additions & 4 deletions lua/orgmode/capture/templates.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
local config = require('orgmode.config')
local Template = require('orgmode.capture.template')
local Date = require('orgmode.objects.date')
local utils = require('orgmode.utils')

local expansions = {
['%f'] = function()
return vim.fn.expand('%')
@@ -34,13 +36,25 @@ local expansions = {
---@see https://orgmode.org/manual/Capture-templates.html

---@class Templates
---@field templates table<string, table>
---@field templates table<string, Template>
local Templates = {}

-- TODO Introduce type
function Templates:new()
function Templates:new(templates)
local opts = {}
opts.templates = config.org_capture_templates

vim.validate({
templates = { templates, 'table', true },
})

opts.templates = {}
for key, template in pairs(templates or config.org_capture_templates) do
if type(template) == 'table' then
opts.templates[key] = Template:new(template)
else
opts.templates[key] = template
end
end

setmetatable(opts, self)
self.__index = self
return opts
10 changes: 9 additions & 1 deletion lua/orgmode/org/mappings.lua
Original file line number Diff line number Diff line change
@@ -43,11 +43,19 @@ function OrgMappings:archive()
end
local item = file:get_closest_headline()
local archive_location = file:get_archive_file_location()
if not archive_location or not item then
return
end

local archive_directory = vim.fn.fnamemodify(archive_location, ':p:h')
if vim.fn.isdirectory(archive_directory) == 0 then
vim.fn.mkdir(archive_directory, 'p')
end
self.capture:refile_file_headline_to_archive(file, item, archive_location)
self.capture:refile_file_headline_to_archive({
file = archive_location,
item = item,
lines = file:get_headline_lines(item),
})
Files.reload(
archive_location,
vim.schedule_wrap(function()
267 changes: 253 additions & 14 deletions tests/plenary/capture/capture_spec.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
local Capture = require('orgmode.capture')
local Templates = require('orgmode.capture.templates')
local Template = require('orgmode.capture.template')
local File = require('orgmode.parser.file')
local helpers = require('tests.plenary.ui.helpers')
local org = require('orgmode')

describe('Menu Items', function()
it('should create a menu item for each template', function()
local templates = {
local templates = Templates:new({
t = {
description = 'todo',
},
@@ -12,8 +17,8 @@ describe('Menu Items', function()
f = {
description = 'file update',
},
}
menu_items = Capture:_create_menu_items(templates)
})
local menu_items = Capture:_create_menu_items(templates:get_list())
assert.are.same(#menu_items, 3)
assert.are.same(
{ 'b', 'f', 't' },
@@ -24,7 +29,7 @@ describe('Menu Items', function()
end)

it('should create one entry for multi-key shortcuts', function()
local multikey_templates = {
local multikey_templates = Templates:new({
k = 'Multikey templates',
kt = {
description = 'multikey todo',
@@ -36,8 +41,8 @@ describe('Menu Items', function()
kbf = {
description = 'file bookmark',
},
}
menu_items = Capture:_create_menu_items(multikey_templates)
})
local menu_items = Capture:_create_menu_items(multikey_templates:get_list())
assert.are.same(#menu_items, 1)
assert.are.same(
{ 'k' },
@@ -48,7 +53,7 @@ describe('Menu Items', function()
end)

it('computes the sub templates', function()
local multikey_templates = {
local multikey_templates = Templates:new({
k = 'Multikey templates',
kt = {
description = 'multikey todo',
@@ -60,9 +65,9 @@ describe('Menu Items', function()
kbf = {
description = 'file bookmark',
},
}
sub_template_items = Capture:_get_subtemplates('k', multikey_templates)
assert.are.same({
})
local sub_template_items = Capture:_get_subtemplates('k', multikey_templates:get_list())
local expected = Templates:new({
b = 'multikey bookmark',
bb = {
description = 'browser bookmark',
@@ -73,14 +78,248 @@ describe('Menu Items', function()
t = {
description = 'multikey todo',
},
}, sub_template_items)
}):get_list()
assert.are.same(expected, sub_template_items)
end)

it('should create one entry for multi-key shortcuts with subtemplates', function()
local multikey_templates = Templates:new({
k = {
description = 'Multikey templates',
subtemplates = {
t = {
description = 'multikey todo',
},
b = {
description = 'multikey bookmark',
subtemplates = {
b = {
description = 'browser bookmark',
},
f = {
description = 'file bookmark',
},
},
},
},
},
})
local menu_items = Capture:_create_menu_items(multikey_templates:get_list())
assert.are.same(#menu_items, 1)
assert.are.same(
{ 'k' },
vim.tbl_map(function(x)
return x.key
end, vim.fn.sort(menu_items))
)
end)

it('adds an ellipses', function()
local template = {
local templates = Templates:new({
k = 'Multikey template',
}
menu_item = Capture:_create_menu_items(template)
})
local menu_item = Capture:_create_menu_items(templates:get_list())
assert.are.same('Multikey template...', menu_item[1].label)
end)
end)

describe('Refile', function()
it('to empty file', function()
local destination_file = helpers.load_file_content({})

local capture_lines = { '* foo' }
helpers.load_file_content(capture_lines)
local capture_file = File.from_content(capture_lines, 'capture')
assert(capture_file)
local item = capture_file:get_headlines()[1]

org.instance().capture:_refile_to_end({
file = destination_file,
lines = capture_lines,
item = item,
})
vim.cmd('edit' .. vim.fn.fnameescape(destination_file))
assert.are.same({
'* foo',
}, vim.api.nvim_buf_get_lines(0, 0, -1, false))
end)

it('to end', function()
local destination_file = helpers.load_file_content({
'* foobar',
' ',
'',
'\t\t\t\t',
'',
})

local capture_lines = { '** baz' }
helpers.load_file_content(capture_lines)
local capture_file = File.from_content(capture_lines, 'capture')
assert(capture_file)
local item = capture_file:get_headlines()[1]

org.instance().capture:_refile_to_end({
file = destination_file,
lines = capture_lines,
item = item,
})
vim.cmd('edit' .. vim.fn.fnameescape(destination_file))
assert.are.same({
'* foobar',
'** baz',
}, vim.api.nvim_buf_get_lines(0, 0, -1, false))
end)
it('to headline', function()
local destination_file = helpers.load_file_content({
'* foobar',
' ',
'',
'\t\t\t\t',
'',
'* barbar',
'',
' ',
'',
})

local capture_lines = { '** baz' }
helpers.load_file_content(capture_lines)
local capture_file = File.from_content(capture_lines, 'capture')
assert(capture_file)
local item = capture_file:get_headlines()[1]

org.instance().capture:refile_to_headline({
file = destination_file,
lines = capture_lines,
item = item,
headline = 'foobar',
})
vim.cmd('edit' .. vim.fn.fnameescape(destination_file))
assert.are.same({
'* foobar',
'** baz',
'* barbar',
'',
' ',
'',
}, vim.api.nvim_buf_get_lines(0, 0, -1, false))
end)
end)

describe('Refile with empty lines', function()
it('to empty file', function()
local destination_file = helpers.load_file_content({})

local capture_lines = { '* foo' }
helpers.load_file_content(capture_lines)
local capture_file = File.from_content(capture_lines, 'capture')
assert(capture_file)
local item = capture_file:get_headlines()[1]

org.instance().capture:_refile_to_end({
file = destination_file,
lines = capture_lines,
item = item,
template = Template:new({
properties = {
empty_lines = {
before = 2,
after = 1,
},
},
}),
})
vim.cmd('edit' .. vim.fn.fnameescape(destination_file))
assert.are.same({
'',
'',
'* foo',
'',
}, vim.api.nvim_buf_get_lines(0, 0, -1, false))
end)

it('to end', function()
local destination_file = helpers.load_file_content({
'* foobar',
' ',
'',
'\t\t\t\t',
'',
})

local capture_lines = { '** baz' }
helpers.load_file_content(capture_lines)
local capture_file = File.from_content(capture_lines, 'capture')
assert(capture_file)
local item = capture_file:get_headlines()[1]

org.instance().capture:_refile_to_end({
file = destination_file,
lines = capture_lines,
item = item,
template = Template:new({
properties = {
empty_lines = {
before = 2,
after = 1,
},
},
}),
})
vim.cmd('edit' .. vim.fn.fnameescape(destination_file))
assert.are.same({
'* foobar',
'',
'',
'** baz',
'',
}, vim.api.nvim_buf_get_lines(0, 0, -1, false))
end)
it('to headline', function()
local destination_file = helpers.load_file_content({
'* foobar',
' ',
'',
'\t\t\t\t',
'',
'* barbar',
'',
' ',
'',
})

local capture_lines = { '** baz' }
helpers.load_file_content(capture_lines)
local capture_file = File.from_content(capture_lines, 'capture')
assert(capture_file)
local item = capture_file:get_headlines()[1]

org.instance().capture:refile_to_headline({
file = destination_file,
lines = capture_lines,
item = item,
headline = 'foobar',
template = Template:new({
properties = {
empty_lines = {
before = 2,
after = 1,
},
},
}),
})
vim.cmd('edit' .. vim.fn.fnameescape(destination_file))
assert.are.same({
'* foobar',
'',
'',
'** baz',
'',
'* barbar',
'',
' ',
'',
}, vim.api.nvim_buf_get_lines(0, 0, -1, false))
end)
end)
21 changes: 18 additions & 3 deletions tests/plenary/ui/mappings/refile_spec.lua
Original file line number Diff line number Diff line change
@@ -22,7 +22,12 @@ describe('Refile mappings', function()

source_file = Files.get_current_file()
local item = source_file:get_closest_headline()
org.instance().capture:refile_to_headline(destination_file, source_file:get_headline_lines(item), item, 'foo')
org.instance().capture:refile_to_headline({
file = destination_file,
lines = source_file:get_headline_lines(item),
item = item,
headline = 'foo',
})
assert.are.same('* not to be refiled', vim.fn.getline(1))
vim.cmd('edit' .. vim.fn.fnameescape(destination_file))
assert.are.same({
@@ -47,7 +52,12 @@ describe('Refile mappings', function()

source_file = Files.get_current_file()
local item = source_file:get_closest_headline()
org.instance().capture:refile_to_headline(destination_file, source_file:get_headline_lines(item), item, 'foobar')
org.instance().capture:refile_to_headline({
file = destination_file,
lines = source_file:get_headline_lines(item),
item = item,
headline = 'foobar',
})
assert.are.same('* not to be refiled', vim.fn.getline(1))
vim.cmd('edit' .. vim.fn.fnameescape(destination_file))
assert.are.same({
@@ -72,7 +82,12 @@ describe('Refile mappings', function()

source_file = Files.get_current_file()
local item = source_file:get_closest_headline()
org.instance().capture:refile_to_headline(destination_file, source_file:get_headline_lines(item), item, 'foobar')
org.instance().capture:refile_to_headline({
file = destination_file,
lines = source_file:get_headline_lines(item),
item = item,
headline = 'foobar',
})
assert.are.same('* not to be refiled', vim.fn.getline(1))
vim.cmd('edit' .. vim.fn.fnameescape(destination_file))
assert.are.same({