htui 0.2.0

A terminal HTML/CSS renderer with an embedded JavaScript engine — build interactive TUIs from HTML, CSS and JS
//! Compile-time HTML / CSS / JS source loading with debug hot-reload paths.

use std::sync::Arc;

macro_rules! define_source {
    ($name:ident) => {
        /// A compile-time source loaded by the matching `include_*!` macro.
        #[derive(Debug, Clone, PartialEq, Eq)]
        pub struct $name {
            content: &'static str,
            path: Option<&'static str>,
        }

        impl $name {
            /// Create a source. `path` is supplied by debug macro expansion.
            pub const fn new(content: &'static str, path: Option<&'static str>) -> Self {
                Self { content, path }
            }

            /// Create source text without a hot-reload path.
            pub const fn inline(content: &'static str) -> Self {
                Self::new(content, None)
            }

            /// The embedded content.
            pub const fn as_str(&self) -> &'static str {
                self.content
            }

            /// The absolute source path in a debug build, or `None` in release.
            pub const fn path(&self) -> Option<&str> {
                self.path
            }
        }
    };
}

/// Source text shared between the runtime threads.
pub type SharedSourceText = Arc<str>;

define_source!(HtmlSource);
define_source!(CssSource);
define_source!(JsSource);

/// Shared expansion for all `include_*!` macros. In debug builds it embeds the
/// absolute source path; in release builds the path constant is removed.
#[doc(hidden)]
#[macro_export]
macro_rules! include_source {
    ($source:ident, $path:literal $(,)?) => {{
        const __HTUI_SOURCE: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/", $path));
        #[cfg(debug_assertions)]
        const __HTUI_SOURCE_PATH: Option<&str> =
            Some(concat!(env!("CARGO_MANIFEST_DIR"), "/", $path));
        #[cfg(not(debug_assertions))]
        const __HTUI_SOURCE_PATH: Option<&str> = None;
        $crate::$source::new(__HTUI_SOURCE, __HTUI_SOURCE_PATH)
    }};
}

/// Embed an HTML file and, in debug builds, remember its source path.
///
/// The path is relative to the current Cargo package root, not the invoking
/// source file.
#[macro_export]
macro_rules! include_html {
    ($path:literal $(,)?) => {
        $crate::include_source!(HtmlSource, $path)
    };
}

/// Embed a CSS file and, in debug builds, remember its source path.
#[macro_export]
macro_rules! include_css {
    ($path:literal $(,)?) => {
        $crate::include_source!(CssSource, $path)
    };
}

/// Embed a JS file and, in debug builds, remember its source path.
#[macro_export]
macro_rules! include_js {
    ($path:literal $(,)?) => {
        $crate::include_source!(JsSource, $path)
    };
}