From f255ac56f3661f02a6b077f2045de84558d9898a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Fl=C3=BCgge?= Date: Sun, 30 Jun 2024 12:38:11 +0200 Subject: [PATCH 1/5] feat(api): Extend API to get links Considers id links, if org-id-link-to-org-use-id is set. Creates ids on file and headline level if needed. --- lua/orgmode/api/init.lua | 60 +++++++++++++++++++++++++++++ lua/orgmode/files/file.lua | 26 +++++++++++++ lua/orgmode/org/hyperlinks/init.lua | 14 +++++++ 3 files changed, 100 insertions(+) diff --git a/lua/orgmode/api/init.lua b/lua/orgmode/api/init.lua index ad479e0b4..226f0d628 100644 --- a/lua/orgmode/api/init.lua +++ b/lua/orgmode/api/init.lua @@ -101,7 +101,67 @@ function OrgApi.refile(opts) return true end +--- Get a link destination as string +--- +--- Depending if org_id_link_to_org_use_id is set the format is +--- +--- id:::*title and the id is created if not existing +--- or +--- file:::*title +--- +--- The result is meant to be used as link_location for OrgApi.insert_link. +--- @param headline OrgApiHeadline +--- @return string +function OrgApi.get_link_to_headline(headline) + local filename = headline.file.filename + local bufnr = vim.fn.bufnr(filename) + + if bufnr == -1 then + -- do remote edit + return orgmode.files + :update_file(filename, function(_) + return Hyperlinks.get_link_to_headline(headline._section) + end) + :wait() + end + + return Hyperlinks.get_link_to_headline(headline._section) +end + +--- Get a link destination as string +--- +--- Depending if org_id_link_to_org_use_id is set the format is +--- +--- id:::*title and the id is created if not existing +--- or +--- file:::*title +--- +--- The result is meant to be used as link_location for OrgApi.insert_link. +--- @param file OrgApiFile +--- @return string +function OrgApi.get_link_to_file(file) + local filename = file.filename + local bufnr = vim.fn.bufnr(filename) + + if bufnr == -1 then + -- do remote edit + return orgmode.files + :update_file(filename, function(_file) + return Hyperlinks.get_link_to_file(_file) + end) + :wait() + end + + return Hyperlinks.get_link_to_file(file._file) +end + --- Insert a link to a given location at the current cursor position +--- +--- The expected format is +--- ::: +--- +--- If is *, is used as prefilled description for the link. +--- If is id, this format can also be used to pass a prefilled description. --- @param link_location string --- @return boolean function OrgApi.insert_link(link_location) diff --git a/lua/orgmode/files/file.lua b/lua/orgmode/files/file.lua index 8434afe91..736dc2f91 100644 --- a/lua/orgmode/files/file.lua +++ b/lua/orgmode/files/file.lua @@ -643,6 +643,7 @@ end memoize('get_category') --- Get the category name for this file +--- If no category is set, the filename without extension is returned --- @return string function OrgFile:get_category() local category = self:_get_directive('category') @@ -653,6 +654,19 @@ function OrgFile:get_category() return vim.fn.fnamemodify(self.filename, ':t:r') or '' end +memoize('get_title') +--- Get the title for this file +--- If no title is set, the filename without extension is returned +--- @return string +function OrgFile:get_title() + local title = self:_get_directive('title') + if title then + return title + end + + return vim.fn.fnamemodify(self.filename, ':t:r') or '' +end + memoize('get_opened_unfinished_headlines') ---@return OrgHeadline[] function OrgFile:get_opened_unfinished_headlines() @@ -703,6 +717,18 @@ function OrgFile:get_directive(directive_name) return self:_get_directive(directive_name) end +--- Get headline id or create a new one if it doesn't exist +--- @return string +function OrgFile:id_get_or_create() + local id = self:get_property('id') + if id then + return id + end + local org_id = require('orgmode.org.id').new() + self:set_property('ID', org_id) + return org_id +end + ---@private ---@return string | nil function OrgFile:_get_directive(directive_name) diff --git a/lua/orgmode/org/hyperlinks/init.lua b/lua/orgmode/org/hyperlinks/init.lua index 2dc6a5d7a..b07558b94 100644 --- a/lua/orgmode/org/hyperlinks/init.lua +++ b/lua/orgmode/org/hyperlinks/init.lua @@ -184,6 +184,20 @@ function Hyperlinks.get_link_to_headline(headline, path) if config.org_id_link_to_org_use_id and id then return ('id:%s::*%s'):format(id, title) end + +---@param file OrgFile +---@param path? string +function Hyperlinks.get_link_to_file(file, path) + local title = file:get_title() + + if config.org_id_link_to_org_use_id then + local id = file:id_get_or_create() + if id then + return ('id:%s::*%s'):format(id, title) + end + end + + path = path or file.filename return ('file:%s::*%s'):format(path, title) end From 5a889552aa6b114647ec8f5a9b0438c874e21e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Fl=C3=BCgge?= Date: Sun, 30 Jun 2024 12:38:39 +0200 Subject: [PATCH 2/5] chore: Remove stale require --- lua/orgmode/api/init.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/orgmode/api/init.lua b/lua/orgmode/api/init.lua index 226f0d628..968bc7a35 100644 --- a/lua/orgmode/api/init.lua +++ b/lua/orgmode/api/init.lua @@ -2,7 +2,6 @@ local OrgFile = require('orgmode.api.file') local OrgHeadline = require('orgmode.api.headline') local Hyperlinks = require('orgmode.org.hyperlinks') -local Link = require('orgmode.org.hyperlinks.link') local orgmode = require('orgmode') ---@class OrgApiRefileOpts From 1344eb1f3bf67ad0b4bdd34bc09c51bc351354b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Fl=C3=BCgge?= Date: Sun, 30 Jun 2024 12:45:50 +0200 Subject: [PATCH 3/5] chore: tiny refactoring to align similar methods Adapt the style of get_link_to_headline to new get_link_to_file - avoid empty declaration of `id` - move initialization of `path` close to it's usage --- lua/orgmode/org/hyperlinks/init.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lua/orgmode/org/hyperlinks/init.lua b/lua/orgmode/org/hyperlinks/init.lua index b07558b94..6f517f577 100644 --- a/lua/orgmode/org/hyperlinks/init.lua +++ b/lua/orgmode/org/hyperlinks/init.lua @@ -174,16 +174,18 @@ end ---@param headline OrgHeadline ---@param path? string function Hyperlinks.get_link_to_headline(headline, path) - path = path or utils.current_file_path() local title = headline:get_title() - local id + if config.org_id_link_to_org_use_id then - id = headline:id_get_or_create() + local id = headline:id_get_or_create() + if id then + return ('id:%s::*%s'):format(id, title) + end end - if config.org_id_link_to_org_use_id and id then - return ('id:%s::*%s'):format(id, title) - end + path = path or utils.current_file_path() + return ('file:%s::*%s'):format(path, title) +end ---@param file OrgFile ---@param path? string From 23f0c98740b0b16a182d130cca01c296d5e802e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Fl=C3=BCgge?= Date: Mon, 1 Jul 2024 19:08:23 +0200 Subject: [PATCH 4/5] refactor: make get_link member functions Simplify the code by providing member functions on org.api.file and org.api.headline. --- lua/orgmode/api/file.lua | 28 +++++++++++++++++++ lua/orgmode/api/headline.lua | 27 ++++++++++++++++++ lua/orgmode/api/init.lua | 54 ------------------------------------ 3 files changed, 55 insertions(+), 54 deletions(-) diff --git a/lua/orgmode/api/file.lua b/lua/orgmode/api/file.lua index 349a743c1..626766a4e 100644 --- a/lua/orgmode/api/file.lua +++ b/lua/orgmode/api/file.lua @@ -1,5 +1,7 @@ ---@diagnostic disable: invisible local OrgHeadline = require('orgmode.api.headline') +local Hyperlinks = require('orgmode.org.hyperlinks') +local org = require('orgmode') ---@class OrgApiFile ---@field category string current file category name. By default it's only filename without extension unless defined differently via #+CATEGORY directive @@ -92,4 +94,30 @@ function OrgFile:get_closest_headline(cursor) return nil end +--- Get a link destination as string +--- +--- Depending if org_id_link_to_org_use_id is set the format is +--- +--- id:::*title and the id is created if not existing +--- or +--- file:::*title +--- +--- The result is meant to be used as link_location for OrgApi.insert_link. +--- @return string +function OrgFile:get_link() + local filename = self.filename + local bufnr = vim.fn.bufnr(filename) + + if bufnr == -1 then + -- do remote edit + return org.files + :update_file(filename, function(file) + return Hyperlinks.get_link_to_file(file) + end) + :wait() + end + + return Hyperlinks.get_link_to_file(self._file) +end + return OrgFile diff --git a/lua/orgmode/api/headline.lua b/lua/orgmode/api/headline.lua index 88d7c6a3e..df803d16d 100644 --- a/lua/orgmode/api/headline.lua +++ b/lua/orgmode/api/headline.lua @@ -3,6 +3,7 @@ local PriorityState = require('orgmode.objects.priority_state') local Date = require('orgmode.objects.date') local Calendar = require('orgmode.objects.calendar') local Promise = require('orgmode.utils.promise') +local Hyperlinks = require('orgmode.org.hyperlinks') local org = require('orgmode') ---@class OrgApiHeadline @@ -259,4 +260,30 @@ function OrgHeadline:_do_action(action) end) end +--- Get a link destination as string +--- +--- Depending if org_id_link_to_org_use_id is set the format is +--- +--- id:::*title and the id is created if not existing +--- or +--- file:::*title +--- +--- The result is meant to be used as link_location for OrgApi.insert_link. +--- @return string +function OrgHeadline:get_link() + local filename = self.file.filename + local bufnr = vim.fn.bufnr(filename) + + if bufnr == -1 then + -- do remote edit + return org.files + :update_file(filename, function(_) + return Hyperlinks.get_link_to_headline(self._section) + end) + :wait() + end + + return Hyperlinks.get_link_to_headline(self._section) +end + return OrgHeadline diff --git a/lua/orgmode/api/init.lua b/lua/orgmode/api/init.lua index 968bc7a35..cf7926da5 100644 --- a/lua/orgmode/api/init.lua +++ b/lua/orgmode/api/init.lua @@ -100,60 +100,6 @@ function OrgApi.refile(opts) return true end ---- Get a link destination as string ---- ---- Depending if org_id_link_to_org_use_id is set the format is ---- ---- id:::*title and the id is created if not existing ---- or ---- file:::*title ---- ---- The result is meant to be used as link_location for OrgApi.insert_link. ---- @param headline OrgApiHeadline ---- @return string -function OrgApi.get_link_to_headline(headline) - local filename = headline.file.filename - local bufnr = vim.fn.bufnr(filename) - - if bufnr == -1 then - -- do remote edit - return orgmode.files - :update_file(filename, function(_) - return Hyperlinks.get_link_to_headline(headline._section) - end) - :wait() - end - - return Hyperlinks.get_link_to_headline(headline._section) -end - ---- Get a link destination as string ---- ---- Depending if org_id_link_to_org_use_id is set the format is ---- ---- id:::*title and the id is created if not existing ---- or ---- file:::*title ---- ---- The result is meant to be used as link_location for OrgApi.insert_link. ---- @param file OrgApiFile ---- @return string -function OrgApi.get_link_to_file(file) - local filename = file.filename - local bufnr = vim.fn.bufnr(filename) - - if bufnr == -1 then - -- do remote edit - return orgmode.files - :update_file(filename, function(_file) - return Hyperlinks.get_link_to_file(_file) - end) - :wait() - end - - return Hyperlinks.get_link_to_file(file._file) -end - --- Insert a link to a given location at the current cursor position --- --- The expected format is From cb621f013f260c33ca0d45acb42183dbd8772686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Fl=C3=BCgge?= Date: Mon, 1 Jul 2024 20:46:09 +0200 Subject: [PATCH 5/5] fix: handle unloaded buffers --- lua/orgmode/api/file.lua | 2 +- lua/orgmode/api/headline.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/orgmode/api/file.lua b/lua/orgmode/api/file.lua index 626766a4e..87b2695d1 100644 --- a/lua/orgmode/api/file.lua +++ b/lua/orgmode/api/file.lua @@ -108,7 +108,7 @@ function OrgFile:get_link() local filename = self.filename local bufnr = vim.fn.bufnr(filename) - if bufnr == -1 then + if bufnr == -1 or not vim.api.nvim_buf_is_loaded(bufnr) then -- do remote edit return org.files :update_file(filename, function(file) diff --git a/lua/orgmode/api/headline.lua b/lua/orgmode/api/headline.lua index df803d16d..282d05fe7 100644 --- a/lua/orgmode/api/headline.lua +++ b/lua/orgmode/api/headline.lua @@ -274,7 +274,7 @@ function OrgHeadline:get_link() local filename = self.file.filename local bufnr = vim.fn.bufnr(filename) - if bufnr == -1 then + if bufnr == -1 or not vim.api.nvim_buf_is_loaded(bufnr) then -- do remote edit return org.files :update_file(filename, function(_)