From 25c7e7fb64d3685c703d785ffb75c950ddfac134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Petri=C4=8Dko?= Date: Sat, 13 Jun 2026 00:20:35 +0200 Subject: [PATCH 1/3] filemanager: fix mouse click handling and crashes - Refactor mouse press to use pre/post handlers so micro manages cursor positioning correctly with softwrap - Add nil checks for scanlist[y] and tree_view to prevent panics - Reduce default pane width from 30 to 25 - Disable autocomplete in tree view to restore Tab navigation - Remove SelectLine call and reset selection on click --- filemanager-plugin/filemanager.lua | 118 +++++++++++++++++------------ 1 file changed, 70 insertions(+), 48 deletions(-) diff --git a/filemanager-plugin/filemanager.lua b/filemanager-plugin/filemanager.lua index fef17d4..64d260d 100644 --- a/filemanager-plugin/filemanager.lua +++ b/filemanager-plugin/filemanager.lua @@ -242,9 +242,6 @@ local function select_line(last_y) -- Makes sure the cursor is visible (if it isn't) -- (false) means no callback tree_view:Center() - - -- Highlight the current line where the cursor is - tree_view.Cursor:SelectLine() end -- Simple true/false if scanlist is currently empty @@ -259,10 +256,10 @@ end local function refresh_view() clear_messenger() - -- If it's less than 30, just use 30 for width. Don't want it too small + -- If it's less than 25, just use 25 for width. Don't want it too small - if tree_view:GetView().Width < 30 then - tree_view:ResizePane(30) + if tree_view:GetView().Width < 25 then + tree_view:ResizePane(25) end -- Delete everything in the view/buffer @@ -427,9 +424,9 @@ local function compress_target(y, delete_y) scanlist = second_table end - if tree_view:GetView().Width > (30 + highest_visible_indent) then + if tree_view:GetView().Width > (25 + highest_visible_indent) then -- Shave off some width - tree_view:ResizePane(30 + highest_visible_indent) + tree_view:ResizePane(25 + highest_visible_indent) end refresh_and_select() @@ -471,8 +468,8 @@ end local function update_current_dir(path) -- Clear the highest since this is a full refresh highest_visible_indent = 0 - -- Set the width back to 30 - tree_view:ResizePane(30) + -- Set the width back to 25 + tree_view:ResizePane(25) -- Update the current dir to the new path current_dir = path @@ -519,16 +516,19 @@ local function try_open_at_y(y) elseif y > 2 and not scanlist_is_empty() then -- -2 to conform to our scanlist "missing" first 3 indicies y = y - 2 - if scanlist[y].dirmsg ~= "" then - -- if passed path is a directory, update the current dir to be one deeper.. - update_current_dir(scanlist[y].abspath) - else - -- If it's a file, then open it - micro.InfoBar():Message("Filemanager opened ", scanlist[y].abspath) - -- Opens the absolute path in new vertical view - micro.CurPane():VSplitIndex(buffer.NewBufferFromFile(scanlist[y].abspath), true) - -- Resizes all views after opening a file - -- tabs[curTab + 1]:Resize() + -- Check if the entry exists before accessing it + if scanlist[y] ~= nil then + if scanlist[y].dirmsg ~= "" then + -- if passed path is a directory, update the current dir to be one deeper.. + update_current_dir(scanlist[y].abspath) + else + -- If it's a file, then open it + micro.InfoBar():Message("Filemanager opened ", scanlist[y].abspath) + -- Opens the absolute path in new vertical view + micro.CurPane():VSplitIndex(buffer.NewBufferFromFile(scanlist[y].abspath), true) + -- Resizes all views after opening a file + -- tabs[curTab + 1]:Resize() + end end else micro.InfoBar():Error("Can't open that") @@ -823,31 +823,39 @@ end -- open_tree setup's the view local function open_tree() - -- Open a new Vsplit (on the very left) + -- Check if it already exists + if tree_view ~= nil then return end + + -- Open a new Vsplit micro.CurPane():VSplitIndex(buffer.NewBuffer("", "filemanager"), false) - -- Save the new view so we can access it later + + -- Check if tree_view was properly initialized tree_view = micro.CurPane() + if tree_view == nil then + micro.InfoBar():Error("Error: Could not initialize filemanager window.") + return + end - -- Set the width of tree_view to 30% & lock it - tree_view:ResizePane(30) + tree_view:ResizePane(25) -- Set the type to unsavable - -- tree_view.Buf.Type = buffer.BTLog - tree_view.Buf.Type.Scratch = true - tree_view.Buf.Type.Readonly = true - + -- tree_view.Buf.Type = buffer.BTLog + tree_view.Buf.Type.Scratch = true + tree_view.Buf.Type.Readonly = true -- Set the various display settings, but only on our view (by using SetLocalOption instead of SetOption) -- NOTE: Micro requires the true/false to be a string -- Softwrap long strings (the file/dir paths) - tree_view.Buf:SetOptionNative("softwrap", true) - -- No line numbering - tree_view.Buf:SetOptionNative("ruler", false) - -- Is this needed with new non-savable settings from being "vtLog"? - tree_view.Buf:SetOptionNative("autosave", false) - -- Don't show the statusline to differentiate the view from normal views - tree_view.Buf:SetOptionNative("statusformatr", "") - tree_view.Buf:SetOptionNative("statusformatl", "filemanager") - tree_view.Buf:SetOptionNative("scrollbar", false) - + tree_view.Buf:SetOptionNative("softwrap", true) + -- No line numbering + tree_view.Buf:SetOptionNative("ruler", false) + -- Disable autocomplete so Tab always goes through IndentSelection, + -- avoiding the autocomplete popup in the tree view. + tree_view.Buf:SetOptionNative("autocomplete", false) + -- Is this needed with new non-savable settings from being "vtLog"? + tree_view.Buf:SetOptionNative("autosave", false) + -- Don't show the statusline to differentiate the view from normal views + tree_view.Buf:SetOptionNative("statusformatr", "") + tree_view.Buf:SetOptionNative("statusformatl", "filemanager") + tree_view.Buf:SetOptionNative("scrollbar", false) -- Fill the scanlist, and then print its contents to tree_view update_current_dir(os.Getwd()) end @@ -1084,17 +1092,23 @@ function onPreviousSplit(view) selectline_if_tree(view) end --- On click, open at the click's y +-- On click, let micro move the cursor to the correct buffer position, +-- then open whatever is at that position. +-- We split across pre/post so micro handles all coordinate mapping for us, +-- correctly accounting for softwrap, tab bars, scroll, etc. function preMousePress(view, event) if view == tree_view then - local x, y = event:Position() - -- Fixes the y because softwrap messes with it - local new_x, new_y = tree_view:GetMouseClickLocation(x, y) - -- Try to open whatever is at the click's y index - -- Will go into/back dirs based on what's clicked, nothing gets expanded - try_open_at_y(new_y) - -- Don't actually allow the mousepress to trigger, so we avoid highlighting stuff - return false + -- Reset selection to prevent extending it on subsequent clicks + tree_view.Cursor:ResetSelection() + -- Return true to let micro handle the click naturally (moves cursor to correct position) + return true + end +end + +function onMousePress(view, event) + if view == tree_view then + -- Cursor is now at the correct buffer position; open whatever is there + try_open_at_y(tree_view.Cursor.Loc.Y) end end @@ -1133,7 +1147,7 @@ end -- Ref https://github.com/zyedidia/micro/issues/992 local tab_pressed = false --- Tab +-- Tab (when autocomplete is not active) function preIndentSelection(view) if view == tree_view then tab_pressed = true @@ -1145,6 +1159,14 @@ function preIndentSelection(view) end end +-- Tab (when autocomplete is active) — block the popup so Tab falls +-- through to IndentSelection which handles opening correctly. +function preAutocomplete(view) + if view == tree_view then + return false + end +end + -- Workaround for tab getting inserted into opened files -- Ref https://github.com/zyedidia/micro/issues/992 function preInsertTab(view) From f9584aa0dce01c1a86a1b1fcc9e3559c900ecb4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Petri=C4=8Dko?= Date: Sat, 13 Jun 2026 01:19:52 +0200 Subject: [PATCH 2/3] filemanager: silently ignore clicks on header and separator lines --- filemanager-plugin/filemanager.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/filemanager-plugin/filemanager.lua b/filemanager-plugin/filemanager.lua index 64d260d..8a974b6 100644 --- a/filemanager-plugin/filemanager.lua +++ b/filemanager-plugin/filemanager.lua @@ -510,8 +510,11 @@ end -- If it's actually a file, open it in a new vsplit -- THIS EXPECTS ZERO-BASED Y local function try_open_at_y(y) + -- 0 = header (current dir path), 1 = separator — silently ignore + if y == 0 or y == 1 then + return -- 2 is the zero-based index of ".." - if y == 2 then + elseif y == 2 then go_back_dir() elseif y > 2 and not scanlist_is_empty() then -- -2 to conform to our scanlist "missing" first 3 indicies From ac63dd0292a1acea6ef24197dee802fc53b1251a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Petri=C4=8Dko?= Date: Thu, 10 Sep 2026 13:54:41 +0200 Subject: [PATCH 3/3] filemanager: document unreleased mouse/crash fixes in CHANGELOG --- filemanager-plugin/CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/filemanager-plugin/CHANGELOG.md b/filemanager-plugin/CHANGELOG.md index 46d51c4..cf6ed8a 100644 --- a/filemanager-plugin/CHANGELOG.md +++ b/filemanager-plugin/CHANGELOG.md @@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [Unreleased] +### Fixed + +- Mouse clicks now let Micro position the cursor natively (via pre/post mouse-press handlers) instead of manually computing the click location, fixing incorrect click targeting with softwrap enabled +- Crashes from clicking on stale/out-of-range scanlist entries by adding nil checks around `scanlist[y]` and `tree_view` +- Tab navigation in the tree view being swallowed by the autocomplete popup; autocomplete is now disabled in the tree view +- Clicking the header or separator lines no longer errors or triggers unintended actions + +### Changed + +- Default tree pane width reduced from 30 to 25 + ## [3.4.0] - 2018-10-22 ### Fixed