Skip to content
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

[WIP] Documenting anathema #55

Merged
merged 16 commits into from
Aug 31, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions anathema-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ pub mod tui;
pub trait Backend {
fn size(&self) -> Size;

/// When [Backend::next_event] returns [Event::Stop], this function will be called to make sure the Backend wants anathema exit.
FishingHacks marked this conversation as resolved.
Show resolved Hide resolved
fn quit_test(&self, event: Event) -> bool;

fn next_event(&mut self, timeout: Duration) -> Option<Event>;

fn resize(&mut self, new_size: Size);

/// Paint the widgets
fn paint<'bp>(
&mut self,
element: &mut Element<'bp>,
Expand All @@ -28,9 +30,12 @@ pub trait Backend {
ignore_floats: bool,
);

/// Publish the changes to the Buffer to the Screen.
fn render(&mut self);

/// Clear the internal buffer entirely. This should not change the screen.
fn clear(&mut self);

/// Finalizes the backend. This is called when the runtime starts.
fn finalize(&mut self) {}
}
17 changes: 10 additions & 7 deletions anathema-backend/src/tui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,25 @@ pub struct TuiBackendBuilder {
}

impl TuiBackendBuilder {
/// Enable alt screen
/// Enable an alternative screen. When using this with stdout it means the output will not persist once the program exits. This won't apply until Runtime::run is called.
pub fn enable_alt_screen(mut self) -> Self {
self.enable_alt_screen = true;
self
}

/// Enable mouse support
/// Enable mouse support. This won't apply until Runtime::run is called.
pub fn enable_mouse(mut self) -> Self {
self.enable_mouse = true;
self
}

/// Enable raw mode
/// When raw mode is enabled, every key press is sent to the terminal. If raw mode is not enabled, the return key has to be pressed to send characters to the terminal. This won't apply until Runtime::run is called.
pub fn enable_raw_mode(mut self) -> Self {
self.enable_raw_mode = true;
self
}

/// Hide the cursor (not the mouse cursor)
/// Hide the text cursor. This won't apply until Runtime::run is called.
pub fn hide_cursor(mut self) -> Self {
self.hide_cursor = true;
self
Expand Down Expand Up @@ -171,6 +171,9 @@ impl Backend for TuiBackend {
}

fn finalize(&mut self) {
// This is to fix an issue with Windows cmd.exe
let _ = Screen::show_cursor(&mut self.output);

if self.hide_cursor {
// This is to fix an issue with Windows cmd.exe
let _ = Screen::show_cursor(&mut self.output);
Expand Down
10 changes: 8 additions & 2 deletions anathema-backend/src/tui/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ pub struct Screen {
impl Screen {
/// Hide the cursor
pub(super) fn hide_cursor(mut output: impl Write) -> Result<()> {
output.queue(cursor::Hide)?;
output.execute(cursor::Hide)?;
FishingHacks marked this conversation as resolved.
Show resolved Hide resolved
Ok(())
}

/// Show the cursor
pub(super) fn show_cursor(mut output: impl Write) -> Result<()> {
output.execute(cursor::Show)?;
FishingHacks marked this conversation as resolved.
Show resolved Hide resolved
Ok(())
}

Expand All @@ -33,7 +39,7 @@ impl Screen {

/// Enable mouse support
pub(super) fn enable_mouse(mut output: impl Write) -> Result<()> {
output.queue(EnableMouseCapture)?;
output.execute(EnableMouseCapture)?;
FishingHacks marked this conversation as resolved.
Show resolved Hide resolved
Ok(())
}

Expand Down
39 changes: 36 additions & 3 deletions anathema-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ use anathema_widgets::components::{
use anathema_widgets::layout::text::StringStorage;
use anathema_widgets::layout::{layout_widget, position_widget, Constraints, LayoutCtx, LayoutFilter, Viewport};
use anathema_widgets::{
eval_blueprint, try_resolve_future_values, update_tree, AttributeStorage, Components, EvalContext, Factory,
FloatingWidgets, Scope, WidgetKind, WidgetTree,
eval_blueprint, try_resolve_future_values, update_tree, AttributeStorage, Components, Elements, EvalContext,
Factory, FloatingWidgets, Scope, WidgetKind, WidgetTree,
};
use events::{EventCtx, EventHandler};
use notify::{recommended_watcher, Event, RecommendedWatcher, RecursiveMode, Watcher};
Expand All @@ -61,6 +61,9 @@ pub struct RuntimeBuilder<T> {
}

impl<T> RuntimeBuilder<T> {
/// Registers a [Component] with the runtime. This returns a unique [ComponentId] that can be used to send messages to the component.
/// A component can only be used once in a template, even if it wouldn't actually be displayed in the end.
/// If you want multiple occurrences, register it as a prototype instead, see [RuntimeBuilder::register_prototype], it is basically a drop-in replacement
pub fn register_component<C: Component + 'static>(
&mut self,
ident: impl Into<String>,
Expand All @@ -74,6 +77,10 @@ impl<T> RuntimeBuilder<T> {
Ok(id.into())
}

/// Registers a [Component] as a prototype with the [Runtime], which allows the usage of multiple instances of the component in the templates.
/// This is useful if for reuse of the component.
/// If you don't need that, consider using [RuntimeBuilder::register_component] or [RuntimeBuilder::register_default] instead.
/// Unlike when registering a component, this won't return a [ComponentId] because there's no meaningful way to express which component the message would go to.
FishingHacks marked this conversation as resolved.
Show resolved Hide resolved
pub fn register_prototype<FC, FS, C>(
&mut self,
ident: impl Into<String>,
Expand All @@ -92,6 +99,10 @@ impl<T> RuntimeBuilder<T> {
Ok(())
}

/// Registers a [Component] with the runtime. This returns a unique [ComponentId] that can be used to send messages to the component.
/// Uses the [Default::default] implementation for the [Component] and [Component::State].
/// A component can only be used once in a template, even if it wouldn't actually be displayed in the end.
/// If you want multiple occurrences, register it as a prototype instead, see [RuntimeBuilder::register_prototype], it is basically a drop-in replacement
pub fn register_default<C>(
&mut self,
ident: impl Into<String>,
Expand All @@ -108,6 +119,7 @@ impl<T> RuntimeBuilder<T> {
Ok(id.into())
}

/// Returns the Runtime [Emitter] to emit messages to components
pub fn emitter(&self) -> Emitter {
self.emitter.clone()
}
Expand Down Expand Up @@ -142,6 +154,8 @@ impl<T> RuntimeBuilder<T> {
Ok(watcher)
}

/// Builds the [Runtime]. This will remove the ability to add new components or prototypes.
/// Fails if compiling the [Document] or creating the file watcher fails.
pub fn finish(mut self) -> Result<Runtime<T>>
where
T: Backend,
Expand Down Expand Up @@ -245,6 +259,7 @@ where
Self::builder(document, backend)
}

/// Creates a [RuntimeBuilder] based on the [Document] and [Backend]. Hot Reloading is configured on the [Document]
pub fn builder(document: Document, backend: T) -> RuntimeBuilder<T> {
let mut factory = Factory::new();

Expand Down Expand Up @@ -308,6 +323,13 @@ where
return;
}

// use std::io::Write;
// let mut file = std::fs::OpenOptions::new()
// .append(true)
// .write(true)
// .open("/tmp/log.lol").unwrap();
// file.write(format!("{}\n", self.changes.len()).as_bytes()).unwrap();

let mut scope = Scope::new();
self.changes.drain().rev().for_each(|(sub, change)| {
sub.iter().for_each(|sub| {
Expand All @@ -332,6 +354,7 @@ where
});
}

/// Handles component messages for (ideally) at most half of a tick
fn handle_messages<'bp>(
&mut self,
fps_now: Instant,
Expand Down Expand Up @@ -387,6 +410,11 @@ where
}
}

/// 1 - Tries to build the first widget tree or throws an error
/// 2 - Selects the first [Component] and calls [Component::on_focus] on it
/// 3 - Repeatedly calls [Self::tick] until [REBUILD] is set to true or any error occured. Using the [Error::Stop], we exit the main loop.
/// 4 - Resets itself using [Self::reset]
/// 5 - Recursively calls [Self::internal_run]. Note: This does not free up the call stack. We should move this into a loop in [Self::run].
fn internal_run(&mut self) -> Result<()> {
let mut fps_now = Instant::now();
let sleep_micros = ((1.0 / self.fps as f64) * 1000.0 * 1000.0) as u128;
Expand Down Expand Up @@ -490,6 +518,11 @@ where
self.globals = globals;
}

/// Resets the Runtime:
/// - Throws away all futures, pending changes and value subscribers
/// - Reloads all components
/// - Moves all the components from the tree back to the registry.
/// - Recompiles the document
fn reset(&mut self, tree: WidgetTree<'_>, states: &mut States) -> Result<()> {
clear_all_futures();
clear_all_changes();
Expand All @@ -500,7 +533,7 @@ where
self.string_storage = StringStorage::new();

// The only way we can get here is if we break the loop
// as a result of the hot_reload triggering.
// as a result of the hot_reload triggering or when building the first tree fails.
self.document.reload_templates()?;

// move all components from the tree back to the registry.
Expand Down
3 changes: 3 additions & 0 deletions anathema-store/src/slab/generational.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ impl From<usize> for Gen {
/// A key is a combination of an index and a generation.
/// To access a value using a key the value at the given index
/// has to have a matching generation.
///
/// Bits 0..48: 48-bit key
/// Bits 48..64 are the 16-bit generation
#[derive(Copy, Clone, PartialEq, Hash, Eq)]
pub struct Key(u64);

Expand Down
2 changes: 1 addition & 1 deletion anathema-store/src/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl<T> Entry<T> {
}

/// Allocate memory but never free it until the entire `Stack` is dropped.
/// Items popped from the stack are marked as `Empty` so the memory is resused.
/// Items popped from the stack are marked as `Empty` so the memory is reused.
#[derive(Debug, Default)]
pub struct Stack<T> {
inner: Vec<Entry<T>>,
Expand Down