diff --git a/filemanager-plugin/README.md b/filemanager-plugin/README.md index 79d983d..342739b 100644 --- a/filemanager-plugin/README.md +++ b/filemanager-plugin/README.md @@ -5,52 +5,3 @@ A simple plugin that allows for easy navigation of a file tree. ![Example picture](./example.jpg?raw=true "Example") **Installation:** run `plugin install filemanager` and restart Micro. - -## Basics - -The top line always has the current directory's path to show you where you are.\ -The `..` near the top is used to move back a directory, from your current position. - -All directories have a `/` added to the end of it, and are syntax-highlighted as a `special` character.\ -If the directory is expanded, there will be a `+` to the left of it. If it is collapsed there will be a `-` instead. - -**NOTE:** If you change files without using the plugin, it can't know what you did. The only fix is to close and open the tree. - -### Options - -| Option | Purpose | Default | -| :--------------------------- | :----------------------------------------------------------- | :------ | -| `filemanager-showdotfiles` | Show dotfiles (hidden if false) | `true` | -| `filemanager-showignored` | Show gitignore'd files (hidden if false) | `true` | -| `filemanager-compressparent` | Collapse the parent dir when left is pressed on a child file | `true` | -| `filemanager-foldersfirst` | Sorts folders above any files | `true` | -| `filemanager-openonstart` | Automatically open the file tree when starting Micro | `false` | - -### Commands and Keybindings - -The keybindings below are the equivalent to Micro's defaults, and not actually set by the plugin. If you've changed any of those keybindings, then that key is used instead. - -If you want to [keybind](https://github.com/zyedidia/micro/blob/master/runtime/help/keybindings.md#rebinding-keys) any of the operations/commands, bind to the labeled API in the table below. - -| Command | Keybinding(s) | What it does | API for `bindings.json` | -| :------- | :------------------------- | :------------------------------------------------------------------------------------------ | :------------------------------------ | -| `tree` | - | Open/close the tree | `filemanager.toggle_tree` | -| - | Tab & MouseLeft | Open a file, or go into the directory. Goes back a dir if on `..` | `filemanager.try_open_at_cursor` | -| - | | Expand directory in tree listing | `filemanager.uncompress_at_cursor` | -| - | | Collapse directory listing | `filemanager.compress_at_cursor` | -| - | Shift ⬆ | Go to the target's parent directory | `filemanager.goto_parent_dir` | -| - | Alt Shift { | Jump to the previous directory in the view | `filemanager.goto_next_dir` | -| - | Alt Shift } | Jump to the next directory in the view | `filemanager.goto_prev_dir` | -| `rm` | - | Prompt to delete the target file/directory your cursor is on | `filemanager.prompt_delete_at_cursor` | -| `rename` | - | Rename the file/directory your cursor is on, using the passed name | `filemanager.rename_at_cursor` | -| `touch` | - | Make a new file under/into the file/directory your cursor is on, using the passed name | `filemanager.new_file` | -| `mkdir` | - | Make a new directory under/into the file/directory your cursor is on, using the passed name | `filemanager.new_dir` | - -#### Notes - -- `rename`, `touch`, and `mkdir` require a name to be passed when calling.\ - Example: `rename newnamehere`, `touch filenamehere`, `mkdir dirnamehere`.\ - If the passed name already exists in the current dir, it will cancel instead of overwriting (for safety). - -- The Ctrl w keybinding is to switch which buffer your cursor is on.\ - This isn't specific to the plugin, it's just part of Micro, but many people seem to not know this. diff --git a/filemanager-plugin/filemanager.lua b/filemanager-plugin/filemanager.lua index fef17d4..b93b460 100644 --- a/filemanager-plugin/filemanager.lua +++ b/filemanager-plugin/filemanager.lua @@ -1,4 +1,4 @@ -VERSION = "3.5.1" +VERSION = "3.5.2" local micro = import("micro") local config = import("micro/config") @@ -53,10 +53,8 @@ end -- A check for if a path is a dir local function is_dir(path) - -- Used for checking if dir - local golib_os = import("os") -- Returns a FileInfo on the current file/path - local file_info, stat_error = golib_os.Stat(path) + local file_info, stat_error = os.Stat(path) -- Wrap in nil check for file/dirs without read permissions if file_info ~= nil then -- Returns true/false if it's a dir @@ -74,7 +72,7 @@ end local function get_ignored_files(tar_dir) -- True/false if the target dir returns a non-fatal error when checked with 'git status' local function has_git() - local git_rp_results = shell.ExecCommand('git -C "' .. tar_dir .. '" rev-parse --is-inside-work-tree') + local git_rp_results = shell.ExecCommand('git', '-C', tar_dir, 'rev-parse', '--is-inside-work-tree') return git_rp_results:match("^true%s*$") end local readout_results = {} @@ -82,7 +80,7 @@ local function get_ignored_files(tar_dir) if has_git() then -- If the dir is a git dir, get all ignored in the dir local git_ls_results = - shell.ExecCommand('git -C "' .. tar_dir .. '" ls-files . --ignored --exclude-standard --others --directory') + shell.ExecCommand('git', '-C', tar_dir, 'ls-files', '.', '--ignored', '--exclude-standard', '--others', '--directory') -- Cut off the newline that is at the end of each result for split_results in string.gmatch(git_ls_results, "([^\r\n]+)") do -- git ls-files adds a trailing slash if it's a dir, so we remove it (if it is one) @@ -438,6 +436,12 @@ end -- Prompts the user for deletion of a file/dir when triggered -- Not local so Micro can access it function prompt_delete_at_cursor() + + if micro.CurPane() ~= tree_view then + micro.InfoBar():Message('"rm" only works with the cursor in the tree!') + return + end + local y = get_safe_y() -- Don't let them delete the top 3 index dir/separator/.. if y == 0 or scanlist_is_empty() then @@ -446,12 +450,10 @@ function prompt_delete_at_cursor() return end - micro.InfoBar():YNPrompt("Do you want to delete the " .. (scanlist[y].dirmsg ~= "" and "dir" or "file") .. ' "' .. scanlist[y].abspath .. '"? ', function(yes, canceled) + micro.InfoBar():YNPrompt("Do you want to delete the " .. (scanlist[y].dirmsg ~= "" and "dir" or "file") .. ' "' .. scanlist[y].abspath .. '"? (y/n) ', function(yes, canceled) if yes and not canceled then - -- Use Go's os.Remove to delete the file - local go_os = import("os") -- Delete the target (if its a dir then the children too) - local remove_log = go_os.RemoveAll(scanlist[y].abspath) + local remove_log = os.RemoveAll(scanlist[y].abspath) if remove_log == nil then micro.InfoBar():Message("Filemanager deleted: ", scanlist[y].abspath) -- Remove the target (and all nested) from scanlist[y + 1] @@ -596,14 +598,13 @@ end -- Stat a path to check if it exists, returning true/false local function path_exists(path) - local go_os = import("os") -- Stat the file/dir path we created -- file_stat should be non-nil, and stat_err should be nil on success - local file_stat, stat_err = go_os.Stat(path) + local file_stat, stat_err = os.Stat(path) -- Check if what we tried to create exists if stat_err ~= nil then -- true/false if the file/dir exists - return go_os.IsExist(stat_err) + return os.IsExist(stat_err) elseif file_stat ~= nil then -- Assume it exists if no errors return true @@ -641,10 +642,15 @@ function rename_at_cursor(bp, args) local old_path = scanlist[y].abspath -- Join the path into their supplied rename, so that we have an absolute path local new_path = dirname_and_join(old_path, new_name) - -- Use Go's os package for renaming the file/dir - local golib_os = import("os") + + -- Check if the name is already taken by a file/dir + if path_exists(new_path) then + micro.InfoBar():Error("You can't create a file/dir with a pre-existing name") + return + end + -- Actually rename the file - local log_out = golib_os.Rename(old_path, new_path) + local log_out = os.Rename(old_path, new_path) -- Output the log, if any, of the rename if log_out ~= nil then micro.Log("Rename log: ", log_out) @@ -704,16 +710,14 @@ local function create_filedir(filedir_name, make_dir) return end - -- Use Go's os package for creating the files - local golib_os = import("os") -- Create the dir or file if make_dir then -- Creates the dir - golib_os.Mkdir(filedir_path, golib_os.ModePerm) + os.Mkdir(filedir_path, os.ModePerm) micro.Log("Filemanager created directory: " .. filedir_path) else -- Creates the file - golib_os.Create(filedir_path) + os.Create(filedir_path) micro.Log("Filemanager created file: " .. filedir_path) end @@ -958,11 +962,9 @@ function goto_parent_dir() end function try_open_at_cursor() - if micro.CurPane() ~= tree_view or scanlist_is_empty() then - return + if micro.CurPane() == tree_view then + try_open_at_y(tree_view.Cursor.Loc.Y) end - - try_open_at_y(tree_view.Cursor.Loc.Y) end -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1085,14 +1087,11 @@ function onPreviousSplit(view) end -- On click, open at the click's y -function preMousePress(view, event) +function onMousePress(view) 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) + try_open_at_cursor() -- Don't actually allow the mousepress to trigger, so we avoid highlighting stuff return false end @@ -1139,7 +1138,7 @@ function preIndentSelection(view) tab_pressed = true -- Open the file -- Using tab instead of enter, since enter won't work with Readonly - try_open_at_y(tree_view.Cursor.Loc.Y) + try_open_at_cursor() -- Don't actually insert a tab return false end @@ -1363,9 +1362,12 @@ function init() config.MakeCommand("mkdir", new_dir, config.NoComplete) -- Delete a file/dir, and anything contained in it if it's a dir config.MakeCommand("rm", prompt_delete_at_cursor, config.NoComplete) + -- Adds colors to the ".." and any dir's in the tree view via syntax highlighting -- TODO: Change it to work with git, based on untracked/changed/added/whatever config.AddRuntimeFile("filemanager", config.RTSyntax, "syntax.yaml") + -- Add the help file + config.AddRuntimeFile("filemanager", config.RTHelp, "help/filemanager.md") -- NOTE: This must be below the syntax load command or coloring won't work -- Just auto-open if the option is enabled diff --git a/filemanager-plugin/help/filemanager.md b/filemanager-plugin/help/filemanager.md new file mode 100644 index 0000000..650ef49 --- /dev/null +++ b/filemanager-plugin/help/filemanager.md @@ -0,0 +1,52 @@ +# Filemanager Plugin + +A simple plugin that allows for easy navigation of a file tree. + +## Basics + +The top line always has the current directory's path to show you where you are.\ +The `..` near the top is used to move back a directory, from your current position. + +All directories have a `/` added to the end of it, and are syntax-highlighted as a `special` character.\ +If the directory is expanded, there will be a `+` to the left of it. If it is collapsed there will be a `-` instead. + +**NOTE:** If you change files without using the plugin, it can't know what you did. The only fix is to close and open the tree. + +### Options + +| Option | Purpose | Default | +| :--------------------------- | :----------------------------------------------------------- | :------ | +| `filemanager.showdotfiles` | Show dotfiles (hidden if false) | `true` | +| `filemanager.showignored` | Show gitignore'd files (hidden if false) | `true` | +| `filemanager.compressparent` | Collapse the parent dir when left is pressed on a child file | `true` | +| `filemanager.foldersfirst` | Sorts folders above any files | `true` | +| `filemanager.openonstart` | Automatically open the file tree when starting Micro | `false` | + +### Commands and Keybindings + +The keybindings below are the equivalent to Micro's defaults, and not actually set by the plugin. If you've changed any of those keybindings, then that key is used instead. + +If you want to [keybind](https://github.com/zyedidia/micro/blob/master/runtime/help/keybindings.md#rebinding-keys) any of the operations/commands, bind to the labeled API in the table below. + +| Command | Keybinding(s) | What it does | API for `bindings.json` | +| :------- | :------------------------- | :------------------------------------------------------------------------------------------ | :------------------------------------ | +| `tree` | - | Open/close the tree | `filemanager.toggle_tree` | +| - | Tab & MouseLeft | Open a file, or go into the directory. Goes back a dir if on `..` | `filemanager.try_open_at_cursor` | +| - | | Expand directory in tree listing | `filemanager.uncompress_at_cursor` | +| - | | Collapse directory listing | `filemanager.compress_at_cursor` | +| - | Shift ⬆ | Go to the target's parent directory | `filemanager.goto_parent_dir` | +| - | Alt Shift { | Jump to the previous directory in the view | `filemanager.goto_next_dir` | +| - | Alt Shift } | Jump to the next directory in the view | `filemanager.goto_prev_dir` | +| `rm` | - | Prompt to delete the target file/directory your cursor is on | `filemanager.prompt_delete_at_cursor` | +| `rename` | - | Rename the file/directory your cursor is on, using the passed name | `filemanager.rename_at_cursor` | +| `touch` | - | Make a new file under/into the file/directory your cursor is on, using the passed name | `filemanager.new_file` | +| `mkdir` | - | Make a new directory under/into the file/directory your cursor is on, using the passed name | `filemanager.new_dir` | + +#### Notes + +- `rename`, `touch`, and `mkdir` require a name to be passed when calling.\ + Example: `rename newnamehere`, `touch filenamehere`, `mkdir dirnamehere`.\ + If the passed name already exists in the current dir, it will cancel instead of overwriting (for safety). + +- The Ctrl w keybinding is to switch which buffer your cursor is on.\ + This isn't specific to the plugin, it's just part of Micro, but many people seem to not know this.