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

Visual Selection #2994

Open
alex-courtis opened this issue Nov 8, 2024 Discussed in #2993 · 4 comments
Open

Visual Selection #2994

alex-courtis opened this issue Nov 8, 2024 Discussed in #2993 · 4 comments
Labels
feature request PR please nvim-tree team does not have the bandwidth to implement; a PR will be gratefully appreciated QOL Quality Of Life Improvement

Comments

@alex-courtis
Copy link
Member

Discussed in #2993

Originally posted by l00sed November 9, 2024
First of all, thank you so much to the open source community, the plugin author, and plugin contributors. Nvim Tree is a fantastic plugin and part of my everyday workflow. 🌳

Some Background, Visual Selection

The vim-centric way to delete multiple lines of text is to first Shift-v— visually select a full line of text. Next, with the visual line selection, I could navigate (j or k) to expand the selection area down or up, respectively. See below:

Screen.Recording.2024-11-08.at.9.13.43.AM.mov

I would love to mimic this behavior for selecting multiple files in Nvim Tree, using <S-v> to visually select files or folders, then pressing c (for example, to copy) or d (to delete)— or running any action against that selection of files.

Performing the selection this way, using the standard Vim visual selection, would feel like a seamless extension of normal buffer behavior.

Example Scenario

I want to delete several markdown files from a folder, blog. The files are in consecutive order, so I can <S-v> to visually select the first file to delete (car-hacking.mdx) and then press j several times to expand the selection downward. Pressing d deletes the selected files.

Screen.Recording.2024-11-08.at.9.20.17.AM.mov

Does anyone have an existing recipe that makes this behavior possible? Perhaps using the existing buffer marking (m) behavior as a way to integrate the key-bindings somehow?

I suspect there are other people interested in this as well— or those who may have already found a solution. Funny enough, I found a stack overflow issue related to NERD Tree which was likely asked in the hope of achieving the same visual-selection behavior in this other Neovim tree-based file manager.

Other relevant discussions:

@alex-courtis
Copy link
Member Author

This feature would be incredible!

I've found myself naturally doing the same: <s-v> j j d
That somewhat maps to marks m j m j m bd
<s-v> j j y p to clipboard c j c j c p
A repcipe to do this sort of mapping would be a bit clunky and failure prone, and will interfere with existing functionality.

A first class solution is desirable.
We cannot use marks as they have use cases other than file manipulation.
We can use the clipboard.
As a start: perhaps:

  • visual x: marks the visual selection as cut (regular x), clearing other cut and copied
  • visual y or c: marks as copied, clearing
  • visual d: deletes

As usual, pull requests are most gratefully appreciated, see CONTRIBUTING.md

@alex-courtis alex-courtis added feature request QOL Quality Of Life Improvement PR please nvim-tree team does not have the bandwidth to implement; a PR will be gratefully appreciated labels Nov 8, 2024
@LisovAlexey
Copy link

While we can't use bookmarkings because they have other usages, I found it very useful to have at least bookmarking-based selection feature. Here I implemented working with visual selection through selection multiple bookmarking in visual mode. By itself it can be separate feature that can be useful in some cases.

I attached basic function that works on the.

Here is the showcase of three commands (adding bookmarking, deleting them and toggle).

123-6000.mp4
And the code for mentioned commands
local function mark_files_in_visual_selection(action) -- mode: "toggle" = 0, "mark_all" = 1, "disable_all_marks" = 2
	print("Current mode is:", action)
	if action == 0 then
		print("It should print 0!")
	end

	local api = require("nvim-tree.api")
	local view = require("nvim-tree.view")

	-- Check if nvim-tree is visible
	if not view.is_visible() then
		print("This function can only be run in nvim-tree.")
		return
	end

	-- Check if we are in visual line mode
	local mode = vim.api.nvim_get_mode().mode
	if mode ~= "V" then
		print("This function can only be run in visual line selection mode.")
		return
	end

	-- Exit Visual Mode (simulate pressing <Esc>)
	vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Esc>", true, false, true), "x", false)

	-- Get the nvim-tree window and buffer
	local winid = view.get_winnr()
	local bufnr = vim.api.nvim_win_get_buf(winid)

	-- Switch to the nvim-tree window
	vim.api.nvim_set_current_win(winid)

	-- Get the start and end lines of the selection (in the context of nvim-tree)
	local start_line = vim.fn.line("'<")
	local end_line = vim.fn.line("'>")

	-- Validate the selection boundaries
	local last_line = vim.api.nvim_buf_line_count(bufnr)
	start_line = math.max(1, math.min(start_line, last_line))
	end_line = math.max(1, math.min(end_line, last_line))

	-- Iterate over the selected lines
	for i = start_line, end_line do
		vim.api.nvim_win_set_cursor(winid, { i, 0 })
		local node = api.tree.get_node_under_cursor()
		if node and node.absolute_path then
			if action == 0 then
				api.marks.toggle(node)
			elseif action == 1 then
				if not api.marks.get(node) then
					api.marks.toggle(node) -- Use the correct method
				end
			elseif action == 2 then
				if api.marks.get(node) then
					api.marks.toggle(node) -- Use the correct method
				end
			end
		end
	end

	-- Return to the original window (if needed)
	vim.api.nvim_set_current_win(vim.fn.win_getid())
end

-- Map the function to keybindings in visual mode
vim.keymap.set("x", "<leader>mt", function()
	mark_files_in_visual_selection(0)
end, { desc = "Toggle markings in visual selection" })

vim.keymap.set("x", "<leader>ma", function()
	mark_files_in_visual_selection(1)
end, { desc = "Add markings in visual selection" })

vim.keymap.set("x", "<leader>md", function()
	mark_files_in_visual_selection(2)
end, { desc = "Delete markings in visual selection" })

@alex-courtis
Copy link
Member Author

That's really elegant! I'd be really grateful if you shared this as a recipe

This would be a valuable core nvim-tree feature that a lot of users would appreciate. Are you open to creating a PR to contribute this?

@LisovAlexey
Copy link

Sure, I will be more than happy to create a PR!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request PR please nvim-tree team does not have the bandwidth to implement; a PR will be gratefully appreciated QOL Quality Of Life Improvement
Projects
None yet
Development

No branches or pull requests

2 participants