From 044a1eba4184cccb8fd041db21021212764837aa Mon Sep 17 00:00:00 2001 From: Joao Sa Date: Mon, 31 Oct 2022 11:03:36 +0100 Subject: [PATCH] Implement refile heading --- lua/orgmode-telescope/utils.lua | 83 +++++++++++++++++ lua/telescope/_extensions/orgmode/init.lua | 89 +------------------ .../_extensions/orgmode/refile_heading.lua | 84 +++++++++++++++++ .../_extensions/orgmode/search_headings.lua | 19 ++++ 4 files changed, 188 insertions(+), 87 deletions(-) create mode 100644 lua/orgmode-telescope/utils.lua create mode 100644 lua/telescope/_extensions/orgmode/refile_heading.lua create mode 100644 lua/telescope/_extensions/orgmode/search_headings.lua diff --git a/lua/orgmode-telescope/utils.lua b/lua/orgmode-telescope/utils.lua new file mode 100644 index 0000000..adfbd66 --- /dev/null +++ b/lua/orgmode-telescope/utils.lua @@ -0,0 +1,83 @@ +local entry_display = require("telescope.pickers.entry_display") + +local orgmode = require('orgmode.api') + +local utils = {} + +utils.get_entries = function(opts) + + local file_results = vim.tbl_map(function(file) + return { file = file, filename = file.filename } + end, orgmode.load()) + + if not opts.archived then + file_results = vim.tbl_filter(function(entry) + return not entry.file.is_archive_file + end, file_results) + end + + if opts.max_depth == 0 then + return file_results + end + + local results = {} + for _, file_entry in ipairs(file_results) do + local agenda_file = orgmode.load(file_entry.filename) + for _, headline in ipairs(agenda_file.headlines) do + + local allowed_depth = opts.max_depth == nil or headline._section.level <= opts.max_depth + local allowed_archive = opts.archived or not headline._section:is_archived() + if allowed_depth and allowed_archive then + local entry = { + file = file_entry.file, + filename = file_entry.filename, + headline = headline + } + table.insert(results, entry) + end + end + end + + return results +end + +utils.make_entry = function(opts) + + local displayer = entry_display.create({ + separator = ' ', + items = { + { width = vim.F.if_nil(opts.location_width, 20) }, + { remaining = true } + } + }) + + local function make_display(entry) + return displayer({ entry.location, entry.line }) + end + + return function(entry) + local headline = entry.headline + + local lnum = nil + local location = vim.fn.fnamemodify(entry.filename, ':t') + local line = "" + + if headline then + lnum = headline.position.start_line + location = string.format('%s:%i', location, lnum) + line = string.format('%s %s', string.rep('*', headline._section.level), headline.title) + end + + return { + value = entry, + ordinal = location .. ' ' .. line, + filename = entry.filename, + lnum = lnum, + display = make_display, + location = location, + line = line + } + end +end + +return utils diff --git a/lua/telescope/_extensions/orgmode/init.lua b/lua/telescope/_extensions/orgmode/init.lua index 0bdca6b..eb3c11e 100644 --- a/lua/telescope/_extensions/orgmode/init.lua +++ b/lua/telescope/_extensions/orgmode/init.lua @@ -10,94 +10,9 @@ local conf = require("telescope.config").values -- TODO: add highlight groups -- TODO: add action to refile/capture -local function get_entries(opts) - - local file_results = vim.tbl_map(function(file) - return { file = file, filename = file.filename } - end, orgmode.load()) - - if not opts.archived then - file_results = vim.tbl_filter(function(entry) - return not entry.file.is_archive_file - end, file_results) - end - - if opts.max_depth == 0 then - return file_results - end - - local results = {} - for _, file_entry in ipairs(file_results) do - local agenda_file = orgmode.load(file_entry.filename) - for _, headline in ipairs(agenda_file.headlines) do - - local allowed_depth = opts.max_depth == nil or headline._section.level <= opts.max_depth - local allowed_archive = opts.archived or not headline._section:is_archived() - if allowed_depth and allowed_archive then - local entry = { - file = file_entry.file, - filename = file_entry.filename, - headline = headline - } - table.insert(results, entry) - end - end - end - - return results -end - -local function search_headings(opts) - opts = opts or {} - - local displayer = entry_display.create({ - separator = ' ', - items = { - { width = vim.F.if_nil(opts.location_width, 20) }, - { remaining = true } - } - }) - - local function make_display(entry) - return displayer({ entry.location, entry.line }) - end - - pickers.new(opts, { - prompt_title = "Search Headings", - finder = finders.new_table { - results = get_entries(opts), - entry_maker = opts.entry_maker or function(entry) - - local headline = entry.headline - - local lnum = nil - local location = vim.fn.fnamemodify(entry.filename, ':t') - local line = "" - - if headline then - lnum = headline.position.start_line - location = string.format('%s:%i', location, lnum) - line = string.format('%s %s', string.rep('*', headline._section.level), headline.title) - end - - return { - value = entry, - ordinal = location .. ' ' .. line, - filename = entry.filename, - lnum = lnum, - display = make_display, - location = location, - line = line - } - end, - }, - sorter = conf.generic_sorter(opts), - previewer = conf.grep_previewer(opts), - }):find() -end - return require("telescope").register_extension { exports = { - search_headings = search_headings, + search_headings = require("telescope._extensions.orgmode.search_headings"), + refile_heading = require("telescope._extensions.orgmode.refile_heading") }, } diff --git a/lua/telescope/_extensions/orgmode/refile_heading.lua b/lua/telescope/_extensions/orgmode/refile_heading.lua new file mode 100644 index 0000000..c62426d --- /dev/null +++ b/lua/telescope/_extensions/orgmode/refile_heading.lua @@ -0,0 +1,84 @@ +local pickers = require("telescope.pickers") +local finders = require("telescope.finders") +local conf = require("telescope.config").values +local action_set = require("telescope.actions.set") +local actions = require("telescope.actions") +local action_state = require("telescope.actions.state") + +local utils = require('orgmode-telescope.utils') + +local Files = require('orgmode.parser.files') +local Capture = require('orgmode.capture') + +return function(opts) + opts = opts or {} + + local src_file = Files.get_current_file() + local src_item = src_file:get_closest_headline() + local src_lines = src_file:get_headline_lines(src_item) + + local function refile(prompt_bufnr) + local entry = action_state.get_selected_entry() + actions.close(prompt_bufnr) + + local dst_file = entry.value.file + local dst_headline = entry.value.headline + if dst_headline then + -- NOTE: adapted from Capture:refile_to_headline + if src_item and src_item.level <= dst_headline._section.level 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 = dst_file.filename == src_item.root.filename + src_lines = src_item:demote(dst_headline._section.level - src_item.level + 1, true, not is_same_file) + end + local refiled = Capture:_refile_to(dst_file.filename, src_lines, src_item, dst_headline.position.end_line) + if not refiled then + return false + end + --utils.echo_info(string.format('Wrote %s', dst_file.filename)) + return true + else + return Capture:_refile_to_end(dst_file.filename, src_lines, src_item) + end + end + + local current_depth = opts.max_depth + local next_depth = nil + if current_depth ~= 0 then + next_depth = 0 + end + + local function depth_toggle(prompt_bufnr) + local current_picker = action_state.get_current_picker(prompt_bufnr) + + -- TODO: use action_state to store these to allow easy rebinding by users + local aux = current_depth + current_depth = next_depth + next_depth = aux + + opts.max_depth = current_depth + local new_finder = finders.new_table { + results = utils.get_entries(opts), + entry_maker = opts.entry_maker or utils.make_entry(opts), + } + + current_picker:refresh(new_finder, opts) + end + + pickers.new(opts, { + -- TODO: alter prompt title when depth is 0: Refile under file, Refile + -- under Headline + prompt_title = "Refile Destination", + finder = finders.new_table { + results = utils.get_entries(opts), + entry_maker = opts.entry_maker or utils.make_entry(opts), + }, + sorter = conf.generic_sorter(opts), + previewer = conf.grep_previewer(opts), + attach_mappings = function(_, map) + action_set.select:replace(refile) + map("i", "", depth_toggle) + return true + end, + }):find() +end diff --git a/lua/telescope/_extensions/orgmode/search_headings.lua b/lua/telescope/_extensions/orgmode/search_headings.lua new file mode 100644 index 0000000..7a84eb5 --- /dev/null +++ b/lua/telescope/_extensions/orgmode/search_headings.lua @@ -0,0 +1,19 @@ +local pickers = require("telescope.pickers") +local finders = require("telescope.finders") +local conf = require("telescope.config").values + +local utils = require('orgmode-telescope.utils') + +return function(opts) + opts = opts or {} + + pickers.new(opts, { + prompt_title = "Search Headings", + finder = finders.new_table { + results = utils.get_entries(opts), + entry_maker = opts.entry_maker or utils.make_entry(opts), + }, + sorter = conf.generic_sorter(opts), + previewer = conf.grep_previewer(opts), + }):find() +end