From 882ae9ac871d88a810d6e056bf1f0157543305bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Fl=C3=BCgge?= Date: Tue, 21 May 2024 16:07:08 +0200 Subject: [PATCH 1/2] feat(api): Allow to insert links through API To give plugins like Telescope-orgmode the ability to insert links, the API needs an extension. The refactoring moves some methods from org.mappings into modules, where they should belong anyway, so they can be used from the new api method. The new API method api.insert_link is mostly existing code moved from org.mappings.insert_link, which now just calls api.insert_link. --- lua/orgmode/api/init.lua | 56 +++++++++++++++++++++++++++++ lua/orgmode/org/hyperlinks/init.lua | 8 +++++ lua/orgmode/org/mappings.lua | 55 ++-------------------------- 3 files changed, 67 insertions(+), 52 deletions(-) diff --git a/lua/orgmode/api/init.lua b/lua/orgmode/api/init.lua index 25182feb6..8a7d13379 100644 --- a/lua/orgmode/api/init.lua +++ b/lua/orgmode/api/init.lua @@ -1,6 +1,8 @@ ---@diagnostic disable: invisible 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 @@ -8,6 +10,10 @@ local orgmode = require('orgmode') ---@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 local OrgApi = {} ---@param name? string|string[] specific file names to return (absolute path). If ommitted, returns all loaded files @@ -99,4 +105,54 @@ function OrgApi.refile(opts) return true end +--- Insert a link to a given location at the current cursor position +--- @param link_location string +--- @return boolean +function OrgApi.insert_link(link_location) + local selected_link = Link:new(link_location) + local desc = selected_link.url:get_target_value() + if selected_link.url:is_id() then + local id_link = ('id:%s'):format(selected_link.url:get_id()) + desc = link_location:gsub('^' .. vim.pesc(id_link) .. '%s+', '') + link_location = id_link + end + + local link_description = vim.trim(vim.fn.OrgmodeInput('Description: ', desc or '')) + + link_location = '[' .. vim.trim(link_location) .. ']' + + if link_description ~= '' then + link_description = '[' .. link_description .. ']' + end + + local insert_from + local insert_to + local target_col = #link_location + #link_description + 2 + + -- check if currently on link + local link, position = Hyperlinks.get_link_under_cursor() + if link and position then + insert_from = position.from - 1 + insert_to = position.to + 1 + target_col = target_col + position.from + else + local colnr = vim.fn.col('.') + insert_from = colnr + insert_to = colnr + 1 + target_col = target_col + colnr + end + + local linenr = vim.fn.line('.') or 0 + local curr_line = vim.fn.getline(linenr) + local new_line = string.sub(curr_line, 0, insert_from) + .. '[' + .. link_location + .. link_description + .. ']' + .. string.sub(curr_line, insert_to, #curr_line) + + vim.fn.setline(linenr, new_line) + vim.fn.cursor(linenr, target_col) +end + return OrgApi diff --git a/lua/orgmode/org/hyperlinks/init.lua b/lua/orgmode/org/hyperlinks/init.lua index 086af8803..3ff367b2a 100644 --- a/lua/orgmode/org/hyperlinks/init.lua +++ b/lua/orgmode/org/hyperlinks/init.lua @@ -2,6 +2,7 @@ local org = require('orgmode') local utils = require('orgmode.utils') local fs = require('orgmode.utils.fs') local Url = require('orgmode.org.hyperlinks.url') +local Link = require('orgmode.org.hyperlinks.link') local config = require('orgmode.config') local Hyperlinks = { stored_links = {}, @@ -204,5 +205,12 @@ function Hyperlinks.autocomplete_links(arg_lead) return vim.tbl_keys(Hyperlinks.stored_links) end +-- +---@return OrgLink|nil, table | nil +function Hyperlinks.get_link_under_cursor() + local line = vim.fn.getline('.') + local col = vim.fn.col('.') or 0 + return Link.at_pos(line, col) +end return Hyperlinks diff --git a/lua/orgmode/org/mappings.lua b/lua/orgmode/org/mappings.lua index a1a6bc470..61866fb80 100644 --- a/lua/orgmode/org/mappings.lua +++ b/lua/orgmode/org/mappings.lua @@ -16,6 +16,7 @@ local Promise = require('orgmode.utils.promise') local events = EventManager.event local Link = require('orgmode.org.hyperlinks.link') local Babel = require('orgmode.babel') +local OrgApi = require('orgmode.api') ---@class OrgMappings ---@field capture OrgCapture @@ -736,50 +737,7 @@ function OrgMappings:insert_link() return end - local selected_link = Link:new(link_location) - local desc = selected_link.url:get_target_value() - if selected_link.url:is_id() then - local id_link = ('id:%s'):format(selected_link.url:get_id()) - desc = link_location:gsub('^' .. vim.pesc(id_link) .. '%s+', '') - link_location = id_link - end - - local link_description = vim.trim(vim.fn.OrgmodeInput('Description: ', desc or '')) - - link_location = '[' .. vim.trim(link_location) .. ']' - - if link_description ~= '' then - link_description = '[' .. link_description .. ']' - end - - local insert_from - local insert_to - local target_col = #link_location + #link_description + 2 - - -- check if currently on link - local link, position = self:_get_link_under_cursor() - if link and position then - insert_from = position.from - 1 - insert_to = position.to + 1 - target_col = target_col + position.from - else - local colnr = vim.fn.col('.') - insert_from = colnr - insert_to = colnr + 1 - target_col = target_col + colnr - end - - local linenr = vim.fn.line('.') or 0 - local curr_line = vim.fn.getline(linenr) - local new_line = string.sub(curr_line, 0, insert_from) - .. '[' - .. link_location - .. link_description - .. ']' - .. string.sub(curr_line, insert_to, #curr_line) - - vim.fn.setline(linenr, new_line) - vim.fn.cursor(linenr, target_col) + OrgApi.insert_link(link_location) end function OrgMappings:store_link() @@ -823,7 +781,7 @@ function OrgMappings:_edit_special_callback() end function OrgMappings:open_at_point() - local link = self:_get_link_under_cursor() + local link = Hyperlinks.get_link_under_cursor() if not link then local date = self:_get_date_under_cursor() if date then @@ -1138,13 +1096,6 @@ function OrgMappings:_adjust_date(amount, span, fallback) return vim.api.nvim_feedkeys(utils.esc(fallback), 'n', true) end ----@return OrgLink|nil, table | nil -function OrgMappings:_get_link_under_cursor() - local line = vim.fn.getline('.') - local col = vim.fn.col('.') or 0 - return Link.at_pos(line, col) -end - ---@param headline OrgHeadline function OrgMappings:_goto_headline(headline) local current_file_path = utils.current_file_path() From 5732cf31070ae29d34c5e393e4305efbbe1b3406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Fl=C3=BCgge?= Date: Tue, 21 May 2024 23:49:14 +0200 Subject: [PATCH 2/2] refactor: move link insertion into Hyperlinks To have clean module dependencies, insert_link is now a method of Hyperlinks and is exposed over the api but also called from mappings. --- lua/orgmode/api/init.lua | 49 +---------------------------- lua/orgmode/org/hyperlinks/init.lua | 49 ++++++++++++++++++++++++++++- lua/orgmode/org/mappings.lua | 2 +- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/lua/orgmode/api/init.lua b/lua/orgmode/api/init.lua index 8a7d13379..ad479e0b4 100644 --- a/lua/orgmode/api/init.lua +++ b/lua/orgmode/api/init.lua @@ -10,10 +10,6 @@ local orgmode = require('orgmode') ---@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 local OrgApi = {} ---@param name? string|string[] specific file names to return (absolute path). If ommitted, returns all loaded files @@ -109,50 +105,7 @@ end --- @param link_location string --- @return boolean function OrgApi.insert_link(link_location) - local selected_link = Link:new(link_location) - local desc = selected_link.url:get_target_value() - if selected_link.url:is_id() then - local id_link = ('id:%s'):format(selected_link.url:get_id()) - desc = link_location:gsub('^' .. vim.pesc(id_link) .. '%s+', '') - link_location = id_link - end - - local link_description = vim.trim(vim.fn.OrgmodeInput('Description: ', desc or '')) - - link_location = '[' .. vim.trim(link_location) .. ']' - - if link_description ~= '' then - link_description = '[' .. link_description .. ']' - end - - local insert_from - local insert_to - local target_col = #link_location + #link_description + 2 - - -- check if currently on link - local link, position = Hyperlinks.get_link_under_cursor() - if link and position then - insert_from = position.from - 1 - insert_to = position.to + 1 - target_col = target_col + position.from - else - local colnr = vim.fn.col('.') - insert_from = colnr - insert_to = colnr + 1 - target_col = target_col + colnr - end - - local linenr = vim.fn.line('.') or 0 - local curr_line = vim.fn.getline(linenr) - local new_line = string.sub(curr_line, 0, insert_from) - .. '[' - .. link_location - .. link_description - .. ']' - .. string.sub(curr_line, insert_to, #curr_line) - - vim.fn.setline(linenr, new_line) - vim.fn.cursor(linenr, target_col) + Hyperlinks.insert_link(link_location) end return OrgApi diff --git a/lua/orgmode/org/hyperlinks/init.lua b/lua/orgmode/org/hyperlinks/init.lua index 3ff367b2a..237d61892 100644 --- a/lua/orgmode/org/hyperlinks/init.lua +++ b/lua/orgmode/org/hyperlinks/init.lua @@ -205,7 +205,7 @@ function Hyperlinks.autocomplete_links(arg_lead) return vim.tbl_keys(Hyperlinks.stored_links) end --- + ---@return OrgLink|nil, table | nil function Hyperlinks.get_link_under_cursor() local line = vim.fn.getline('.') @@ -213,4 +213,51 @@ function Hyperlinks.get_link_under_cursor() return Link.at_pos(line, col) end +function Hyperlinks.insert_link(link_location) + local selected_link = Link:new(link_location) + local desc = selected_link.url:get_target_value() + if selected_link.url:is_id() then + local id_link = ('id:%s'):format(selected_link.url:get_id()) + desc = link_location:gsub('^' .. vim.pesc(id_link) .. '%s+', '') + link_location = id_link + end + + local link_description = vim.trim(vim.fn.OrgmodeInput('Description: ', desc or '')) + + link_location = '[' .. vim.trim(link_location) .. ']' + + if link_description ~= '' then + link_description = '[' .. link_description .. ']' + end + + local insert_from + local insert_to + local target_col = #link_location + #link_description + 2 + + -- check if currently on link + local link, position = Hyperlinks.get_link_under_cursor() + if link and position then + insert_from = position.from - 1 + insert_to = position.to + 1 + target_col = target_col + position.from + else + local colnr = vim.fn.col('.') + insert_from = colnr + insert_to = colnr + 1 + target_col = target_col + colnr + end + + local linenr = vim.fn.line('.') or 0 + local curr_line = vim.fn.getline(linenr) + local new_line = string.sub(curr_line, 0, insert_from) + .. '[' + .. link_location + .. link_description + .. ']' + .. string.sub(curr_line, insert_to, #curr_line) + + vim.fn.setline(linenr, new_line) + vim.fn.cursor(linenr, target_col) +end + return Hyperlinks diff --git a/lua/orgmode/org/mappings.lua b/lua/orgmode/org/mappings.lua index 61866fb80..4c81dc97f 100644 --- a/lua/orgmode/org/mappings.lua +++ b/lua/orgmode/org/mappings.lua @@ -737,7 +737,7 @@ function OrgMappings:insert_link() return end - OrgApi.insert_link(link_location) + Hyperlinks.insert_link(link_location) end function OrgMappings:store_link()