pub struct Commands<U>where
U: Ui,{ /* private fields */ }Expand description
Implementations§
source§impl<U> Commands<U>where
U: Ui,
impl<U> Commands<U>where
U: Ui,
sourcepub const fn new(
current_file: &'static CurFile<U>,
current_widget: &'static CurWidget<U>,
) -> Self
pub const fn new( current_file: &'static CurFile<U>, current_widget: &'static CurWidget<U>, ) -> Self
Returns a new instance of Commands.
sourcepub fn quit(&self)
pub fn quit(&self)
Canonical way to quit Duat.
By calling the quit command, all threads will finish their
tasks, and then Duat will execute a program closing
function, as defined by the Ui.
sourcepub fn switch_to<W: ActiveWidget<U>>(&self) -> Result<Option<Text>, ()>
pub fn switch_to<W: ActiveWidget<U>>(&self) -> Result<Option<Text>, ()>
Switches to the given ActiveWidget.
The widget will be chosen in the following order:
- The first of said widget pushed to the current
File. - Other instances of it in the current window.
- Instances in other windows.
sourcepub fn edit(&self, file: impl Display) -> Result<Option<Text>, ()>
pub fn edit(&self, file: impl Display) -> Result<Option<Text>, ()>
Switches to/opens a File with the given name.
If you wish to specifically switch to files that are already
open, use Commands::buffer.
If there are more arguments, they will be ignored.
sourcepub fn buffer(&self, file: impl Display) -> Result<Option<Text>, ()>
pub fn buffer(&self, file: impl Display) -> Result<Option<Text>, ()>
Switches to a File with the given name.
If there is no file open with that name, does nothing. Use
Commands::edit if you wish to open files.
If there are more arguments, they will be ignored.
sourcepub fn next_file(&self) -> Result<Option<Text>, ()>
pub fn next_file(&self) -> Result<Option<Text>, ()>
Switches to the next File.
This function will only look at files that are opened in the
current window. If you want to include other windows in the
search, use Commands::next_global_file.
sourcepub fn prev_file(&self) -> Result<Option<Text>, ()>
pub fn prev_file(&self) -> Result<Option<Text>, ()>
Switches to the previous File.
This function will only look at files that are opened in the
current window. If you want to include other windows in the
search, use Commands::prev_global_file.
sourcepub fn next_global_file(&self) -> Result<Option<Text>, ()>
pub fn next_global_file(&self) -> Result<Option<Text>, ()>
Switches to the next File.
This function will look for files in all windows. If you want
to limit the search to just the current window, use
Commands::next_file.
sourcepub fn prev_global_file(&self) -> Result<Option<Text>, ()>
pub fn prev_global_file(&self) -> Result<Option<Text>, ()>
Switches to the previous File.
This function will look for files in all windows. If you want
to limit the search to just the current window, use
Commands::prev_file.
sourcepub fn return_to_file(&self) -> Result<Option<Text>, ()>
pub fn return_to_file(&self) -> Result<Option<Text>, ()>
If not in a File, switches to the last active File.
This is useful if the currently active widget is not a file
(e.g. CommandLine, a file tree, etc), and you want to
return to the file seamlessly.
sourcepub fn alias(
&self,
alias: impl ToString,
command: impl ToString,
) -> Result<Option<Text>, ()>
pub fn alias( &self, alias: impl ToString, command: impl ToString, ) -> Result<Option<Text>, ()>
Tries to alias a caller to an existing command.
Returns an Err if the caller is already a caller for
another command, or if command is not a real caller to an
exisiting [Command].
sourcepub fn run(&self, call: impl Display) -> Result<Option<Text>, ()>
pub fn run(&self, call: impl Display) -> Result<Option<Text>, ()>
Runs a full command, with a caller, Flags, and Args.
When running the command, the ordering of flags does not matter, as long as they are placed before the arguments to the command.
§Examples
context.commands.run("set-prompt new-prompt")In this case we’re running a command that will affect the most
relevant CommandLine. See Commands::add_for_widget for
more information.
sourcepub fn add(
&self,
callers: impl IntoIterator<Item = impl ToString>,
f: impl FnMut(Flags<'_, '_>, Args<'_>) -> CmdResult + 'static,
) -> Result<(), ()>
pub fn add( &self, callers: impl IntoIterator<Item = impl ToString>, f: impl FnMut(Flags<'_, '_>, Args<'_>) -> CmdResult + 'static, ) -> Result<(), ()>
Adds a command to the global list of commands.
This command cannot take any arguments beyond the Flags
and Args, so any mutation of state must be done
through captured variables, usually in the form of
RwDatas.
§Examples
// Shared state, which will be displayed in a `StatusLine`.
let var = RwData::new(35);
/* inside of a plugin, where a `Context` could be found */
context.commands.add(["set-var"], {
let var = var.clone();
move |_flags, mut args| {
let value: usize = args.next_as()?;
*var.write() = value;
Ok(None)
}
});
/* */
let status_cfg = status!("The value is currently " var);Since var is an RwData, it will be updated
automatically in the StatusLine
sourcepub fn add_for_current<T: 'static>(
&'static self,
callers: impl IntoIterator<Item = impl ToString>,
f: impl FnMut(&mut T, Flags<'_, '_>, Args<'_>) -> CmdResult + 'static,
) -> Result<(), ()>
pub fn add_for_current<T: 'static>( &'static self, callers: impl IntoIterator<Item = impl ToString>, f: impl FnMut(&mut T, Flags<'_, '_>, Args<'_>) -> CmdResult + 'static, ) -> Result<(), ()>
Adds a command to an object “related” to the current File
This object can be one of three things, a PassiveWidget,
an InputMethod, or the File itself. When the
command is ran, Duat will look at the currently active
file for any instance of an RwData<Thing> it can find.
Those will either be the file itself, or will be added in
the Session’s “file_fn”.
§Examples
#[derive(Debug)]
enum Mode {
Normal,
Insert,
Prompt,
Visual,
}
struct ModalEditor {
mode: Mode,
}
impl InputMethod for ModalEditor {
/* Implementation details. */
}
context.commands.add_for_current::<ModalEditor>(
["set-mode"],
|modal, flags, mut args| {
let mode = args.next_else(text!("No mode given"))?;
match mode {
"normal" | "Normal" => modal.mode = Mode::Normal,
"insert" | "Insert" => modal.mode = Mode::Insert,
"prompt" | "Prompt" => modal.mode = Mode::Prompt,
"visual" | "Visual" => modal.mode = Mode::Visual,
mode => {
return Err(text!(
"Mode" [AccentErr] mode []
"is not a valid mode"
));
}
}
let mode = format!("{:?}", modal.mode);
Ok(Some(text!("Mode was set to " [AccentOk] mode [] ".")))
}
)
.unwrap();sourcepub fn add_for_widget<W: PassiveWidget<U>>(
&'static self,
callers: impl IntoIterator<Item = impl ToString>,
f: impl FnMut(&mut W, &U::Area, Flags<'_, '_>, Args<'_>) -> CmdResult + 'static,
) -> Result<(), ()>
pub fn add_for_widget<W: PassiveWidget<U>>( &'static self, callers: impl IntoIterator<Item = impl ToString>, f: impl FnMut(&mut W, &U::Area, Flags<'_, '_>, Args<'_>) -> CmdResult + 'static, ) -> Result<(), ()>
Adds a command that can mutate a widget of the given type,
along with its associated dyn Area.
This command will look for the PassiveWidget in the
following order:
- Any instance that is “related” to the currently active
File, that is, any widgets that were added during theSession’s “file_fn”. - Other widgets in the currently active window, related or
not to any given
File. - Any instance of the
PassiveWidgetthat is found in other windows, looking first at windows ahead.
Keep in mind that the search is deterministic, that is, if there are multiple instances of the widget that fit the same category, only one of them will ever be used.
This search algorithm allows a more versatile configuration of
widgets, for example, one may have a CommandLine per
File, or one singular CommandLine that acts upon
all files in the window, and both would respond correctly
to the "set-prompt" command.
§Examples
In this example, we create a simple Timer widget, along with
some control commands.
// Required feature for widgets.
#![feature(return_position_impl_trait_in_trait)]
impl PassiveWidget for Timer {
fn build<U: Ui>() -> (Widget<U>, impl Fn() -> bool, PushSpecs) {
let timer = Self {
text: text!(AlignCenter [Counter] "0ms"),
instant: Instant::now(),
// No need to use an `RwData`, since
// `RwData::has_changed` is never called.
running: Arc::new(AtomicBool::new(false)),
};
// The checker should tell the `Timer` to update only
// if `running` is `true`.
let checker = {
// Clone any variables before moving them to
// the `checker`.
let running = timer.running.clone();
move || running.load(Ordering::Relaxed)
};
let specs = PushSpecs::below().with_lenght(1.0);
(Widget::passive(timer), checker, specs)
}
fn update(&mut self, _area: &impl Area) {
if self.running.load(Ordering::Relaxed) {
let duration = self.instant.elapsed();
let duration = format!("{:.3?}", duration);
self.text = text!(
AlignCenter [Counter] duration [] "elapsed"
);
}
}
fn text(&self) -> &Text {
&self.text
}
// The `once` function of a `PassiveWidget` is only called
// when that widget is first created.
// It is generally useful to add commands and set forms
// in the `palette`.
fn once() {
// `palette::set_weak_form` will only set that form if
// it doesn't already exist.
// That means that a user of the widget will be able to
// control that form by changing it before or after this
// widget is pushed.
palette::set_weak_form("Counter", Form::new().green());
commands::add_for_widget::<Timer>(
["play"],
|timer, _area, _flags, _args| {
timer.running.store(true, Ordering::Relaxed);
Ok(None)
})
.unwrap();
commands::add_for_widget::<Timer>(
["pause"],
|timer, _area, _flags, _args| {
timer.running.store(false, Ordering::Relaxed);
Ok(None)
})
.unwrap();
commands::add_for_widget::<Timer>(
["pause"],
|timer, _area, _flags, _args| {
timer.instant = Instant::now();
Ok(None)
})
.unwrap();
}
}