Skip to content

Restructuring #15

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 3 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lua/telescope-orgmode/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
return {
refile_heading = require('telescope-orgmode.refile_heading'),
search_headings = require('telescope-orgmode.search_headings'),
}
57 changes: 57 additions & 0 deletions lua/telescope-orgmode/refile_heading.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
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('telescope-orgmode.utils')

local OrgApi = require('orgmode.api')

local M = {}

M.refile = function(prompt_bufnr)
local entry = action_state.get_selected_entry()
actions.close(prompt_bufnr)

-- Refile to the file by default
local destination = entry.value.file

-- Refile to a specific heading if is set
if entry.value.headline then
destination = entry.value.headline
end

return OrgApi.refile({
source = M.closest_headline,
destination = destination,
})
end

M.closest_headline = nil

return function(opts)
opts = opts or {}

M.closest_headline = OrgApi.current():get_closest_headline()

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(prompt_bufnr, map)
action_set.select:replace(M.refile)
map('i', '<c-space>', utils.gen_depth_toggle(opts, prompt_bufnr))
return true
end,
})
:find()
end
21 changes: 21 additions & 0 deletions lua/telescope-orgmode/search_headings.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
local pickers = require('telescope.pickers')
local finders = require('telescope.finders')
local conf = require('telescope.config').values

local utils = require('telescope-orgmode.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
61 changes: 61 additions & 0 deletions lua/telescope-orgmode/typehints.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
-- Type-hints copied from nvim-orgmode to simplify development

---@class OrgFileMetadata
---@field mtime number
---@field changedtick number

---@class OrgFileOpts
---@field filename string
---@field lines string[]
---@field bufnr? number

---@class OrgFile
---@field filename string
---@field lines string[]
---@field content string
---@field metadata OrgFileMetadata
---@field parser vim.treesitter.LanguageTree
---@field root TSNode

---@class OrgApiFile
---@field category string current file category name. By default it's only filename without extension unless defined differently via #+CATEGORY directive
---@field filename string absolute path of the current file
---@field headlines OrgApiHeadline[]
---@field is_archive_file boolean
---@field private _file OrgFile
--
---@class OrgRange
---@field start_line number
---@field start_col number
---@field end_line number
---@field end_col number

---@class OrgApiHeadline
---@field title string headline title without todo keyword, tags and priority. Ex. `* TODO I am a headline :SOMETAG:` returns `I am a headline`
---@field line string full headline line
---@field level number headline level (number of asterisks). Example: 1
---@field todo_value? string todo keyword of the headline (Example: TODO, DONE)
---@field todo_type? 'TODO' | 'DONE' | ''
---@field tags string[] List of own tags
---@field deadline OrgDate|nil
---@field scheduled OrgDate|nil
---@field properties table<string, string> Table containing all properties. All keys are lowercased
---@field closed OrgDate|nil
---@field dates OrgDate[] List of all dates that are not "plan" dates
---@field position OrgRange
---@field all_tags string[] List of all tags (own + inherited)
---@field file OrgApiFile
---@field parent OrgApiHeadline|nil
---@field priority string|nil
---@field is_archived boolean headline marked with the `:ARCHIVE:` tag
---@field headlines OrgApiHeadline[]
--
---@class OrgApiRefileOpts
---@field source OrgApiHeadline
---@field destination OrgApiFile | OrgApiHeadline

---@class OrgApi
---@field load fun(name?: string|string[]): OrgApiFile|OrgApiFile[]
---@field current fun(): OrgApiFile
---@field refile fun(opts: OrgApiRefileOpts)
---@field insert_link fun(link_location: string): boolean
178 changes: 110 additions & 68 deletions lua/telescope-orgmode/utils.lua
Original file line number Diff line number Diff line change
@@ -1,79 +1,121 @@
local entry_display = require("telescope.pickers.entry_display")
require('telescope-orgmode.typehints')

local orgmode = require("orgmode.api")
local entry_display = require('telescope.pickers.entry_display')
local finders = require('telescope.finders')
local action_state = require('telescope.actions.state')
local state = require('telescope.state')

local orgmode = require('orgmode.api')

local utils = {}

---@class OrgEntry
---@field file OrgApiFile
---@field filename string
---@field headline? OrgApiHeadline

---Fetches entrys from OrgApi and extracts the relevant information
---@param opts any
---@return OrgEntry[]
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
for _, headline in ipairs(file_entry.file.headlines) do
local allowed_depth = opts.max_depth == nil or headline.level <= opts.max_depth
local allowed_archive = opts.archived or not headline.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
---@type { file: OrgApiFile, filename: string }[]
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
for _, headline in ipairs(file_entry.file.headlines) do
local allowed_depth = opts.max_depth == nil or headline.level <= opts.max_depth
local allowed_archive = opts.archived or not headline.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

---Entry-Maker for Telescope
---@param opts any
---@return fun(entry: OrgEntry):MatchEntry
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.level), headline.title)
end

return {
value = entry,
ordinal = location .. " " .. line,
filename = entry.filename,
lnum = lnum,
display = make_display,
location = location,
line = line,
}
end
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.level), headline.title)
end

return {
value = entry,
ordinal = location .. ' ' .. line,
filename = entry.filename,
lnum = lnum,
display = make_display,
location = location,
line = line,
}
end
end

utils.gen_depth_toggle = function(opts, prompt_bufnr)
local status = state.get_status(prompt_bufnr)
status._ot_current_depth = opts.max_depth
status._ot_next_depth = nil
if status._ot_current_depth ~= 0 then
status._ot_next_depth = 0
end

return function()
local current_picker = action_state.get_current_picker(prompt_bufnr)

local aux = status._ot_current_depth
status._ot_current_depth = status._ot_next_depth
status._ot_next_depth = aux

opts.max_depth = status._ot_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
end

return utils
10 changes: 5 additions & 5 deletions lua/telescope/_extensions/orgmode/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
-- public orgmode api
-- TODO: add highlight groups

return require("telescope").register_extension({
exports = {
search_headings = require("telescope._extensions.orgmode.search_headings"),
refile_heading = require("telescope._extensions.orgmode.refile_heading"),
},
return require('telescope').register_extension({
exports = {
search_headings = require('telescope-orgmode').search_headings,
refile_heading = require('telescope-orgmode').refile_heading,
},
})
Loading