-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(commands): add support for custom typable commands #12320
base: master
Are you sure you want to change the base?
Conversation
refactor: no longer special case for bracket lists refactor: no longer special case end space This was a hold over from before the `raw` function was added to `Args`. perf: remove `bytes` field to save 16 bytes From 56 bytes to 40, saving 16 bytes. perf: move `in_quotes` field to local variable perf: move `quote` field to local variable refactor: remove `is_finished` state from `Args` test: change example command to `read` `yank-join` now uses `raw` and thus would not be parsed with the `next` function so no longer applicable. refactor: remove unneeded range end for index refactor: remove backtracking escape check Instead, it can be tracked as the parser scans through the first time. refactor: clean up code and add more comments feat(shellwords): add test for empty values
refactor(commands): ignore unit pattern match refactor(commands): use `if let` over `matches!` refactor(commands): ignore unit pattern match perf(commands):remove unnecessary ref for a &str refactor(commands): change `MappableCommand` `args` from `Vec<String>` to String refactor(commands): use `Args::raw` over `fold`ing refactor: use `rest` in `set_option` command refactor: use `rest` in `toggle_option` command chore(dap): add TODOs to switch to `Args` perf: change `ok_or` to `ok_or_else` to make fn call lazy feat(shellwords): add `args_count` to `Args` fix(commands): default to `line_ending` for `yank_join` when args are empty
Unfortunate happening with lifetimes here. Also supports getting the commands from the custom label and running them as typable commands.
@the-mikedavis I have some questions on the implimentation of how I can get access to the commands in the config.
// helix-term/src/config.rs
pub struct Config {
pub theme: Option<String>,
pub keys: HashMap<Mode, KeyTrie>,
pub editor: helix_view::editor::Config,
} And as
And I assume there would be another area which handles reloading the config. So If I do this change in |
Something more difficult than I thought would be is figuring out how best to merge arguments. For now I assume that if the typed command( It needs to work the simplest usage as well as when there are chained commands. Just because the input command has arguments, it should not be assumed that the chained commands wont want to run their own arguments. This needs to take place even for basic aliases: [commands]
":w!" = ":write --force %{arg}" In the input, we can provide a path, but with the current logic, all args for the write command, including the flags, would be disregarded. In this case, only using the provided path, as We also cant just send the input args to each command, as some commands explicitly take no arguments. And with an |
Actually, I think it might be fine, as it will get merged correctly on variable expansion, but will have to wait and see when that gets merged and base off those changes to check. For now there is a validator to decide what to do. |
58df78c
to
b363c57
Compare
3f70d97
to
984c447
Compare
984c447
to
3fce8f9
Compare
Have the config parsing implemented, at least as a placeholder until I can get more direction. The command validation is tricker than I expected it to be. They keys are turned into a
|
Also not sure if there exists the same issue where We also wouldnt be able to sperate multi-operations, like |
TODO
editor.config
MappableCommand
, but the custom commands cannt be put in that part of the execution path.:test
in a rust context(buffer?) might have a:sh wezterm cli spawn --floating-pane cargo test
:test
in a go context might have a:sh wezterm cli spawn --floating-pane go test
The implimentation needs to build off of #12288 and #11164 which themselves build off of #11149, so still a ways out, but I think I have a good framework going forward.
Concept
Config
Basic
The config will get a
[commands]
table for which the custom commands will go. At the most basic level of usage, an alias for a single command, it would look like this:This would provide no completions, only showing up in the list of commands. The prompt would be bare, only the name and the mapping, no description or what it accepts:
Advanced
The most advanced usage is what I hope to be possible to implement, but as I haven't actually done it, jury is still out on what's actually feasible:
This would show the commands from the list of commands like before, but now offers the ability to run multiple commands in a chain, provide positional arguments, a description, indicate what it accepts, as well as which completer to run when using the command, sourced from the name of an existing typable command.
The prompt now looks like this:
%{arg}
represents a positional argument that is provided when using the command.These could be given numbers as well:
%{arg:1}
.%{arg}
would be equal to%{arg:0}
. This is able to take advantage of theArgs
iterator that #11149 introduces, just taking the number provided and pass it tonth
.Nesting
Custom commands can also be used in other custom commands, though with some limitations to be mindful of:
The prompt would look like so, again if the first impl was a
wcd
, no force.In short, it works, but the design of the commands must be able to compose.
Implimentation Details
Its is based around a
CustomTypableCommand
struct:The config itself would hold a wrapper of this:
The usage of this would look roughly like:
There is more here that would need to be layered in, like the flags and expanding the variables from the other PRs, but this is the gist.
The main points I haven't delved into yet is the parsing from the toml into the struct and add it to the config, which to me is looking like the hardest part (😆). As well as how to provide the command in the list of commands, and be able to show the prompt for it properly.
Currently, this is pretty hacky due to lifetimes, but should work (at least its able to compile currently):
The commands have to be cloned into the closure and because it stores
Strings
, you cant just make acommand.name.as_str
call, as that references the local function, and the prompt has its own lifetime. Due to this, I had to make all the&'static str
on theTYPABLE_COMMAND_LIST
String
as well, and then collect into aVec
. This is meant to be temporary, but would love some help here to prevent all these allocations. The jank might have to last until theCustomTypableCommand
can directly store aTypeableCommand
, which needs #5555 to be completed. Otherwise the completers might just have lifetime issues as they cannot be static.I'd also love some feedback on the TOML design, as well as some example usage, some ultra creative ones, to make sure I can design around as much as possible. Like I said at the start, this is all a ways out, but this still has issues to work out anyways, so hopefully if we get these ironed out, and the dependent pull requests merge in without issue, and I can work on this in the next release cycle as a major feature of the release.
Potentially Common Use-Cases
Floating
lazygit
paneFloating terminal pane
Floating
yazi
paneRemoving current buffer file
Future Considerations
Remove some static aliases
#12288 allows the ability to collapse current separate commands, where behavior can be dictated by flags, into a single command. This is good in a lot of ways, but the side effect is that for a command like
write
, the prompt is filled with aliases:With the ability to have custom commands, including aliasing, it might be worth it to remove some currently statically defined aliases.
Furthering this idea, is that with the collapsing of commands to a single one, we can adopt a concept where we consider these are now primitives, in which can be composed together:
We could also provide a set of defaults, basically what we have now, that crosscut here, away from the "primitive" commands. This would be the blend boundary, and we are just exposing a frontend in the form of a config for the users to also have this ability. Considering they are documented and show the underlying commands, I think it would be enough to inform the user what it happening.
Escaping
Note
Currently this is a feature, but will need to be discussed if it remains or not.
If a user makes a mapping that is the same as a built-in one, should there be a way to escape? For example, we could allow a
^
prefix to escape shadowing:If we have:
:^w # :write
Deterministic Command Execution
Currently, when you list commands,
[":sh ...", ":open ..."]
,:open
can happen before:sh
is finished. This is done so that there is no blocking that happens. However, this breaks the users assumption that this will work just fine, leading to confusion. This also affects macros as well, for example, preventing their use in sequences. Going forward, non UI blocking, sequential execution order should be strived for. Not only would this line up with expectations, it will also make the command system more powerful and expressive, making it straight forward to compose them together.Closes: #4423