From 2e96a4bf7a2e84580414b3f7d530b51ccf56d372 Mon Sep 17 00:00:00 2001 From: kiyan Date: Sun, 10 Jul 2022 11:33:12 +0200 Subject: [PATCH] feat(bookmarks): add bookmark feature for nodes Uses the signcolum to display the mark status. Marks are saved in memory for now, we'll see if we want to implement a filesystem save for the marks (would not be hard). Added `m` keybinding to toggle the mark on the node. Users can call `require "nvim-tree.marks".get_marks()` which returns a list of absolute paths. --- doc/nvim-tree-lua.txt | 19 ++++++ lua/nvim-tree.lua | 2 + lua/nvim-tree/actions/dispatch.lua | 1 + lua/nvim-tree/actions/init.lua | 5 ++ lua/nvim-tree/colors.lua | 2 + lua/nvim-tree/iterators/node-iterator.lua | 16 +++--- lua/nvim-tree/marks.lua | 70 +++++++++++++++++++++++ lua/nvim-tree/renderer/init.lua | 3 + 8 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 lua/nvim-tree/marks.lua diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 18f3aa916f6..bb190e712ca 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -14,6 +14,7 @@ CONTENTS *nvim-tree* 6. Highlight Groups |nvim-tree-highlight| 7. Events |nvim-tree-events| 7.1 Available Events |nvim-tree.events| + 8. Bookmarks |nvim-tree-bookmarks| ============================================================================== 1. INTRODUCTION *nvim-tree-introduction* @@ -220,6 +221,7 @@ Subsequent calls to setup will replace the previous configuration. glyphs = { default = "", symlink = "", + bookmark = "", folder = { arrow_closed = "", arrow_open = "", @@ -1012,6 +1014,7 @@ DEFAULT MAPPINGS *nvim-tree-default-mappings `.` run_file_command enter vim command mode with the file the cursor is on `` toggle_file_info toggle a popup with file infos about the file under the cursor `g?` toggle_help toggle help +`m` toggle_mark Toggle node in bookmarks > view.mappings.list = { -- BEGIN_DEFAULT_MAPPINGS @@ -1059,6 +1062,7 @@ DEFAULT MAPPINGS *nvim-tree-default-mappings { key = ".", action = "run_file_command" } { key = "", action = "toggle_file_info" } { key = "g?", action = "toggle_help" } + { key = "m", action = "toggle_mark" } } -- END_DEFAULT_MAPPINGS < ============================================================================== @@ -1130,6 +1134,11 @@ There are 2 highlight groups for the live filter feature NvimTreeLiveFilterPrefix NvimTreeLiveFilterValue +Color of the bookmark icon + +NvimTreeBookmark + + ============================================================================== 7. EVENTS *nvim-tree-events* @@ -1245,4 +1254,14 @@ on_tree_resize({handler}) {handler} `{function}` Handler function, with the signature `function(size)`. +============================================================================== + 8. BOOKMARKS *nvim-tree-bookmarks* + +You can toggle marks on files/folders with +`require("nvim-tree.marks").toggle_mark(node)` which is bound to `m` by +default. + +To get the list of marked paths, you can call +`require("nvim-tree.marks").get_marks()`. This will return `{string}`. + vim:tw=78:ts=4:sw=4:et:ft=help:norl: diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index 3067eae9267..3ea2d194e83 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -469,6 +469,7 @@ local DEFAULT_OPTS = { -- BEGIN_DEFAULT_OPTS glyphs = { default = "", symlink = "", + bookmark = "", folder = { arrow_closed = "", arrow_open = "", @@ -674,6 +675,7 @@ function M.setup(conf) require("nvim-tree.lib").setup(opts) require("nvim-tree.renderer").setup(opts) require("nvim-tree.live-filter").setup(opts) + require("nvim-tree.marks").setup(opts) if M.config.renderer.icons.show.file and pcall(require, "nvim-web-devicons") then require("nvim-web-devicons").setup() end diff --git a/lua/nvim-tree/actions/dispatch.lua b/lua/nvim-tree/actions/dispatch.lua index 0602c58a009..ae8cbb4ce94 100644 --- a/lua/nvim-tree/actions/dispatch.lua +++ b/lua/nvim-tree/actions/dispatch.lua @@ -45,6 +45,7 @@ local Actions = { run_file_command = require("nvim-tree.actions.node.run-command").run_file_command, toggle_file_info = require("nvim-tree.actions.node.file-popup").toggle_file_info, system_open = require("nvim-tree.actions.node.system-open").fn, + toggle_mark = require("nvim-tree.marks").toggle_mark, } local function handle_action_on_help_ui(action) diff --git a/lua/nvim-tree/actions/init.lua b/lua/nvim-tree/actions/init.lua index 4c18cb3a75a..77cb3270b03 100644 --- a/lua/nvim-tree/actions/init.lua +++ b/lua/nvim-tree/actions/init.lua @@ -227,6 +227,11 @@ local DEFAULT_MAPPINGS = { action = "toggle_help", desc = "toggle help", }, + { + key = "m", + action = "toggle_mark", + desc = "Toggle node in bookmarks", + }, } -- END_DEFAULT_MAPPINGS diff --git a/lua/nvim-tree/colors.lua b/lua/nvim-tree/colors.lua index 1bf071252e5..908aa9c3b89 100644 --- a/lua/nvim-tree/colors.lua +++ b/lua/nvim-tree/colors.lua @@ -53,6 +53,8 @@ local function get_hl_groups() WindowPicker = { gui = "bold", fg = "#ededed", bg = "#4493c8" }, LiveFilterPrefix = { gui = "bold", fg = colors.purple }, LiveFilterValue = { gui = "bold", fg = "#fff" }, + + Bookmark = { fg = colors.green }, } end diff --git a/lua/nvim-tree/iterators/node-iterator.lua b/lua/nvim-tree/iterators/node-iterator.lua index d285973bab2..e4a1d0bb0fc 100644 --- a/lua/nvim-tree/iterators/node-iterator.lua +++ b/lua/nvim-tree/iterators/node-iterator.lua @@ -38,27 +38,25 @@ function NodeIterator:recursor(f) end function NodeIterator:iterate() + local iteration_count = 0 local function iter(nodes) - local i = 1 for _, node in ipairs(nodes) do if self._filter_hidden(node) then + iteration_count = iteration_count + 1 if self._match(node) then - return node, i + return node, iteration_count end - self._apply_fn_on_node(node) + self._apply_fn_on_node(node, iteration_count) local children = self._recurse_with(node) if children then - local n, idx = iter(children) - i = i + idx + local n = iter(children) if n then - return n, i + return n, iteration_count end - else - i = i + 1 end end end - return nil, i + return nil, 0 end return iter(self.nodes) diff --git a/lua/nvim-tree/marks.lua b/lua/nvim-tree/marks.lua new file mode 100644 index 00000000000..ac399e0274c --- /dev/null +++ b/lua/nvim-tree/marks.lua @@ -0,0 +1,70 @@ +local view = require "nvim-tree.view" +local Iterator = require "nvim-tree.iterators.node-iterator" +local core = require "nvim-tree.core" + +local NvimTreeMarks = {} + +local M = {} + +local function add_mark(node) + NvimTreeMarks[node.absolute_path] = true + M.draw() +end + +local function remove_mark(node) + NvimTreeMarks[node.absolute_path] = nil + M.draw() +end + +function M.toggle_mark(node) + if M.get_mark(node) then + remove_mark(node) + else + add_mark(node) + end +end + +function M.get_mark(node) + return NvimTreeMarks[node.absolute_path] +end + +function M.get_marks() + local list = {} + for k in pairs(NvimTreeMarks) do + table.insert(list, k) + end + return list +end + +local GROUP = "NvimTreeMarkSigns" +local SIGN_NAME = "NvimTreeMark" + +function M.clear() + vim.fn.sign_unplace(GROUP) +end + +function M.draw() + if not view.is_visible() then + return + end + + M.clear() + + local buf = view.get_bufnr() + Iterator.builder(core.get_explorer().nodes) + :recursor(function(node) + return node.open and node.nodes + end) + :applier(function(node, idx) + if M.get_mark(node) then + vim.fn.sign_place(0, GROUP, SIGN_NAME, buf, { lnum = idx + 1, priority = 3 }) + end + end) + :iterate() +end + +function M.setup(opts) + vim.fn.sign_define(SIGN_NAME, { text = opts.renderer.icons.glyphs.bookmark, texthl = "NvimTreeBookmark" }) +end + +return M diff --git a/lua/nvim-tree/renderer/init.lua b/lua/nvim-tree/renderer/init.lua index 31d77e45297..1efe31d68c8 100644 --- a/lua/nvim-tree/renderer/init.lua +++ b/lua/nvim-tree/renderer/init.lua @@ -10,6 +10,7 @@ local help = require "nvim-tree.renderer.help" local git = require "nvim-tree.renderer.components.git" local Builder = require "nvim-tree.renderer.builder" local live_filter = require "nvim-tree.live-filter" +local marks = require "nvim-tree.marks" local api = vim.api @@ -88,8 +89,10 @@ function M.draw() if view.is_help_ui() then diagnostics.clear() + marks.clear() else diagnostics.update() + marks.draw() end view.grow_from_content()