nvim-orgmode / nvim-orgmode/orgmode

Enhanced API for advanced Hyperlink handling

Open
#962 0 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Lua
Stars
3.9k
Forks
190
Avg merge
2d 13h
Merged PRs (30d)
7

Description

Does this feature exist in Emacs orgmode core?

N/A

Orgmode link

No response

Feature value

Hi there! I wanted to share some thoughts on the hyperlink system after using it more extensively in my personal notes. I've been really impressed with how the hyperlink functionality has evolved recently, especially since I last contributed to this part of the codebase some time ago. The recent improvements to the system are a big step forward, but I've encountered some limitations when I tried to implement more advanced workflows in my personal setup. I believe that with a few small extensions to the API, these limitations could be overcome, allowing users and plugin creators to implement their own extensions to enrich link handling.

My Use Case

I'd like to customize how different types of links are handled in specific contexts. For example:

  1. Opening directory links like [[some/folder/]] in different file explorers based on context:

    • Document directories → neotree/nvim-tree/oil-buffer
    • Project directories → external file manager/new neovim-instance/vs code
  2. Adding preview capabilities to links:

    • Preview images without leaving the buffer
    • Preview org headlines before navigating to them
    • Show file metadata without opening files
    • Open-with plugin
  3. Controlling where links open:

    • Choose destination splits/windows
    • Open in background tabs

Current Limitations

I've explored the existing hyperlinks.sources configuration, which is great for adding custom link types. However, I've found some limitations:

  1. Single action per link type: The current API is focused on "following" links, but doesn't support alternative actions like "preview"

  2. Built-in handlers are fixed: Can't easily extend built-in handlers (like file:) without replacing them entirely

  3. No way to access link data: No method to get the current link's data without following it

Proposed Enhancements

I've thought about some minimal API additions that would enable these workflows without major changes:

1. Link Context Access Function
-- Get link at cursor without following it
require('orgmode').api.get_link_at_cursor()

This would return parsed link information, enabling custom keymaps like:

vim.keymap.set('n', 'K', function()
  local link = require('orgmode').api.get_link_at_cursor()
  if not link then return end
  
  -- Preview based on link type
  if link.path:match('%.png$') or link.path:match('%.jpg$') then
    require('image_preview').show(link.path)
  elseif link.type == 'headline' then
    require('headline_preview').show(link.path, link.target)
  end
end)
2. Link Follow Options

Add a minimal API method to follow links with options:

-- Follow a link with options (useful for custom keymaps)
require('orgmode').api.follow_link(link_string, {
  split = "vertical", -- or "horizontal", nil for current window
  background = false, -- true to return to current position after opening
})

-- Example custom keymap using this
vim.keymap.set('n', '<leader>ov', function()
  local link = require('orgmode').api.get_link_at_cursor()
  if link then
    require('orgmode').api.follow_link(link.raw, {split = "vertical"})
  end
end)
3. Extended File Link Handler Configuration

Enhance the existing configuration to support conditional handling:

require('orgmode').setup({
  hyperlinks = {
    file_handlers = {
      -- Pattern-based directory handling
      directories = {
        ['~/projects/.*/$'] = function(path) 
          require('neo-tree').open(path)
          return true
        end,
        ['~/documents/.*/$'] = function(path)
          vim.fn.jobstart('dolphin ' .. path, {detach = true})
          return true
        end
      },
      -- Handle specific file types differently
      files = {
        ['%.pdf$'] = function(path)
          vim.fn.jobstart('okular ' .. path, {detach = true})
          return true
        end,
        ['%.org$'] = function(path, target)
          -- Custom org file handler with window selection
          require('window_picker').pick(function(win)
            vim.api.nvim_set_current_win(win)
            -- Use the original handler to navigate to target
            require('orgmode').api.follow_file_link(path, target)
          end)
          return true
        end
      }
    }
  }
})

Benefits

These minimal changes would:

  1. Enable completely custom link workflows through regular Neovim keymaps
  2. Keep the core API simple (only 2-3 new functions)
  3. Maintain backward compatibility
  4. Allow plugins to build advanced link handling while leveraging orgmode's link parsing

@kristijanhusak What do you think of this approach? Would you be open to these types of enhancements? If so, I would be happy to contribute a PR.

Additional context

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the existing hyperlinks.sources configuration and the current hyperlink handling API, then compare its capabilities with the proposed link-context, follow-options, and file-handler extensions. Done requires an agreed, scoped API design before implementation; the issue names no files or tests and leaves the final behavior open.

Written by the indexing model from the issue text.

Assessment

Tech stack
lua
Domain
api, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.