diff --git a/README.md b/README.md index b1402ca..eb1a33e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ plugin. ## Requirements -- [Yazi](https://github.com/sxyazi/yazi) v0.3.0+ +- [Yazi](https://github.com/sxyazi/yazi) v0.4.2+ - [`7z` or `7zz` command](https://github.com/p7zip-project/p7zip) - [`file` command](https://www.darwinsys.com/file/) @@ -44,10 +44,13 @@ ya pack -u | ----------------------------------- | ------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `prompt` | `true` or `false` | `false` | Create a prompt to choose between hovered and selected items when both exist. If this option is disabled, selected items will only be operated on when the hovered item is selected, otherwise the hovered item will be the default item that is operated on. | | `default_item_group_for_prompt` | `hovered`, `selected` or `none` | `hovered` | The default item group to operate on when the prompt is submitted without any value. This only takes effect if `prompt` is set to `true`, otherwise this option doesn't do anything. `hovered` means the hovered item is operated on, `selected` means the selected items are operated on, and `none` just cancels the operation. | -| `smart_enter` | `true` or `false` | `true` | Use one command to open files or enter a directory. With this option set, the `enter` and `open` commands will both call the `enter` command when a directory is hovered and call the `open` command when a regular file is hovered. | +| `smart_enter` | `true` or `false` | `true` | Use one command to open files or enter a directory. With this option set, the `enter` and `open` commands will both call the `enter` command when a directory is hovered and call the `open` command when a regular file is hovered. You can also enable this behaviour by passing the `--smart` flag to the `enter` or `open` commands. | | `smart_paste` | `true` or `false` | `false` | Paste items into a directory without entering it. The behaviour is exactly the same as the [smart paste tip on Yazi's documentation](https://yazi-rs.github.io/docs/tips#smart-paste). Setting this option to `false` will use the default `paste` behaviour. You can also enable this behaviour by passing the `--smart` flag to the `paste` command. | | `smart_tab_create` | `true` or `false` | `false` | Create tabs in the directory that is being hovered instead of the current directory. The behaviour is exactly the same as the [smart tab tip on Yazi's documentation](https://yazi-rs.github.io/docs/tips#smart-tab). Setting this option to `false` will use the default `tab_create` behaviour, which means you need to pass the `--current` flag to the command. You can also enable this behaviour by passing the `--smart` flag to the `tab_create` command. | | `smart_tab_switch` | `true` or `false` | `false` | If the tab that is being switched to does not exist yet, setting this option to `true` will create all the tabs in between the current number of open tabs, and the tab that is being switched to. The behaviour is exactly the same as [this tip](https://github.com/sxyazi/yazi/issues/918#issuecomment-2058157773). Setting this option to `false` will use the default `tab_switch` behaviour. You can also enable this behaviour by passing the `--smart` flag to the `tab_switch` command. | +| `open_file_after_creation` | `true` or `false` | `false` | This option determines whether the plugin will open a file after it has been created. Setting this option to `true` will cause the plugin to open created file. You can also enable this behaviour by passing the `--open` flag to the `create` command. | +| `enter_directory_after_creation` | `true` or `false` | `false` | This option determines whether the plugin will enter a directory after it has been created. Setting this option to `true` will cause the plugin enter the created directory. You can also enable this behaviour by passing the `--enter` flag to the `create` command. | +| `use_default_create_behaviour` | `true` or `false` | `false` | This option determines whether the plugin will use the behaviour of Yazi's `create` command. Setting this option to `true` will use the behaviour of Yazi's `create` command. You can also enable this behaviour by passing the `--default-behaviour` flag to the `create` command. | | `enter_archives` | `true` or `false` | `true` | Automatically extract and enter archive files. This option requires the [7z or 7zz command](https://github.com/p7zip-project/p7zip) to be present. | | `extract_retries` | An integer, like `1`, `3`, `10`, etc. | `3` | This option determines how many times the plugin will retry opening an encrypted or password-protected archive when a wrong password is given. This value plus 1 is the total number of times the plugin will try opening an encrypted or password-protected archive. | | `extract_archives_recursively` | `true` or `false` | `true` | This option determines whether the plugin will extract all archives inside an archive file recursively. If this option is set to `false`, archive files inside an archive will not be extracted, and you will have to manually extract them yourself. | @@ -76,6 +79,9 @@ require("augment-command"):setup({ smart_paste = false, smart_tab_create = false, smart_tab_switch = false, + open_file_after_creation = false, + enter_directory_after_creation = false, + use_default_create_behaviour = false, enter_archives = true, extract_retries = 3, extract_archives_recursively = true, @@ -105,6 +111,8 @@ An example configuration is shown below: require("augment-command"):setup({ prompt = true, default_item_group_for_prompt = "none", + open_file_after_creation = true, + enter_directory_after_creation = true, extract_retries = 5, ignore_hidden_items = true, wraparound_file_navigation = true, @@ -137,6 +145,12 @@ then it will operate on the selected items. - When `smart_enter` is set to `true`, it calls the `enter` command when the hovered item is a directory. +- `--smart` flag to use one command to `open` files and `enter` directories. + This flag will cause the `open` command to call the `enter` command when + the hovered item is a directory even when `smart_enter` is set to `false`. + This allows you to set a key to use this behaviour + with the `open` command instead of using it for + every `open` command. - `--no-skip` flag, which only applies when `smart_enter` is used as it is passed to the `enter` command. More details about this flag can be found at the documentation @@ -174,6 +188,13 @@ then it will operate on the selected items. contain only one subdirectory when entering directories. This can be turned off by setting `skip_single_subdirectory_on_enter` to `false` in the configuration. +- `--smart` flag to use one command to `enter` directories and `open` files. + This flag will cause the `enter` command to call the `open` command when + the selected items or the hovered item is a file, + even when `smart_enter` is set to `false`. + This allows you to set a key to use this behaviour + with the `enter` command instead of using it for + every `enter` command. - `--no-skip` flag. It stops the plugin from skipping directories that contain only one subdirectory when entering directories, even when `skip_single_subdirectory_on_enter` is set to `true`. @@ -203,6 +224,46 @@ then it will operate on the selected items. - The `remove` command is augmented as stated in [this section above](#what-about-the-commands-are-augmented). +### Create (`create`) + +- You should use Yazi's default `create` command instead of this augmented + `create` command if you don't want the paths without file extensions to + be created as directories by default, and you don't care about automatically + opening and entering the created file and directory respectively. +- The `create` command has a different behaviour from Yazi's `create` command. + When the path given to the command doesn't have a file extension, + the `create` command will create a directory instead of a file, + unlike Yazi's `create` command. Other that this major difference, + the `create` command functions identically to Yazi's `create` command, + which means that you can use a trailing `/` on Unix-like systems + or `\` on Windows to create a directory. It will also recursively + create directories to ensure that the path given exists. + It also supports all the options supported by Yazi's `create` command, + so you can pass them to the command and expect the same behaviour. + However, due to the + [`confirm` component](https://github.com/sxyazi/yazi/issues/2082) + currently not being exposed to plugin developers, it uses Yazi's input + component to prompt for a confirmation, like in Yazi v0.3.0 and below. + This is not ideal, but it shouldn't happen that often and + hopefully wouldn't be too annoying. +- The rationale for this behaviour is that creating a path without + a file extension usually means you intend to create a directory instead + of a file, as files usually have file extensions. +- When `open_file_after_creation` is set to `true`, the `create` command + will `open` the created file. This behaviour can also be enabled by + passing the `--open` flag to the `create` command. + Likewise, when `enter_directory_after_creation` is set to `true`, + the `create` command will `enter` the created directory. + This behaviour can also be enabled by passing the `--enter` flag + to the `create` command. + To enable both behaviours with flags, just pass both the `--open` flag + and the `--enter` flag to the `create` command. +- If you would like to use the behaviour of Yazi's `create` command, + probably because you would like to automatically open and enter the created + file and directory respectively, you can either set + `use_default_create_behaviour` to `true`, + or pass the `--default-behaviour` flag to the `create` command. + ### Shell (`shell`) - This command runs the shell command given with the augment stated in @@ -228,7 +289,7 @@ then it will operate on the selected items. [[manager.prepend_keymap]] on = [ "o" ] - run = 'plugin augment-command --args="shell \"$EDITOR $@\" --block --confirm"' + run = 'plugin augment-command --args="shell \"$EDITOR $@\" --block"' desc = "Open the editor" ``` @@ -242,12 +303,12 @@ then it will operate on the selected items. [[manager.prepend_keymap]] on = [ "o" ] - run = '''plugin augment-command --args='shell "$EDITOR $@" --block --confirm'''' + run = '''plugin augment-command --args='shell "$EDITOR $@" --block'''' desc = "Open the editor" [[manager.prepend_keymap]] on = [ "i" ] - run = '''plugin augment-command --args="shell '$PAGER $@' --block --confirm"''' + run = '''plugin augment-command --args="shell '$PAGER $@' --block"''' desc = "Open the pager" ``` @@ -267,7 +328,7 @@ then it will operate on the selected items. [[manager.prepend_keymap]] on = [ "i" ] - run = '''plugin augment-command --args="shell '$PAGER $@' --block --confirm --exit-if-dir"''' + run = '''plugin augment-command --args="shell '$PAGER $@' --block --exit-if-dir"''' desc = "Open the pager" ``` diff --git a/init.lua b/init.lua index 2d13d74..c9864ef 100644 --- a/init.lua +++ b/init.lua @@ -35,6 +35,9 @@ ---@field smart_paste boolean Whether to use smart paste ---@field smart_tab_create boolean Whether to use smart tab create ---@field smart_tab_switch boolean Whether to use smart tab switch +---@field open_file_after_creation boolean Whether to open after creation +---@field enter_directory_after_creation boolean Whether to enter after creation +---@field use_default_create_behaviour boolean Use Yazi's create behaviour? ---@field enter_archives boolean Whether to enter archives ---@field extract_retries number How many times to retry extracting ---@field extract_archives_recursively boolean Re-extract inner archives or not @@ -70,13 +73,13 @@ ---@field is_archive boolean ---@field is_absolute boolean ---@field has_root boolean ----@field name fun(): string|nil ----@field stem fun(): string|nil ----@field join fun(url: Url|string): Url ----@field parent fun(): Url|nil ----@field starts_with fun(url: Url|string): boolean ----@field ends_with fun(url: Url|string): boolean ----@field strip_prefix fun(url: Url|string): boolean +---@field name fun(self): string|nil +---@field stem fun(self): string|nil +---@field join fun(self, url: Url|string): Url +---@field parent fun(self): Url|nil +---@field starts_with fun(self, url: Url|string): boolean +---@field ends_with fun(self, url: Url|string): boolean +---@field strip_prefix fun(self, url: Url|string): boolean -- The type for the extraction results ---@class (exact) ExtractionResult @@ -102,6 +105,7 @@ local Commands = { Leave = "leave", Rename = "rename", Remove = "remove", + Create = "create", Shell = "shell", Paste = "paste", TabCreate = "tab_create", @@ -122,8 +126,6 @@ local ExtractBehaviour = { RenameExisting = "-aot", } --- The user configuration for the plugin - -- The default configuration for the plugin ---@type UserConfiguration local DEFAULT_CONFIG = { @@ -133,6 +135,9 @@ local DEFAULT_CONFIG = { smart_paste = false, smart_tab_create = false, smart_tab_switch = false, + open_file_after_creation = false, + enter_directory_after_creation = false, + use_default_create_behaviour = false, enter_archives = true, extract_retries = 3, extract_archives_recursively = true, @@ -152,7 +157,7 @@ local DEFAULT_CONFIG = { ---@field level "info" | "warn" | "error" local DEFAULT_NOTIFICATION_OPTIONS = { title = "Augment Command Plugin", - timeout = 5.0, + timeout = 5, } -- The default input options for this plugin @@ -217,10 +222,6 @@ local MIME_TYPE_PREFIXES_TO_REMOVE = { "vnd%.", } --- The pattern to get the double dash from the front of the argument ----@type string -local double_dash_pattern = "^%-%-" - -- The pattern template to get the mime type without a prefix ---@type string local get_mime_type_without_prefix_template_pattern = @@ -353,6 +354,24 @@ local function string_trim(string) return string:match("^%s*(.-)%s*$") end +-- Function to pop a key from a table +---@param table table The table to pop from +---@param key string The key to pop +---@param default any The default value to return if the key doesn't exist +local function table_pop(table, key, default) + -- + + -- Get the value of the key from the table + local value = table[key] + + -- Remove the key from the table + table[key] = nil + + -- Return the value if it exist, + -- otherwise return the default value + return value or default +end + -- Function to parse the number arguments to the number type ---@param args Arguments The arguments to parse ---@return Arguments parsed_args The parsed arguments @@ -380,87 +399,12 @@ local function parse_number_arguments(args) return parsed_args end --- Function to parse the arguments given. --- This function takes the arguments passed to the entry function ----@param args string[] The list of string arguments given by Yazi ----@return Arguments parsed_args The list of arguments with the correct types -local function parse_args(args) - -- - - -- The table of arguments to pass to ya.manager_emit - ---@type Arguments - local parsed_arguments = {} - - -- Iterates over the arguments given - for _, argument in ipairs(args) do - -- - - -- If the argument doesn't start with a double dash - if not argument:find(double_dash_pattern) then - -- - - -- Try to convert the argument to a number - local number_argument = tonumber(argument) - - -- Add the argument to the list of options - table.insert( - parsed_arguments, - number_argument and number_argument or argument - ) - - -- Continue the loop - goto continue - end - - -- Otherwise, remove the double dash from the front of the argument - local cleaned_argument = argument:gsub(double_dash_pattern, "") - - -- Replace all of the dashes with underscores - cleaned_argument = cleaned_argument:gsub("%-", "_") - - -- Split the arguments at the = character - local arg_name, arg_value = - table.unpack(string_split(cleaned_argument, "=")) - - -- If the argument value is nil - if arg_value == nil then - -- - - -- Set the argument name to the cleaned argument - arg_name = cleaned_argument - - -- Set the argument value to true - arg_value = true - - -- Otherwise - else - -- - - -- Try to convert the argument value to a number - local number_arg_value = tonumber(arg_value) - - -- Set the argument value to the number - -- if the the argument value can be converted to a number - arg_value = number_arg_value and number_arg_value or arg_value - end - - -- Add the argument name and value to the options - parsed_arguments[arg_name] = arg_value - - -- The label to continue the loop - ::continue:: - end - - -- Return the table of arguments - return parsed_arguments -end - --- Function to warn the user ----@param warning string The warning message +-- Function to show a warning +---@param warning_message string The warning message ---@return nil -local function warn_user(warning) +local function show_warning(warning_message) return ya.notify(merge_tables(DEFAULT_NOTIFICATION_OPTIONS, { - content = warning, + content = warning_message, level = "warn", })) end @@ -485,6 +429,31 @@ local function get_user_input(prompt) })) end +-- Function to get the user's confirmation +-- TODO: Switch to `ya.confirm()` when it's available +---@param prompt string The prompt to show to the user +---@return boolean confirmation Whether the user has confirmed or not +local function get_user_confirmation(prompt) + -- + + -- Get the user's input + local user_input, event = get_user_input(prompt) + + -- If the user has not confirmed the input, + -- or the user input is nil, + -- then return false + if not user_input or event ~= 1 then return false end + + -- Lowercase the user's input + user_input = user_input:lower() + + -- If the user input starts with a "y", then return true + if user_input:find("^y") then return true end + + -- Otherwise, return false + return false +end + -- Function to merge the given configuration table with the default one ---@param config UserConfiguration|nil The configuration table to merge ---@return UserConfiguration merged_config The merged configuration table @@ -535,7 +504,7 @@ local function merge_configuration(config) if #invalid_configuration_options <= 0 then return merged_config end -- Otherwise, warn the user of the invalid configuration options - warn_user( + show_warning( "Invalid configuration options: " .. table.concat(invalid_configuration_options, ", ") ) @@ -562,7 +531,7 @@ local initialise_config = ya.sync(function(state, user_config, additional_data) return state.config end) --- The function to try if a shell command exists +-- Function to try if a shell command exists ---@param shell_command string The shell command to check ---@return boolean shell_command_exists Whether the shell command exists local function shell_command_exists(shell_command) @@ -610,7 +579,7 @@ local function shell_command_exists(shell_command) return successfully_executed end --- The function to initialise the plugin +-- Function to initialise the plugin ---@param opts Configuration|nil The options given to the plugin ---@return Configuration config The initialised configuration object local function initialise_plugin(opts) @@ -812,6 +781,13 @@ local get_paths_of_selected_items = ya.sync(function(_, quote) return paths_of_selected_items end) +-- Function to get if Yazi is loading +---@param _ any +---@return boolean is_loading Whether Yazi is loading +local yazi_is_loading = ya.sync( + function(_) return cx.active.current.stage.is_loading end +) + -- Function to choose which group of items to operate on. -- It returns ItemGroup.Hovered for the hovered item, -- ItemGroup.Selected for the selected items, @@ -935,7 +911,7 @@ local function get_item_group() end end --- The function to get all the items in the given directory +-- Function to get all the items in the given directory ---@param directory string The path to the directory ---@param ignore_hidden_items boolean Whether to ignore hidden items ---@param directories_only boolean|nil Whether to only get directories @@ -993,7 +969,10 @@ local function skip_single_child_directories(args, config, initial_directory) -- If the user doesn't want to skip single subdirectories on enter, -- or one of the arguments passed is no skip, -- then exit the function - if not config.skip_single_subdirectory_on_enter or args.no_skip then + if + not config.skip_single_subdirectory_on_enter + or table_pop(args, "no_skip", false) + then return end @@ -1031,7 +1010,7 @@ local function skip_single_child_directories(args, config, initial_directory) ya.manager_emit("cd", { directory }) end --- The function to check if an archive is password protected +-- Function to check if an archive is password protected ---@param command_error_string string The error string from the extractor ---@return boolean is_encrypted Whether the archive is password protected local function archive_is_encrypted(command_error_string) @@ -1046,12 +1025,12 @@ local function archive_is_encrypted(command_error_string) end end --- The function to handle retrying the extractor command +-- Function to handle retrying the extractor command -- -- The initial password is the password given to the extractor command -- and the test encryption is to test the archive password without -- actually executing the given extractor command. ----@param extractor_function ExtractorFunction The function to run the extractor +---@param extractor_function ExtractorFunction Function to run the extractor ---@param config Configuration The configuration object ---@param initial_password string|nil The initial password to try ---@param archive_path string|nil The path to the archive file @@ -1233,7 +1212,7 @@ local function list_archive_items_command( :output() end --- The function to get if the archive +-- Function to get if the archive -- file has more than one file in it. ---@param archive_path string The path to the archive file ---@param config Configuration The configuration object @@ -1244,7 +1223,7 @@ end local function get_archive_items(archive_path, config) -- - -- The function to list the items in the archive + -- Function to list the items in the archive local function list_items_in_archive(password, configuration, _) return list_archive_items_command( archive_path, @@ -1332,6 +1311,7 @@ local function get_temporary_directory_url(path) -- -- Get the parent directory of the file path + ---@type Url local parent_directory = Url(path):parent() -- If the parent directory doesn't exist, then return nil @@ -1418,7 +1398,7 @@ local function extract_command( :output() end --- The function to get the mime type of a file +-- Function to get the mime type of a file ---@param file_path string The path to the file ---@return string mime_type The mime type of the file local function get_mime_type(file_path) @@ -1451,7 +1431,7 @@ local function get_mime_type(file_path) return mime_type end --- The function to check if a file is an archive +-- Function to check if a file is an archive ---@param file_path string The path to the file ---@return boolean is_archive Whether the file is an archive local function is_archive_file(file_path) @@ -1470,7 +1450,7 @@ local function is_archive_file(file_path) return is_archive end --- The function to clean up the temporary directory +-- Function to clean up the temporary directory -- after extracting an archive. ---@param temporary_directory_url Url The url of the temporary directory ---@param removal_mode "dir" | "dir_all" | "dir_clean" The removal mode @@ -1490,7 +1470,7 @@ local function clean_up_temporary_directory( return ... end --- The function to move extracted items out of the temporary directory +-- Function to move extracted items out of the temporary directory ---@param archive_url Url The url of the archive ---@param temporary_directory_url Url The url of the temporary directory ---@return boolean move_successful Whether the move was successful @@ -1638,7 +1618,7 @@ local function move_extracted_items_to_archive_parent_directory( ) end ---- The function to extract an archive. +--- Function to extract an archive. ---@param archive_path string The path to the archive ---@param config Configuration The configuration object ---@param has_only_one_file boolean Whether the archive has only one file @@ -1679,6 +1659,7 @@ local function extract_archive( end -- Get the url of the archive + ---@type Url local archive_url = Url(archive_path) -- Get the name of the archive @@ -1755,7 +1736,7 @@ local function extract_archive( return extraction_result end --- The function to recursively extract archives +-- Function to recursively extract archives ---@param archive_path string The path to the archive ---@param config Configuration The configuration object ---@return ExtractionResult[] extraction_results The list of extraction results @@ -1818,6 +1799,7 @@ local function recursively_extract_archives(archive_path, config) end -- Get the url of the extracted items path + ---@type Url local extracted_items_url = Url(extracted_items_path) -- Initialise the base url for the extracted items @@ -1920,7 +1902,7 @@ local function handle_open(args, config, command_table) -- If smart enter is wanted, -- calls the function to enter the directory -- and exit the function - if config.smart_enter then + if config.smart_enter or table_pop(args, "smart", false) then return enter_command(args, config, command_table) end @@ -2007,13 +1989,13 @@ local function handle_enter(args, config, command_table) local open_command = command_table[Commands.Open] -- If the hovered item is not a directory - if not hovered_item_is_dir() and config.smart_enter then + if not hovered_item_is_dir() then -- -- If smart enter is wanted, -- call the function for the open command -- and exit the function - if config.smart_enter then + if config.smart_enter or table_pop(args, "smart", false) then return open_command(args, config, command_table) end @@ -2042,7 +2024,10 @@ local function handle_leave(args, config) -- If the user doesn't want to skip single subdirectories on leave, -- or one of the arguments passed is no skip, -- then exit the function - if not config.skip_single_subdirectory_on_leave or args.no_skip then + if + not config.skip_single_subdirectory_on_leave + or table_pop(args, "no_skip", false) + then return end @@ -2062,6 +2047,7 @@ local function handle_leave(args, config) if #directory_items ~= 1 then break end -- Get the parent directory of the current directory + ---@type Url local parent_directory = Url(directory):parent() -- If the parent directory is nil, @@ -2105,6 +2091,196 @@ local function handle_yazi_command(command, args) end end +-- Function to enter or open the created file +---@param item_url Url The url of the item to create +---@param is_directory boolean|nil Whether the item to create is a directory +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object +---@return nil +local function enter_or_open_created_item(item_url, is_directory, args, config) + -- + + -- If the item is a directory + if is_directory then + -- + + -- If user does not want to enter the directory + -- after creating it, exit the function + if + not ( + config.enter_directory_after_creation + or table_pop(args, "enter", false) + ) + then + return + end + + -- Otherwise, call the function change to the created directory + ya.manager_emit("cd", { tostring(item_url) }) + + -- Otherwise, the item is a file + else + -- + + -- If the user does not want to open the file + -- after creating it, exit the function + if + not ( + config.open_file_after_creation + or table_pop(args, "open", false) + ) + then + return + end + + -- Otherwise, call the function to reveal the created file + ya.manager_emit("reveal", { tostring(item_url) }) + + -- Wait for Yazi to finish loading + while yazi_is_loading() do + end + + -- Call the function to open the file + ya.manager_emit("open", { hovered = true }) + end +end + +-- Function to execute the create command +---@param item_url Url The url of the item to create +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object +---@return nil +local function execute_create(item_url, is_directory, args, config) + -- + + -- Get the parent directory of the file to create + local parent_directory_url = item_url:parent() + + -- If the parent directory doesn't exist, + -- then show an error and exit the function + if not parent_directory_url then + return show_error( + "Parent directory of the item to create doesn't exist" + ) + end + + -- If the item to create is a directory + if is_directory then + -- + + -- Call the function to create the directory + local successful, error_message = fs.create("dir_all", item_url) + + -- If the function is not successful, + -- show the error message and exit the function + if not successful then return show_error(tostring(error_message)) end + + -- Otherwise, the item to create is a file + else + -- + + -- Otherwise, create the parent directory if it doesn't exist + if not fs.cha(parent_directory_url, false) then + -- + + -- Call the function to create the parent directory + local successful, error_message = + fs.create("dir_all", parent_directory_url) + + -- If the function is not successful, + -- show the error message and exit the function + if not successful then + return show_error(tostring(error_message)) + end + end + + -- Otherwise, create the file + local successful, error_message = fs.write(item_url, "") + + -- If the function is not successful, + -- show the error message and exit the function + if not successful then return show_error(tostring(error_message)) end + end + + -- Call the function to enter or open the created item + enter_or_open_created_item(item_url, is_directory, args, config) +end + +-- Function to handle the create command +---@param args Arguments The arguments passed to the plugin +---@param config Configuration The configuration object +---@return nil +local function handle_create(args, config) + -- + + -- Otherwise, get the user's input for the item to create + local user_input, event = get_user_input("Create:") + + -- If the user did not confirm the input, + -- or the user input is nil, + -- exit the function + if not user_input or event ~= 1 then return end + + -- Get the current working directory as a url + local current_working_directory = fs.cwd() + + -- If there's not current working directory, + -- then show an error and exit the function + if not current_working_directory then + return show_error("Current working directory doesn't exist") + end + + -- Get whether the url ends with a path delimiter + local ends_with_path_delimiter = user_input:find("[/\\]$") + + -- Get the whether the given item is a directory or not based + -- on the default conditions for a directory + local is_directory = ends_with_path_delimiter + or table_pop(args, "dir", false) + + -- Get the url from the user's input + ---@type Url + local item_url = Url(user_input) + + -- If the user does not want to use the default Yazi create behaviour + if + not ( + config.use_default_create_behaviour + or table_pop(args, "default_behaviour", false) + ) + then + -- + + -- Get the file extension from the user's input + local file_extension = user_input:match(file_extension_pattern) + + -- Set the is directory variable to the is directory condition + -- or if the file extension exists + is_directory = is_directory or not file_extension + end + + -- Get the full url of the item to create + local full_url = current_working_directory:join(item_url) + + -- If the path to the item to create already exists, + -- and the user did not pass the force flag + if fs.cha(full_url, false) and not table_pop(args, "force", false) then + -- + + -- Get the user's confirmation for + -- whether they want to overwrite the item + local user_confirmation = + get_user_confirmation("The item already exists, overwrite? (y/N)") + + -- If the user did not confirm the overwrite, + -- then exit the function + if not user_confirmation then return end + end + + -- Call the function to execute the create command + return execute_create(full_url, is_directory, args, config) +end + -- Function to remove the F flag from the less command ---@param command string The shell command containing the less command ---@return string command The command with the F flag removed @@ -2273,7 +2449,7 @@ local function handle_shell(args, _, _, exit_if_dir) -- If the exit if directory flag is not given, -- and the arguments contain the -- exit if directory flag - if not exit_if_dir and args.exit_if_dir then + if not exit_if_dir and table_pop(args, "exit_if_dir", false) then -- -- Set the exit if directory flag to true @@ -2352,7 +2528,10 @@ local function handle_paste(args, config) -- -- If the hovered item is not a directory or smart paste is not wanted - if not hovered_item_is_dir() or not (config.smart_paste or args.smart) then + if + not hovered_item_is_dir() + or not (config.smart_paste or table_pop(args, "smart", false)) + then -- -- Just paste the items inside the current directory @@ -2370,7 +2549,7 @@ local function handle_paste(args, config) ya.manager_emit("leave", {}) end --- The function to execute the tab create command +-- Function to execute the tab create command ---@param state State The state object ---@param args Arguments The arguments passed to the plugin ---@return nil @@ -2388,7 +2567,7 @@ local execute_tab_create = ya.sync(function(state, args) -- in the hovered directory if hovered_item_is_directory - and (state.config.smart_tab_create or args.smart) + and (state.config.smart_tab_create or table_pop(args, "smart", false)) then -- @@ -2428,7 +2607,9 @@ local execute_tab_switch = ya.sync(function(state, args) -- or the tab index is not given, -- then just call the tab switch command -- and exit the function - if not (state.config.smart_tab_switch or args.smart) then + if + not (state.config.smart_tab_switch or table_pop(args, "smart", false)) + then return ya.manager_emit("tab_switch", args) end @@ -2750,6 +2931,7 @@ local function run_command_func(command, args, config) [Commands.Leave] = handle_leave, [Commands.Rename] = function(_) handle_yazi_command("rename", args) end, [Commands.Remove] = function(_) handle_yazi_command("remove", args) end, + [Commands.Create] = handle_create, [Commands.Shell] = handle_shell, [Commands.Paste] = handle_paste, [Commands.TabCreate] = handle_tab_create, @@ -2783,7 +2965,7 @@ local function setup(_, opts) initialise_plugin(opts) end --- The function to be called to use the plugin +-- Function to be called to use the plugin ---@param _ any ---@param job Job The job object given by Yazi ---@return nil @@ -2792,7 +2974,7 @@ local function entry(_, job) -- Get the arguments to the plugin ---@type Arguments - local args = parse_number_arguments(job.args) or parse_args(job) + local args = parse_number_arguments(job.args) -- Get the command passed to the plugin local command = table.remove(args, 1)