-
-
Notifications
You must be signed in to change notification settings - Fork 163
[WIP][RFC] Hyperlink Refactor - Registry Version #793
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
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
local utils = require('orgmode.utils') | ||
local Org = require('orgmode') | ||
local Internal = require('orgmode.org.hyperlinks.builtin.internal') | ||
|
||
---@class OrgLinkHandlerCustomId:OrgLinkHandlerInternal | ||
local CustomId = Internal:new() | ||
|
||
function CustomId:new(custom_id) | ||
---@class OrgLinkHandlerCustomId | ||
local this = Internal:new() | ||
this.custom_id = custom_id | ||
setmetatable(this, self) | ||
self.__index = self | ||
return this | ||
end | ||
|
||
---@param input string | ||
function CustomId.parse(input) | ||
return CustomId:new(input) | ||
end | ||
|
||
function CustomId:__tostring() | ||
return string.format('#%s', self.custom_id) | ||
end | ||
|
||
function CustomId:follow() | ||
local headlines = Org.files:get_current_file():find_headlines_with_property_matching('custom_id', self.custom_id) | ||
|
||
if #headlines == 0 then | ||
return utils.echo_warning(('Could not find custom ID "%s".'):format(self.custom_id)) | ||
end | ||
|
||
utils.goto_oneof(headlines) | ||
end | ||
|
||
function CustomId:insert_description() | ||
return self.custom_id | ||
end | ||
|
||
function CustomId:complete(lead, context) | ||
local file = self.get_file_from_context(context) | ||
local headlines = file:find_headlines_with_property_matching('CUSTOM_ID', lead) | ||
|
||
local completions = {} | ||
for _, headline in pairs(headlines) do | ||
local id = headline:get_property('CUSTOM_ID') | ||
table.insert(completions, tostring(self:new(id))) | ||
end | ||
|
||
return completions | ||
end | ||
|
||
return CustomId |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
local utils = require('orgmode.utils') | ||
local Org = require('orgmode') | ||
local Internal = require('orgmode.org.hyperlinks.builtin.internal') | ||
local Id = require('orgmode.org.hyperlinks.builtin.id') | ||
|
||
---@class OrgLinkHandlerHeadline:OrgLinkHandlerInternal | ||
local Headline = Internal:new() | ||
|
||
function Headline:new(headline) | ||
---@class OrgLinkHandlerHeadline | ||
local this = Internal:new() | ||
this.headline = headline | ||
setmetatable(this, self) | ||
self.__index = self | ||
return this | ||
end | ||
|
||
---@param input string | ||
function Headline.parse(input) | ||
return Headline:new(input) | ||
end | ||
|
||
function Headline:__tostring() | ||
return string.format('*%s', self.headline) | ||
end | ||
|
||
function Headline:follow() | ||
local headlines = Org.files:get_current_file():find_headlines_by_title(self.headline) | ||
|
||
if #headlines == 0 then | ||
return utils.echo_warning(('Could not find headline "%s".'):format(self.headline)) | ||
end | ||
|
||
utils.goto_oneof(headlines) | ||
end | ||
|
||
function Headline:insert_description() | ||
return self.headline | ||
end | ||
|
||
function Headline:complete(lead, context) | ||
local file = self.get_file_from_context(context) | ||
local headlines = file:find_headlines_by_title(lead) | ||
|
||
local completions = {} | ||
for _, headline in pairs(headlines) do | ||
table.insert(completions, tostring(Headline:new(headline:get_title()))) | ||
end | ||
|
||
return completions | ||
end | ||
|
||
return Headline |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
local Internal = require('orgmode.org.hyperlinks.builtin.internal') | ||
|
||
---@class OrgLinkHandlerLineNumber:OrgLinkHandlerInternal | ||
local LineNumber = Internal:new() | ||
|
||
function LineNumber:new(line_number) | ||
---@class OrgLinkHandlerLineNumber | ||
local this = Internal:new() | ||
this.line_number = line_number | ||
setmetatable(this, self) | ||
self.__index = self | ||
return this | ||
end | ||
|
||
---@param input string | ||
function LineNumber.parse(input) | ||
return LineNumber:new(tonumber(input)) | ||
end | ||
|
||
function LineNumber:__tostring() | ||
return string.format('%d', self.line_number) | ||
end | ||
|
||
function LineNumber:follow() | ||
vim.cmd(('normal! %dGzv'):format(self.line_number)) | ||
end | ||
|
||
return LineNumber |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
local utils = require('orgmode.utils') | ||
local Org = require('orgmode') | ||
local Internal = require('orgmode.org.hyperlinks.builtin.internal') | ||
|
||
---@class OrgLinkHandlerPlain:OrgLinkHandlerInternal | ||
local Plain = Internal:new() | ||
|
||
function Plain:new(text) | ||
---@class OrgLinkHandlerPlain | ||
local this = Internal:new() | ||
this.text = text | ||
setmetatable(this, self) | ||
self.__index = self | ||
return this | ||
end | ||
|
||
---@param input string | ||
function Plain.parse(input) | ||
return Plain:new(input) | ||
end | ||
|
||
function Plain:__tostring() | ||
return self.text | ||
end | ||
|
||
function Plain:follow() | ||
local anchors = vim.fn.matchbufline(0, ('<<<?%s[^>]*>>>?'):format(self.text), 0, '$') | ||
|
||
if #anchors >= 1 then | ||
vim.fn.cursor(anchors[1].lnum, anchors[1].byteidx) | ||
return | ||
end | ||
|
||
-- TODO from here, behaviour should depend on org-link-search-must-match-exact-headline | ||
-- TODO #+NAME tag support should be added, but it didn't exists yet | ||
|
||
local plain_text_matches = vim.fn.matchbufline(0, self.text, 0, '$') | ||
|
||
if #plain_text_matches >= 1 then | ||
vim.fn.cursor(plain_text_matches[1].lnum, plain_text_matches[1].byteidx) | ||
return | ||
end | ||
|
||
return utils.echo_warning(('No matches found for "%s".'):format(self.text)) | ||
end | ||
|
||
function Plain:insert_description() | ||
return self.text | ||
end | ||
|
||
-- TODO #+NAME tag support should be added, but it didn't exists yet | ||
function Plain:complete(lead, context) | ||
local file = self.get_file_from_context(context) | ||
local completions = {} | ||
|
||
local anchors = file.content:gmatch(('<<<?%s[^>]*>>>?'):format(lead)) | ||
for anchor in anchors do | ||
table.insert(completions, tostring(Plain:new(anchor))) | ||
end | ||
|
||
local headlines = file:find_headlines_by_title(lead) | ||
for _, headline in pairs(headlines) do | ||
table.insert(completions, tostring(Plain:new(headline:get_title()))) | ||
end | ||
|
||
return completions | ||
end | ||
|
||
return Plain |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
local fs = require('orgmode.utils.fs') | ||
local Link = require('orgmode.org.links.link_handler') | ||
local Id = require('orgmode.org.links.handlers.id') | ||
local Internal = require('orgmode.org.links.handlers.internal') | ||
|
||
---@class OrgLinkHandlerFile:OrgLinkHandler | ||
---@field new fun(self: OrgLinkHandlerFile, path: string, target: OrgLinkHandlerInternal | nil, prefix: boolean | nil, files: OrgFile[]): OrgLinkHandlerFile | ||
---@field parse fun(link: string, prefix: boolean | nil): OrgLinkHandlerFile | nil | ||
---@field path string | ||
---@field skip_prefix boolean | ||
---@field target OrgLinkHandlerInternal | nil | ||
local File = Link:new('file') | ||
|
||
function File:new(path, target, skip_prefix, files) | ||
---@class OrgLinkHandlerFile | ||
local this = Link:new() | ||
this.skip_prefix = skip_prefix or false | ||
this.path = path | ||
this.target = target | ||
this.files = files | ||
setmetatable(this, self) | ||
self.__index = self | ||
return this | ||
end | ||
|
||
-- TODO make protocol prefix optional. Based on what? | ||
function File:__tostring() | ||
local v = '' | ||
if self.skip_prefix then | ||
v = ('%s'):format(self.path) | ||
else | ||
v = ('%s:%s'):format(self.protocol, self.path) | ||
end | ||
|
||
if self.target then | ||
v = string.format('%s::%s', v, self.target) | ||
end | ||
|
||
return v | ||
end | ||
|
||
function File:follow() | ||
vim.cmd('edit ' .. fs.get_real_path(self.path)) | ||
|
||
if self.target then | ||
self.target:follow() | ||
end | ||
end | ||
|
||
function File:_autocompletions_filenames(lead) | ||
local filenames = self.files:filenames() | ||
|
||
local matches = {} | ||
for _, f in ipairs(filenames) do | ||
local realpath = fs.substitute_path(lead) or lead | ||
if f:find('^' .. realpath) then | ||
local path = f:gsub('^' .. realpath, lead) | ||
table.insert(matches, { real = f, path = path }) | ||
end | ||
end | ||
|
||
print(vim.inspect(matches)) | ||
return matches | ||
end | ||
|
||
function File:insert_description() | ||
local Org = require('orgmode') | ||
if self.target then | ||
return self.target:insert_description() | ||
end | ||
|
||
local path = fs.get_real_path(self.path) | ||
if not path then | ||
return nil | ||
end | ||
local file = Org.files:get(path) | ||
if not file then | ||
return nil | ||
end | ||
|
||
return file:get_title() | ||
end | ||
|
||
local FileFactory = {} | ||
|
||
function FileFactory:init(files) | ||
self.files = files | ||
end | ||
|
||
function FileFactory:new(path, target, skip_prefix) | ||
return File:new(path, target, skip_prefix, self.files) | ||
end | ||
|
||
function FileFactory:parse(input, skip_prefix) | ||
if input == nil or #input == 0 then | ||
return nil | ||
end | ||
local deliniator_start, deliniator_stop = input:find('::') | ||
|
||
---@type OrgLinkHandlerInternal | nil | ||
local target = nil | ||
local path = input | ||
|
||
if deliniator_start then | ||
---@class OrgLinkHandlerInternal | nil | ||
target = Internal.parse(input:sub(deliniator_stop + 1), true) | ||
path = input:sub(0, deliniator_start - 1) | ||
end | ||
|
||
self:new(path, target, skip_prefix) | ||
end | ||
|
||
function FileFactory:complete(lead, context) | ||
context = context or {} | ||
local deliniator_start, deliniator_stop = lead:find('::') | ||
|
||
if not deliniator_start then | ||
return self:_complete(lead, context) | ||
else | ||
local path = lead:sub(0, deliniator_start - 1) | ||
local target_lead = lead:sub(deliniator_stop + 1) | ||
return self:_complete_targets(path, target_lead, context) | ||
end | ||
end | ||
|
||
function FileFactory:_complete(lead, context) | ||
return vim.tbl_map(function(f) | ||
return tostring(self:new(f, nil, context.skip_prefix)) | ||
end, self:_autocompletions_filenames(lead)) | ||
end | ||
|
||
function FileFactory:_complete_targets(path, target_lead, context) | ||
return vim.tbl_map( | ||
function(t) | ||
return tostring(self:new(path, t, context.skip_prefix)) | ||
end, | ||
Internal:complete(target_lead, { | ||
filename = fs.get_real_path(path), | ||
only_internal = true, | ||
}) | ||
) | ||
end | ||
|
||
return FileFactory |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should pass down
files
from the top through constructor instead of requiringorgmode
directly.