diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..adbdb1b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = space +indent_size = 4 diff --git a/README.md b/README.md index 653fc7e..cd8c588 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,21 @@ With `Telescope neorg search_headings` you can search through all the headings i search_headings +### Search File and Heading Backlinks +- `Telescope neorg find_backlinks` - find every line in your workspace that links^* to the current file +- `Telescope neorg find_header_backlinks` - same but with links to the current file _and_ heading + +These are limited to workspace relative links (ie. +`{:$/worspace/relative/path:}`) for the sake of simplicity. Both exact +(`{:$/path:** lvl 2 heading}`) and fuzzy (`{:$/path:# heading}`) links are +found. + +
+ Demo + +![search backlink](https://github.com/nvim-neorg/neorg-telescope/assets/56943754/37a5b68f-29b3-43ae-a679-9656cfa646db) +
+ ## Gtd Pickers ### Those pickers are all broken since gtd was removed in core
diff --git a/lua/neorg/modules/core/integrations/telescope/module.lua b/lua/neorg/modules/core/integrations/telescope/module.lua index 82a7cec..afe51f2 100644 --- a/lua/neorg/modules/core/integrations/telescope/module.lua +++ b/lua/neorg/modules/core/integrations/telescope/module.lua @@ -28,6 +28,8 @@ module.load = function() "find_aof_tasks", "find_context_tasks", "switch_workspace", + "find_backlinks", + "find_header_backlinks", }) end @@ -42,6 +44,8 @@ module.public = { find_aof_tasks = require("telescope._extensions.neorg.find_aof_tasks"), find_aof_project_tasks = require("telescope._extensions.neorg.find_aof_project_tasks"), switch_workspace = require("telescope._extensions.neorg.switch_workspace"), + find_backlinks = require("telescope._extensions.neorg.backlinks.file_backlinks"), + find_header_backlinks = require("telescope._extensions.neorg.backlinks.header_backlinks"), } module.on_event = function(event) @@ -65,6 +69,10 @@ module.on_event = function(event) module.public.find_context_tasks() elseif event.split_type[2] == "core.integrations.telescope.switch_workspace" then module.public.switch_workspace() + elseif event.split_type[2] == "core.integrations.telescope.find_backlinks" then + module.public.find_backlinks() + elseif event.split_type[2] == "core.integrations.telescope.find_header_backlinks" then + module.public.find_header_backlinks() end end @@ -80,6 +88,8 @@ module.events.subscribed = { ["core.integrations.telescope.find_aof_tasks"] = true, ["core.integrations.telescope.find_aof_project_tasks"] = true, ["core.integrations.telescope.switch_workspace"] = true, + ["core.integrations.telescope.find_backlinks"] = true, + ["core.integrations.telescope.find_header_backlinks"] = true, }, } diff --git a/lua/neorg/telescope_utils.lua b/lua/neorg/telescope_utils.lua index 6bd5c74..20f5e5f 100644 --- a/lua/neorg/telescope_utils.lua +++ b/lua/neorg/telescope_utils.lua @@ -152,4 +152,15 @@ utils.get_project_tasks = function() return projects_tasks end +---Gets the full path to the current workspace +---@return string? +utils.get_current_workspace = function() + local dirman = neorg.modules.get_module("core.dirman") + if dirman then + local current_workspace = dirman.get_current_workspace()[2] + return current_workspace + end + return nil +end + return utils diff --git a/lua/telescope/_extensions/neorg.lua b/lua/telescope/_extensions/neorg.lua index ea5fe1d..5861243 100644 --- a/lua/telescope/_extensions/neorg.lua +++ b/lua/telescope/_extensions/neorg.lua @@ -10,5 +10,7 @@ return require("telescope").register_extension({ find_aof_tasks = require("neorg.modules.core.integrations.telescope.module").public.find_aof_tasks, find_aof_project_tasks = require("neorg.modules.core.integrations.telescope.module").public.find_aof_project_tasks, switch_workspace = require("neorg.modules.core.integrations.telescope.module").public.switch_workspace, + find_backlinks = require("neorg.modules.core.integrations.telescope.module").public.find_backlinks, + find_header_backlinks = require("neorg.modules.core.integrations.telescope.module").public.find_header_backlinks, }, }) diff --git a/lua/telescope/_extensions/neorg/backlinks/common.lua b/lua/telescope/_extensions/neorg/backlinks/common.lua new file mode 100644 index 0000000..65153ed --- /dev/null +++ b/lua/telescope/_extensions/neorg/backlinks/common.lua @@ -0,0 +1,27 @@ +local M = {} + +---produce the regular expression used to find workspace relative paths to the given file. +---Optionally takes a header that should exist in the current file +---@param workspace_path string "/abs/path/to/workspace" +---@param current_file string "test.norg" +---@param heading string? "** heading" +---@return string +M.build_backlink_regex = function(workspace_path, current_file, heading) + current_file = vim.api.nvim_buf_get_name(0) + current_file = current_file:gsub("%.norg$", "") + current_file = current_file:gsub("^" .. workspace_path .. "/", "") + + if not heading then + return ([[\{:\$/%s:.*\}]]):format(current_file) -- {:$/workspace_path:} + end + + local heading_prefix = heading:match("^%**") + if heading_prefix then + heading_prefix = heading_prefix:gsub("%*", "\\*") + end + local heading_text = heading:gsub("^%** ", "") + heading_text = heading_text:gsub("^%(.%)%s?", "") + return ([[\{:\$/%s:(#|%s) %s\}]]):format(current_file, heading_prefix, heading_text) -- {:$/workspace_path:(# heading or ** heading)} +end + +return M diff --git a/lua/telescope/_extensions/neorg/backlinks/file_backlinks.lua b/lua/telescope/_extensions/neorg/backlinks/file_backlinks.lua new file mode 100644 index 0000000..77e5a4b --- /dev/null +++ b/lua/telescope/_extensions/neorg/backlinks/file_backlinks.lua @@ -0,0 +1,19 @@ +local common = require("telescope._extensions.neorg.backlinks.common") +local utils = require("neorg.telescope_utils") + +return function() + local current_workspace = utils.get_current_workspace() + + if not current_workspace then + return + end + + local current_file = vim.api.nvim_buf_get_name(0) + + require("telescope.builtin").grep_string({ + search = common.build_backlink_regex(current_workspace, current_file), + use_regex = true, + search_dirs = { current_workspace }, + prompt_title = "File Backlinks", + }) +end diff --git a/lua/telescope/_extensions/neorg/backlinks/header_backlinks.lua b/lua/telescope/_extensions/neorg/backlinks/header_backlinks.lua new file mode 100644 index 0000000..9159579 --- /dev/null +++ b/lua/telescope/_extensions/neorg/backlinks/header_backlinks.lua @@ -0,0 +1,38 @@ +local common = require("telescope._extensions.neorg.backlinks.common") +local utils = require("neorg.telescope_utils") + +return function() + local current_workspace = utils.get_current_workspace() + + if not current_workspace then + return + end + + local current_file = vim.api.nvim_buf_get_name(0) + local linenr = vim.api.nvim_win_get_cursor(0)[1] + local lines = vim.api.nvim_buf_get_lines(0, 0, linenr, false) + local heading = nil + + -- HACK: iterate backward (up) over lines, and use the first heading we find. We should be using + -- TS instead, but I'm not super familiar with how to do things like that. + for i = #lines, 1, -1 do + local line = lines[i] + local potential_heading = line:match("^%s*%*+ .*$") + if potential_heading then + heading = potential_heading + break + end + end + + if not heading then + vim.notify("[Neorg Telescope] Couldn't find current heading", vim.log.levels.ERROR) + return + end + + require("telescope.builtin").grep_string({ + search = common.build_backlink_regex(current_workspace, current_file, heading), + use_regex = true, + search_dirs = { current_workspace }, + prompt_title = "Header Backlinks (" .. heading .. ")", + }) +end diff --git a/lua/telescope/_extensions/neorg/find_linkable.lua b/lua/telescope/_extensions/neorg/find_linkable.lua index 45236dc..92e0d18 100644 --- a/lua/telescope/_extensions/neorg/find_linkable.lua +++ b/lua/telescope/_extensions/neorg/find_linkable.lua @@ -1,23 +1,9 @@ -local neorg_loaded, neorg = pcall(require, "neorg.core") - -assert(neorg_loaded, "Neorg is not loaded - please make sure to load Neorg first") - -local function get_current_workspace() - local dirman = neorg.modules.get_module("core.dirman") - - if dirman then - local current_workspace = dirman.get_current_workspace()[2] - - return current_workspace - end - - return nil -end +local utils = require("neorg.telescope_utils") return function(opts) opts = opts or {} - local current_workspace = get_current_workspace() + local current_workspace = utils.get_current_workspace() if not current_workspace then return