status

Macro status 

Source
pub macro status($($parts:tt)*) {
    ...
}
Expand description

The macro that creates a StatusLine

This macro works like the txt! macro, in that Forms are pushed with [{FormName}]. However, txt! is evaluated immediately, while status! is evaluated when updates occur.

The macro will mostly read from the File widget and its related structs. In order to do that, it will accept functions as arguments. These functions take the following parameters:

Both of these can also have a second argument of type &Area. This will include the Widget’s Area when creating the status part. Additionally, you may include a first argument of type &Pass (e.g. fn(&Pass, &File), `fn(&Pass, &Widget, &Area), etc.), giving you non mutating access to global state.

Here’s some examples:

setup_duat!(setup);
use duat::prelude::*;

fn name_but_funky(file: &File) -> String {
    file.name()
        .chars()
        .enumerate()
        .map(|(i, char)| {
            if i % 2 == 1 {
                char.to_uppercase().to_string()
            } else {
                char.to_lowercase().to_string()
            }
        })
        .collect()
}

fn powerline_main_txt(file: &File, area: &Area) -> Text {
    let selections = file.selections();
    let cfg = file.print_cfg();
    let v_caret = selections
        .get_main()
        .unwrap()
        .v_caret(file.text(), area, cfg);

    txt!(
        "[separator][coord]{}[separator][coord]{}[separator][coord]{}",
        v_caret.visual_col(),
        v_caret.line(),
        file.len_lines()
    )
    .build()
}

fn setup() {
    hook::add::<WindowCreated>(|_, builder| {
        builder.push(status!("[file]{name_but_funky}[] {powerline_main_txt}"));
    });
}

Now, there are other types of arguments that you can also pass. They update differently from the previous ones. The previous arguments update when the File updates. The following types of arguments update independently or not at all:

  • A Text argument, which can be formatted in a similar way throught the txt! macro;
  • Any impl Display, such as numbers, strings, chars, etc. impl Debug types also work, when including the usual ":?" and derived suffixes;
  • RwData or DataMaps of the previous two types. These will update whenever the data inside is changed;
  • An (Fn(&Pass) -> Text/Display/Debug, Fn(&Pass) -> bool) tuple. The first function returns what will be shown, while the second function checks for updates, which will call the first function again;

Here’s an examples:

setup_duat!(setup);
use std::sync::atomic::{AtomicUsize, Ordering};

use duat::prelude::*;

fn setup() {
    let changing_str = RwData::new("Initial text".to_string());

    fn counter(update: bool) -> usize {
        static COUNT: AtomicUsize = AtomicUsize::new(0);
        if update {
            COUNT.fetch_add(1, Ordering::Relaxed) + 1
        } else {
            COUNT.load(Ordering::Relaxed)
        }
    }

    hook::add::<WindowCreated>({
        let changing_str = changing_str.clone();
        move |_, builder| {
            let changing_str = changing_str.clone();
            let checker = changing_str.checker();

            let text = txt!("Static text").build();

            let counter = move |_: &File| counter(checker());

            builder.push(status!("{changing_str} [counter]{counter}[] {text}",));
        }
    });

    cmd::add!("set-text", |pa, new: &str| {
        *changing_str.write(pa) = new.to_string();
        Ok(None)
    })
}

In the above example, I added some dynamic Text, through the usage of an RwData<Text>, I added some static Text, some Forms ("counter" and "default") and even a counter,.