Skip to content

Visual Selection #2994

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

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!

# for free to join this conversation on GitHub. Already have an account? # 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