duat_core/mode/
mod.rs

1//! [`Mode`]s that handle user input
2//!
3//! Each [`Mode`] controls a specifig type of [`Widget`], and
4//! switching [`Mode`]s is how one sets the current [`Widget`]. For
5//! example, the [`Standard`] (like most [`Mode`]s), controls the
6//! [`File`] [`Widget`]. So when you switch to that [`Mode`], you
7//! return to the active [`File`] if you were focused on another
8//! [`Widget`].
9//!
10//! Other than the [`File`] the main [`Widget`] that is controled by
11//! [`Mode`]s is the [`PromptLine`]. It is an example of a [`Widget`]
12//! that has many [`Mode`]s implemented for it. Chief of which is
13//! [`RunCommands`], but there is also [`IncSearch`] and
14//! [`PipeSelections`], and the creation of more [`Mode`]s for the
15//! [`PromptLine`] is very much encouraged.
16//!
17//! [`Standard`]: docs.rs/duat-utils/latest/duat_utils/modes/struct.Standard.html
18//! [`PromptLine`]: docs.rs/duat-utils/latest/duat_utils/widgets/struct.PromptLine.html
19//! [`RunCommands`]: docs.rs/duat-utils/latest/duat_utils/modes/struct.RunCommands.html
20//! [`IncSearch`]: docs.rs/duat-utils/latest/duat_utils/modes/struct.IncSearch.html
21//! [`PipeSelections`]: docs.rs/duat-utils/latest/duat_utils/modes/struct.PipeSelections.html
22use core::str;
23use std::sync::atomic::{AtomicBool, Ordering};
24
25pub use crossterm::event::{KeyCode, KeyEvent};
26
27/// Key modifiers, like Shift, Alt, Super, Shift + Alt, etc
28pub type KeyMod = crossterm::event::KeyModifiers;
29
30pub use self::{
31    cursor::{Cursor, Cursors, PointOrPoints, Selection, Selections, VPoint},
32    remap::*,
33    switch::*,
34};
35use crate::{
36    context::Handle,
37    data::Pass,
38    file::File,
39    ui::{Ui, Widget},
40};
41
42mod cursor;
43mod remap;
44mod switch;
45
46/// A blank [`Mode`], intended for plugin authors to use
47///
48/// This [`Mode`] just resets to the default [`File`] [`Mode`], no
49/// matter what key is pressed. It is instead used for mapping keys to
50/// other [`Mode`]s in a common place:
51///
52/// ```rust
53/// # use duat_core::doc_duat as duat;
54/// # mod plugin0{
55/// #     use duat_core::prelude::*;
56/// #     #[derive(Clone, Copy, Debug)]
57/// #     pub struct PluginMode0;
58/// #     impl<U: Ui> Mode<U> for PluginMode0 {
59/// #         type Widget = File<U>;
60/// #         fn send_key(&mut self, _: &mut Pass, _: KeyEvent, _: Handle<Self::Widget, U>) {}
61/// #     }
62/// # }
63/// # mod plugin1 {
64/// #     use duat_core::prelude::*;
65/// #     #[derive(Clone, Copy, Debug)]
66/// #     pub struct PluginMode1;
67/// #     impl<U: Ui> Mode<U> for PluginMode1 {
68/// #         type Widget = File<U>;
69/// #         fn send_key(&mut self, _: &mut Pass, _: KeyEvent, _: Handle<Self::Widget, U>) {}
70/// #     }
71/// # }
72/// # mod kak {
73/// #     use duat_core::prelude::*;
74/// #     #[derive(Clone, Copy, Debug)]
75/// #     pub struct Normal;
76/// #     impl<U: Ui> Mode<U> for Normal {
77/// #         type Widget = File<U>;
78/// #         fn send_key(&mut self, _: &mut Pass, _: KeyEvent, _: Handle<Self::Widget, U>) {}
79/// #     }
80/// # }
81/// setup_duat!(setup);
82/// use duat::prelude::*;
83/// use plugin0::*;
84/// use plugin1::*;
85///
86/// fn setup() {
87///     map::<User>("0", PluginMode0);
88///     map::<User>("1", PluginMode1);
89///     map::<kak::Normal>(" ", User);
90/// }
91/// ```
92///
93/// This way, there is a common "hub" for mappings, which plugins can
94/// use in order to map their own [`Mode`]s without interfering with
95/// the user's mapping.
96#[derive(Clone, Copy, Debug)]
97pub struct User;
98
99impl<U: Ui> Mode<U> for User {
100    type Widget = File<U>;
101
102    fn send_key(&mut self, _: &mut Pass, _: KeyEvent, _: Handle<Self::Widget, U>) {
103        reset::<File<U>, U>();
104    }
105}
106
107/// Wether the reverse modifier should be [alt] as opposed to [shift]
108///
109/// [shift]: KeyMod::SHIFT
110/// [alt]: KeyMod::ALT
111static ALT_IS_REFERSE: AtomicBool = AtomicBool::new(false);
112
113/// Wether [alt] should be the reverse [modifier], instead of [shift]
114///
115/// On most editing models, the key that reverses actions (mostly
116/// searching), is the [shift] key, (like `shift + n` to go to the
117/// previouse match). In other situations though, that may not be the
118/// case, like with [`duat-kak`], where that key is [alt] (for
119/// consistency reasons).
120///
121/// Changing this key via [`set_alt_is_reverse`] does not cause any
122/// internal changes in [`duat-core`] or [`duat-utils`]. It is only
123/// meant to serve as a general setting for plugins to follow.
124///
125/// [modifier]: KeyMod
126/// [shift]: KeyMod::SHIFT
127/// [alt]: KeyMod::ALT
128/// [`duat-kak`]: docs.rs/duat-kak/latest/duat_kak
129/// [`duat-core`]: docs.rs/duat-core/latest/duat_core
130/// [`duat-utils`]: docs.rs/duat-utils/latest/duat_utils
131pub fn alt_is_reverse() -> bool {
132    ALT_IS_REFERSE.load(Ordering::Relaxed)
133}
134
135/// Sets wether [alt] should be the reverse [modifier], instead of
136/// [shift]
137///
138/// On most editing models, the key that reverses actions (mostly
139/// searching), is the [shift] key, (like `shift + n` to go to the
140/// previouse match). In other situations though, that may not be the
141/// case, like with [`duat-kak`], where that key is [alt] (for
142/// consistency reasons).
143///
144/// The value of this setting can be retrieved with
145/// [`alt_is_reverse`].
146///
147/// [modifier]: KeyMod
148/// [shift]: KeyMod::SHIFT
149/// [alt]: KeyMod::ALT
150/// [`duat-kak`]: docs.rs/duat-kak/latest/duat_kak
151/// [`duat-core`]: docs.rs/duat-core/latest/duat_core
152/// [`duat-utils`]: docs.rs/duat-utils/latest/duat_utils
153pub fn set_alt_is_reverse(value: bool) -> bool {
154    ALT_IS_REFERSE.swap(value, Ordering::Relaxed)
155}
156
157/// A mode for a [`Widget`]
158///
159/// [`Mode`]s are the way that Duat decides how keys are going to
160/// modify widgets.
161///
162/// For this example, I will create a `Menu` widget. This example
163/// doesn't make use of the [`Cursor`] methods from the [`Handle`].
164/// Those are methods that modify [`Selection`]s, and can use them to
165/// modify the [`Text`] in a declarative fashion. For an example with
166/// [`Cursor`]s, see the documentation for [`Handle`]s.
167///
168/// First, the [`Widget`] itself:
169///
170/// ```rust
171/// # use duat_core::text::Text;
172/// #[derive(Default)]
173/// struct Menu {
174///     text: Text,
175///     selected_entry: usize,
176///     active_etry: Option<usize>,
177/// }
178/// ```
179/// In this widget, the entries will be selectable via a [`Mode`], by
180/// pressing the up and down keys. Let's say that said menu has five
181/// entries, and one of them can be active at a time:
182///
183/// ```rust
184/// # #![feature(let_chains)]
185/// # use duat_core::prelude::*;
186/// # struct Menu {
187/// #     text: Text,
188/// #     selected_entry: usize,
189/// #     active_entry: Option<usize>,
190/// # }
191/// impl Menu {
192///     pub fn shift_selection(&mut self, shift: i32) {
193///         let selected = self.selected_entry as i32 + shift;
194///         self.selected_entry = if selected < 0 {
195///             4
196///         } else if selected > 4 {
197///             0
198///         } else {
199///             selected as usize
200///         };
201///     }
202///
203///     pub fn toggle(&mut self) {
204///         self.active_entry = match self.active_entry {
205///             Some(entry) if entry == self.selected_entry => None,
206///             Some(_) | None => Some(self.selected_entry),
207///         };
208///     }
209///
210///     fn build_text(&mut self) {
211///         let mut builder = Text::builder();
212///         builder.push(AlignCenter);
213///
214///         for i in 0..5 {
215///             if let Some(active) = self.active_entry
216///                 && active == i
217///             {
218///                 if self.selected_entry == i {
219///                     builder.push(form::id_of!("MenuSelActive"))
220///                 } else {
221///                     builder.push(form::id_of!("MenuActive"))
222///                 }
223///             } else if self.selected_entry == i {
224///                 builder.push(form::id_of!("MenuSelected"))
225///             }
226///
227///             builder.push(txt!("Entry {i}"));
228///         }
229///
230///         self.text = builder.build();
231///     }
232/// }
233/// ```
234///
235/// By making `shift_selection` and `toggle` `pub`, I can allow an end
236/// user to create their own [`Mode`] for this widget.
237///
238/// Now I'll implement [`Widget`]:
239///
240/// ```rust
241/// # #[derive(Default)]
242/// # struct Menu {
243/// #     text: Text,
244/// #     selected_entry: usize,
245/// #     active_entry: Option<usize>,
246/// # }
247/// # impl Menu {
248/// #     fn build_text(&mut self) { todo!(); }
249/// # }
250/// use duat_core::prelude::*;
251///
252/// struct MenuCfg;
253///
254/// impl<U: Ui> WidgetCfg<U> for MenuCfg {
255///     type Widget = Menu;
256///
257///     fn build(self, _: &mut Pass, _: BuildInfo<U>) -> (Menu, PushSpecs) {
258///         let mut widget = Menu::default();
259///         widget.build_text();
260///
261///         let specs = PushSpecs::left().hor_len(10.0).ver_len(5.0);
262///
263///         (widget, specs)
264///     }
265/// }
266///
267/// impl<U: Ui> Widget<U> for Menu {
268///     type Cfg = MenuCfg;
269///
270///     fn update(_: &mut Pass, handle: &Handle<Self, U>) {}
271///
272///     fn needs_update(&self, _: &Pass) -> bool {
273///         false
274///     }
275///
276///     fn text(&self) -> &Text {
277///         &self.text
278///     }
279///
280///     fn text_mut(&mut self) -> &mut Text {
281///         &mut self.text
282///     }
283///
284///     fn cfg() -> Self::Cfg {
285///         MenuCfg
286///     }
287///
288///     fn once() -> Result<(), Text> {
289///         form::set_weak("menu.active", Form::blue());
290///         form::set_weak("menu.selected", "accent");
291///         form::set_weak("menu.selected.active", "menu.selected");
292///         Ok(())
293///     }
294/// }
295/// ```
296///
297/// One thing that you'll notice is the definition of
298/// [`Widget::needs_update`]. It can always return `false` because the
299/// `Menu` only needs to update after keys are sent, and sent keys
300/// automatically trigger [`Widget::update`].
301///
302/// Now, let's take a look at some [`Widget`] methods that are used
303/// when the [`Widget`] is supposed to be handled by [`Mode`]s. Those
304/// are the [`on_focus`] and [`on_unfocus`] methods:
305///
306/// ```rust
307/// # use duat_core::prelude::*;
308/// # #[derive(Default)]
309/// # struct Menu {
310/// #     text: Text,
311/// #     selected_entry: usize,
312/// #     active_entry: Option<usize>,
313/// # }
314/// # struct MenuCfg;
315/// # impl<U: Ui> WidgetCfg<U> for MenuCfg {
316/// #     type Widget = Menu;
317/// #     fn build(self, _: &mut Pass, _: BuildInfo<U>) -> (Menu, PushSpecs) { todo!() }
318/// # }
319/// impl<U: Ui> Widget<U> for Menu {
320/// #     type Cfg = MenuCfg;
321/// #     fn cfg() -> Self::Cfg { todo!() }
322/// #     fn text(&self) -> &Text { todo!() }
323/// #     fn text_mut(&mut self) -> &mut Text { todo!() }
324/// #     fn once() -> Result<(), Text> { Ok(()) }
325/// #     fn update(_: &mut Pass, _: &Handle<Self, U>) {}
326/// #     fn needs_update(&self, _: &Pass) -> bool { todo!(); }
327///     // ...
328///     fn on_focus(_: &mut Pass, handle: &Handle<Self, U>) {
329///         handle.set_mask("inactive");
330///     }
331///
332///     fn on_unfocus(_: &mut Pass, handle: &Handle<Self, U>) {
333///         handle.set_mask("inactive");
334///     }
335/// }
336/// ```
337///
338/// These methods can do work when the wiget is focused or unfocused.
339///
340/// In this case, I chose to replace the [`Form`]s with "inactive"
341/// variants, to visually show when the widget is not active. Also,
342/// the usage of [`form::set_weak`] means that if an end user used
343/// [`form::set`] on one of these [`Form`]s, that will be prioritized.
344///
345/// Do also note that [`on_focus`] and [`on_unfocus`] are optional
346/// methods, since a [`Widget`] doesn't necessarily need to change on
347/// focus/unfocus.
348///
349/// Now, all that is left to do is  the `MenuInput` [`Mode`]. We just
350/// need to create an empty struct and call the methods of the `Menu`:
351///
352/// ```rust
353/// # use duat_core::prelude::*;
354/// # #[derive(Default)]
355/// # struct Menu {
356/// #     text: Text,
357/// #     selected_entry: usize,
358/// #     active_entry: Option<usize>,
359/// # }
360/// # impl Menu {
361/// #     pub fn shift_selection(&mut self, shift: i32) {}
362/// #     pub fn toggle(&mut self) {}
363/// #     fn build_text(&mut self) {}
364/// # }
365/// # struct MenuCfg;
366/// # impl<U: Ui> WidgetCfg<U> for MenuCfg {
367/// #     type Widget = Menu;
368/// #     fn build(self, _: &mut Pass, _: BuildInfo<U>) -> (Menu, PushSpecs) { todo!() }
369/// # }
370/// # impl<U: Ui> Widget<U> for Menu {
371/// #     type Cfg = MenuCfg;
372/// #     fn cfg() -> Self::Cfg { todo!() }
373/// #     fn text(&self) -> &Text { todo!() }
374/// #     fn text_mut(&mut self) -> &mut Text { todo!() }
375/// #     fn once() -> Result<(), Text> { Ok(()) }
376/// #     fn update(_: &mut Pass, _: &Handle<Self, U>) {}
377/// #     fn needs_update(&self, _: &Pass) -> bool { todo!(); }
378/// # }
379/// #[derive(Clone)]
380/// struct MenuInput;
381///
382/// impl<U: Ui> Mode<U> for MenuInput {
383///     type Widget = Menu;
384///
385///     fn send_key(&mut self, pa: &mut Pass, key: KeyEvent, handle: Handle<Self::Widget, U>) {
386///         use KeyCode::*;
387///
388///         let menu = handle.write(pa);
389///         match key {
390///             key!(Down) => menu.shift_selection(1),
391///             key!(Up) => menu.shift_selection(-1),
392///             key!(Enter | Tab | Char(' ')) => menu.toggle(),
393///             _ => {}
394///         }
395///     }
396/// }
397/// ```
398/// Notice the [`key!`] macro. This macro is useful for pattern
399/// matching [`KeyEvent`]s on [`Mode`]s.
400///
401/// [`Cursor`]: crate::mode::Cursor
402/// [`print`]: Widget::print
403/// [`on_focus`]: Widget::on_focus
404/// [`on_unfocus`]: Widget::on_unfocus
405/// [resizing]: crate::ui::Area::constrain_ver
406/// [`Form`]: crate::form::Form
407/// [`duat-kak`]: https://docs.rs/duat-kak/latest/duat_kak/index.html
408/// [`form::set_weak`]: crate::form::set_weak
409/// [`form::set`]: crate::form::set
410/// [Kakoune]: https://github.com/mawww/kakoune
411/// [`Text`]: crate::Text
412/// [`&mut Selections`]: Selections
413#[allow(unused_variables)]
414pub trait Mode<U: Ui>: Sized + Clone + Send + 'static {
415    /// The [`Widget`] that this [`Mode`] controls
416    type Widget: Widget<U>;
417
418    /// Sends a [`KeyEvent`] to this [`Mode`]
419    fn send_key(&mut self, pa: &mut Pass, key: KeyEvent, handle: Handle<Self::Widget, U>);
420
421    /// A function to trigger after switching to this [`Mode`]
422    ///
423    /// This can be some initial setup, like adding [`Tag`]s to the
424    /// [`Text`] in order to show some important visual help for that
425    /// specific [`Mode`].
426    ///
427    /// [`Tag`]: crate::text::Tag
428    /// [`Text`]: crate::text::Text
429    fn on_switch(&mut self, pa: &mut Pass, handle: Handle<Self::Widget, U>) {}
430
431    /// A function to trigger before switching off this [`Mode`]
432    ///
433    /// This can be some final cleanup like removing the [`Text`]
434    /// entirely, for example.
435    ///
436    /// You might think "Wait, can't I just do these things before
437    /// calling [`mode::set`] or [`mode::reset`]?". Yeah, you could,
438    /// but these functions can fail, so you would do cleanup without
439    /// actually leaving the [`Mode`]. [`before_exit`] _only_ triggers
440    /// if the switch was actually successful.
441    ///
442    /// [`Text`]: crate::text::Text
443    /// [`mode::set`]: set
444    /// [`mode::reset`]: reset
445    /// [`before_exit`]: Mode::before_exit
446    fn before_exit(&mut self, pa: &mut Pass, handle: Handle<Self::Widget, U>) {}
447
448    /// DO NOT IMPLEMENT THIS FUNCTION, IT IS MEANT FOR `&str` ONLY
449    #[doc(hidden)]
450    fn just_keys(&self) -> Option<&str> {
451        None
452    }
453}
454
455// This implementation exists only to allow &strs to be passed to
456// remaps.
457impl<U: Ui> Mode<U> for &'static str {
458    // Doesn't matter
459    type Widget = File<U>;
460
461    fn send_key(&mut self, _: &mut Pass, _: KeyEvent, _: Handle<Self::Widget, U>) {
462        unreachable!("&strs are only meant to be sent as AsGives, turning into keys");
463    }
464
465    fn just_keys(&self) -> Option<&str> {
466        Some(self)
467    }
468}
469
470/// This is a macro for matching keys in patterns:
471///
472/// Use this for quickly matching a [`KeyEvent`], probably inside an
473/// [`Mode`]:
474///
475/// ```rust
476/// # use duat_core::mode::{KeyEvent, KeyCode, KeyMod, key};
477/// # fn test(key: KeyEvent) {
478/// if let key!(KeyCode::Char('o'), KeyMod::NONE) = key { /* Code */ }
479/// // as opposed to
480/// if let KeyEvent {
481///     code: KeyCode::Char('c'),
482///     modifiers: KeyMod::NONE,
483///     ..
484/// } = key
485/// { /* Code */ }
486/// # }
487/// ```
488///
489/// You can also assign while matching:
490///
491/// ```rust
492/// # use duat_core::mode::{KeyEvent, KeyCode, KeyMod, key};
493/// # fn test(key: KeyEvent) {
494/// if let key!(code, KeyMod::SHIFT | KeyMod::ALT) = key { /* Code */ }
495/// // as opposed to
496/// if let KeyEvent {
497///     code,
498///     modifiers: KeyMod::SHIFT | KeyMod::ALT,
499///     ..
500/// } = key
501/// { /* Code */ }
502/// # }
503/// ```
504pub macro key {
505    ($code:pat) => {
506        KeyEvent { code: $code, modifiers: KeyMod::NONE, .. }
507    },
508
509    ($code:pat, $modifiers:pat) => {
510        KeyEvent { code: $code, modifiers: $modifiers, .. }
511    }
512}
513
514/// Return the length of a strin in chars
515#[allow(dead_code)]
516#[doc(hidden)]
517pub const fn len_chars(s: &str) -> usize {
518    let mut i = 0;
519    let b = s.as_bytes();
520    let mut nchars = 0;
521    while i < b.len() {
522        if crate::text::utf8_char_width(b[i]) > 0 {
523            nchars += 1;
524        }
525        i += 1;
526    }
527    nchars
528}
529
530/// Maps each [`char`] in an `&str` to a [`KeyEvent`]
531#[allow(dead_code)]
532#[doc(hidden)]
533pub fn key_events<const LEN: usize>(str: &str, modif: KeyMod) -> [KeyEvent; LEN] {
534    let mut events = [KeyEvent::new(KeyCode::Esc, KeyMod::NONE); LEN];
535
536    for (event, char) in events.iter_mut().zip(str.chars()) {
537        *event = KeyEvent::new(KeyCode::Char(char), modif)
538    }
539
540    events
541}