3030
3131-- Holds the micro.CurPane() we're manipulating
3232local tree_view = nil
33+ -- The last bufpane we were using before we open the tree
34+ local last_buf_pane = nil
3335-- Keeps track of the current working directory
3436local current_dir = os .Getwd ()
3537-- Keep track of current highest visible indent to resize width appropriately
@@ -84,6 +86,17 @@ local function is_dir(path)
8486 end
8587end
8688
89+ -- Turn to relative path if possible
90+ local function try_convert_rel (path )
91+ local wd , err = os .Getwd ()
92+ if err == nil then
93+ local relPath , relErr = filepath .Rel (wd , path )
94+ return relPath
95+ end
96+
97+ return path
98+ end
99+
87100-- Returns a list of files (in the target dir) that are ignored by the VCS system (if exists)
88101-- aka this returns a list of gitignored files (but for whatever VCS is found)
89102local function get_ignored_files (tar_dir )
@@ -539,6 +552,101 @@ local function go_back_dir()
539552 end
540553end
541554
555+ function open_pane_if_exist (path )
556+ local cleanFilepath = filepath .Clean (path )
557+ local wd , wdErr = os .Getwd ()
558+ for i = 1 , # micro .Tabs ().List do
559+ for j = 1 , # micro .Tabs ().List [i ].Panes do
560+ local currentPane = micro .Tabs ().List [i ].Panes [j ]
561+ local currentBuf = currentPane .Buf
562+
563+ -- if currentBuf ~= nil then
564+ -- micro.Log("cleanFilepath:", cleanFilepath)
565+ -- micro.Log("currentBuf.AbsPath:", currentBuf.AbsPath)
566+ -- micro.Log("currentBuf.Path:", currentBuf.Path)
567+ -- end
568+
569+ if currentBuf ~= nil and currentBuf .AbsPath ~= " " and currentBuf .AbsPath ~= nil then
570+ local calculatedAbsPath = filepath .Abs (cleanFilepath )
571+ if not filepath .IsAbs (cleanFilepath ) and wdErr == nil then
572+ local absPath , absErr = filepath .Abs (filepath .Join (wd , cleanFilepath ))
573+ -- micro.Log("absPath:", absPath)
574+ if absErr == nil then
575+ calculatedAbsPath = absPath
576+ end
577+ end
578+ -- micro.Log("calculatedAbsPath:", calculatedAbsPath)
579+
580+ if filepath .Clean (currentBuf .AbsPath ) == calculatedAbsPath or
581+ filepath .Clean (currentBuf .AbsPath ) == cleanFilepath or
582+ filepath .Clean (currentBuf .Path ) == cleanFilepath then
583+
584+ -- NOTE: SetActive functions has index starting at 0 instead lol
585+ micro .Tabs ():SetActive (i - 1 )
586+ micro .Tabs ().List [i ]:SetActive (j - 1 )
587+ return true
588+ end
589+ end
590+ end
591+ end
592+
593+ return false
594+ end
595+
596+ -- Stat a path to check if it exists, returning true/false
597+ local function path_exists (path )
598+ local go_os = import (' os' )
599+ -- Stat the file/dir path we created
600+ -- file_stat should be non-nil, and stat_err should be nil on success
601+ local file_stat , stat_err = go_os .Stat (path )
602+ -- Check if what we tried to create exists
603+ if stat_err ~= nil then
604+ -- true/false if the file/dir exists
605+ return go_os .IsExist (stat_err )
606+ elseif file_stat ~= nil then
607+ -- Assume it exists if no errors
608+ return true
609+ end
610+ return false
611+ end
612+
613+
614+ local function is_path_dir (path )
615+ -- Stat the file/dir path we created
616+ -- file_stat should be non-nil, and stat_err should be nil on success
617+ local file_stat , stat_err = os .Stat (path )
618+ if stat_err ~= nil then
619+ return false
620+ elseif file_stat ~= nil then
621+ -- Assume it exists if no errors
622+ return file_stat :IsDir ()
623+ end
624+ return false
625+ end
626+
627+
628+ function smart_new_tab (path )
629+ local cleanFilepath = filepath .Clean (path )
630+
631+ -- If current pane is empty, we can open in it
632+ if not path_exists (last_buf_pane .Buf .AbsPath ) or is_path_dir (last_buf_pane .Buf .AbsPath ) then
633+ if # last_buf_pane .Buf :Bytes () == 0 then
634+ last_buf_pane :OpenCmd ({cleanFilepath })
635+ return
636+ end
637+ end
638+
639+ -- Otherwise find if there's any existing panes
640+ if open_pane_if_exist (cleanFilepath ) then
641+ return
642+ end
643+
644+ -- If not just open it
645+ local currentActiveIndex = micro .Tabs ():Active ()
646+ last_buf_pane :NewTabCmd ({cleanFilepath })
647+ last_buf_pane :TabMoveCmd ({tostring (currentActiveIndex + 2 )})
648+ end
649+
542650-- Tries to open the current index
543651-- If it's the top dir indicator, or separator, nothing happens
544652-- If it's ".." then it tries to go back a dir
@@ -558,10 +666,21 @@ local function try_open_at_y(y)
558666 -- if passed path is a directory, update the current dir to be one deeper..
559667 update_current_dir (scanlist [y ].abspath )
560668 else
669+ local open_path = scanlist [y ].abspath
670+
671+ if config .GetGlobalOption (' filemanager2.relativepath' ) then
672+ open_path = try_convert_rel (scanlist [y ].abspath )
673+ end
674+
561675 -- If it's a file, then open it
562- micro .InfoBar ():Message (' Filemanager2 opened ' , scanlist [y ].abspath )
563- -- Opens the absolute path in new vertical view
564- micro .CurPane ():VSplitIndex (buffer .NewBufferFromFile (scanlist [y ].abspath ), true )
676+ micro .InfoBar ():Message (' Filemanager2 opened ' , open_path )
677+ open_path = filepath .Clean (open_path )
678+ if config .GetGlobalOption (' filemanager2.newtab' ) then
679+ smart_new_tab (open_path )
680+ else
681+ micro .CurPane ():VSplitIndex (buffer .NewBufferFromFile (open_path ), true )
682+ end
683+
565684 -- Resizes all views after opening a file
566685 -- tabs[curTab + 1]:Resize()
567686 end
@@ -631,23 +750,6 @@ local function uncompress_target(y)
631750 end
632751end
633752
634- -- Stat a path to check if it exists, returning true/false
635- local function path_exists (path )
636- local go_os = import (' os' )
637- -- Stat the file/dir path we created
638- -- file_stat should be non-nil, and stat_err should be nil on success
639- local file_stat , stat_err = go_os .Stat (path )
640- -- Check if what we tried to create exists
641- if stat_err ~= nil then
642- -- true/false if the file/dir exists
643- return go_os .IsExist (stat_err )
644- elseif file_stat ~= nil then
645- -- Assume it exists if no errors
646- return true
647- end
648- return false
649- end
650-
651753-- Prompts for a new name, then renames the file/dir at the cursor's position
652754-- Not local so Micro can use it
653755function rename_at_cursor (bp , args )
@@ -855,8 +957,44 @@ function new_dir(bp, args)
855957 create_filedir (dir_name , true )
856958end
857959
960+ local function try_uncompress_path (path )
961+ local target_path = try_convert_rel (path )
962+ target_path = filepath .Clean (target_path )
963+ local current = current_dir
964+ local components = {}
965+
966+ -- Split the path into components
967+ while target_path ~= current and target_path ~= " /" and target_path ~= " ." do
968+ table.insert (components , 1 , get_basename (target_path ))
969+ target_path = filepath .Dir (target_path )
970+ end
971+
972+ -- For each component, find and uncompress the corresponding directory
973+ local y = 0
974+ for i = 1 , # components do
975+ -- Search for the component in current level
976+ for j = 1 , # scanlist do
977+ if get_basename (scanlist [j ].abspath ) == components [i ] then
978+ y = j
979+ -- If it's a directory and not the last component, uncompress it
980+ if i < # components and scanlist [j ].dirmsg == Icons ()[' dir' ] then
981+ uncompress_target (y )
982+ end
983+ break
984+ end
985+ end
986+ end
987+
988+ -- Move cursor to the final target
989+ if y > 0 then
990+ tree_view .Cursor .Loc .Y = y + 2 -- +2 to account for header lines
991+ select_line ()
992+ end
993+ end
994+
858995-- open_tree setup's the view
859996local function open_tree ()
997+ last_buf_pane = micro .CurPane ()
860998 -- Open a new Vsplit (on the very left)
861999 micro .CurPane ():VSplitIndex (buffer .NewBuffer (' ' , ' filemanager2' ), false )
8621000 -- Save the new view so we can access it later
@@ -884,6 +1022,19 @@ local function open_tree()
8841022
8851023 -- Fill the scanlist, and then print its contents to tree_view
8861024 update_current_dir (os .Getwd ())
1025+
1026+ config .RegisterCommonOption (' filemanager2' , ' showcurrent' , true )
1027+ -- Use relative path is possible
1028+ config .RegisterCommonOption (' filemanager2' , ' relativepath' , true )
1029+ -- Open on new tab?
1030+ config .RegisterCommonOption (' filemanager2' , ' newtab' , true )
1031+
1032+ if config .GetGlobalOption (' filemanager2.showcurrent' ) then
1033+ -- If there's a valid buffer path, uncompress the tree to reach it
1034+ if path_exists (last_buf_pane .Buf .AbsPath ) then
1035+ try_uncompress_path (last_buf_pane .Buf .AbsPath )
1036+ end
1037+ end
8871038end
8881039
8891040function onBufPaneOpen (bp )
9021053-- close_tree will close the tree plugin view and release memory.
9031054local function close_tree ()
9041055 if tree_view ~= nil then
905- tree_view :Quit ()
1056+ tree_view :Unsplit ()
9061057 tree_view = nil
9071058 clear_messenger ()
9081059 end
@@ -1403,6 +1554,12 @@ function init()
14031554 config .RegisterCommonOption (' filemanager2' , ' openonstart' , false )
14041555 -- Use nerd fonts icons
14051556 config .RegisterCommonOption (' filemanager2' , ' nerdfonts' , false )
1557+ -- Shows the current file directory
1558+ config .RegisterCommonOption (' filemanager2' , ' showcurrent' , true )
1559+ -- Use relative path is possible
1560+ config .RegisterCommonOption (' filemanager2' , ' relativepath' , true )
1561+ -- Open on new tab?
1562+ config .RegisterCommonOption (' filemanager2' , ' newtab' , true )
14061563
14071564 -- Use file icon in status bar
14081565 micro .SetStatusInfoFn (' filemanager2.FileIcon' )
0 commit comments