Skip to content
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

Enable link opening from agenda #361

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
8 changes: 8 additions & 0 deletions DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,14 @@ Open selected agenda item in the same buffer
#### **org_agenda_goto**
*mapped to*: `{'<TAB>'}`<br />
Open selected agenda item in split window
#### **org_agenda_open_link**
*mapped to*: `<Leader>oo`<br />
Open hyperlink under cursor.<br />
Hyperlink types supported:
* URL (http://, https://)
* File (starts with `file:`. Example: `file:/home/user/.config/nvim/init.lua`) Optionally, a line number can be specified
using the '+' character. Example: `file:/home/user/.config/nvim/init.lua +10`
* Fallback: If file path, opens the file.<br />
#### **org_agenda_goto_date**
*mapped to*: `J`<br />
Open calendar that allows selecting date to jump to
Expand Down
66 changes: 66 additions & 0 deletions lua/orgmode/agenda/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ local AgendaSearchView = require('orgmode.agenda.views.search')
local AgendaTodosView = require('orgmode.agenda.views.todos')
local AgendaTagsView = require('orgmode.agenda.views.tags')
local AgendaView = require('orgmode.agenda.views.agenda')
local Hyperlinks = require('orgmode.org.hyperlinks')

---@class Agenda
---@field content table[]
Expand Down Expand Up @@ -245,6 +246,71 @@ function Agenda:change_todo_state()
})
end

function Agenda:open_link()
local link = Hyperlinks.get_link_under_cursor()
if not link then
return
end
local parts = vim.split(link, '][', true)
local url = parts[1]
local link_ctx = { base = url, skip_add_prefix = true }
-- file links
if url:find('^file:') then
if url:find(' +', 1, true) then
parts = vim.split(url, ' +', true)
url = parts[1]
local line_number = parts[2]
vim.cmd(string.format('edit +%s %s', line_number, url:sub(6)))
vim.cmd([[normal! zv]])
return
end

if url:find('^file:(.-)::') then
link_ctx.line = url
else
vim.cmd(string.format('edit %s', url:sub(6)))
vim.cmd([[normal! zv]])
return
end
end
-- web links
if url:find('^https?://') then
if not vim.g.loaded_netrwPlugin then
return utils.echo_warning('Netrw plugin must be loaded in order to open urls.')
end
return vim.fn['netrw#BrowseX'](url, vim.fn['netrw#CheckIfRemote']())
end
-- fallback: filepath
local stat = vim.loop.fs_stat(url)
if stat and stat.type == 'file' then
return vim.cmd(string.format('edit %s', url))
end
-- headline link
local headlines = Hyperlinks.find_matching_links(link_ctx)
if #headlines == 0 then
utils.echo_warning('foobar')
return
end
local headline = headlines[1]
if #headlines > 1 then
local longest_headline = utils.reduce(headlines, function(acc, h)
return math.max(acc, h.line:len())
end, 0)
local options = {}
for i, h in ipairs(headlines) do
table.insert(options, string.format('%d) %-' .. longest_headline .. 's (%s)', i, h.line, h.file))
end
vim.cmd([[echo "Multiple targets found. Select target:"]])
local choice = vim.fn.inputlist(options)
if choice < 1 or choice > #headlines then
return
end
headline = headlines[choice]
end
vim.cmd(string.format('edit %s', headline.file))
vim.fn.cursor(headline.range.start_line, 0)
end

function Agenda:clock_in()
return self:_remote_edit({
action = 'clock.org_clock_in',
Expand Down
1 change: 1 addition & 0 deletions lua/orgmode/config/defaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ return {
org_agenda_quit = 'q',
org_agenda_switch_to = '<CR>',
org_agenda_goto = '<TAB>',
org_agenda_open_link = '<prefix>o',
org_agenda_goto_date = 'J',
org_agenda_redo = 'r',
org_agenda_todo = 't',
Expand Down
1 change: 1 addition & 0 deletions lua/orgmode/config/mappings/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ return {
{ opts = { desc = 'org open agenda item (same buffer)' } }
),
org_agenda_goto = m.action('agenda.goto_item', { opts = { desc = 'org open agenda item (split buffer)' } }),
org_agenda_open_link = m.action('agenda.open_link', { opts = { desc = 'org open hyperlink' } }),
org_agenda_goto_date = m.action('agenda.goto_date', { opts = { desc = 'org goto date' } }),
org_agenda_redo = m.action('agenda.redo', { opts = { desc = 'org redo' } }),
org_agenda_todo = m.action('agenda.change_todo_state', { opts = { desc = 'org cycle todo state' } }),
Expand Down
18 changes: 18 additions & 0 deletions lua/orgmode/org/hyperlinks.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@ local Files = require('orgmode.parser.files')
local utils = require('orgmode.utils')
local Hyperlinks = {}

---@return string|nil
function Hyperlinks.get_link_under_cursor()
local found_link = nil
local links = {}
local line = vim.fn.getline('.')
local col = vim.fn.col('.')
for link in line:gmatch('%[%[(.-)%]%]') do
local start_from = #links > 0 and links[#links].to or nil
local from, to = line:find('%[%[(.-)%]%]', start_from)
if col >= from and col <= to then
found_link = link
break
end
table.insert(links, { link = link, from = from, to = to })
end
return found_link
end

local function get_file_from_context(ctx)
return (
ctx.hyperlinks and ctx.hyperlinks.filepath and Files.get(ctx.hyperlinks.filepath, true)
Expand Down
20 changes: 1 addition & 19 deletions lua/orgmode/org/mappings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ function OrgMappings:open_at_point()
return self.agenda:open_day(date)
end

local link = self:_get_link_under_cursor()
local link = Hyperlinks.get_link_under_cursor()
if not link then
return
end
Expand Down Expand Up @@ -910,22 +910,4 @@ function OrgMappings:_adjust_date(amount, span, fallback)
return vim.api.nvim_feedkeys(utils.esc(fallback), 'n', true)
end

---@return string|nil
function OrgMappings:_get_link_under_cursor()
local found_link = nil
local links = {}
local line = vim.fn.getline('.')
local col = vim.fn.col('.')
for link in line:gmatch('%[%[(.-)%]%]') do
local start_from = #links > 0 and links[#links].to or nil
local from, to = line:find('%[%[(.-)%]%]', start_from)
if col >= from and col <= to then
found_link = link
break
end
table.insert(links, { link = link, from = from, to = to })
end
return found_link
end

return OrgMappings