pub mod config;
#[cfg(any(feature = "egui-backend", feature = "webview-backend"))]
pub mod icon;
pub mod image_validation;
#[cfg(feature = "webview-backend")]
pub mod markdown;
pub mod mermaid;
#[cfg(any(feature = "egui-backend", feature = "webview-backend"))]
pub mod net;
pub mod paths;
#[cfg(feature = "webview-backend")]
pub mod sanitize;
pub mod slug;
#[cfg(any(feature = "egui-backend", feature = "webview-backend"))]
pub mod style;
#[cfg(any(
feature = "egui-backend",
feature = "webview-backend",
feature = "tui-backend"
))]
pub mod svg;
pub mod toc;
pub mod watcher;
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
static VERBOSE: AtomicBool = AtomicBool::new(false);
pub fn set_verbose(v: bool) {
VERBOSE.store(v, Ordering::Relaxed);
}
pub fn verbose() -> bool {
VERBOSE.load(Ordering::Relaxed)
}
static OFFLINE: AtomicBool = AtomicBool::new(false);
pub fn set_offline(v: bool) {
OFFLINE.store(v, Ordering::Relaxed);
}
#[cfg(any(
feature = "egui-backend",
feature = "webview-backend",
feature = "tui-backend"
))]
pub fn offline() -> bool {
OFFLINE.load(Ordering::Relaxed)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Theme {
#[default]
Auto,
Dark,
Light,
}
impl Theme {
pub fn parse(s: &str) -> Option<Self> {
match s {
"auto" => Some(Self::Auto),
"dark" => Some(Self::Dark),
"light" => Some(Self::Light),
_ => None,
}
}
}
static THEME: AtomicU8 = AtomicU8::new(0);
pub fn set_theme(theme: Theme) {
THEME.store(
match theme {
Theme::Auto => 0,
Theme::Dark => 1,
Theme::Light => 2,
},
Ordering::Relaxed,
);
}
static DOCUMENT_BASE: std::sync::OnceLock<std::path::PathBuf> = std::sync::OnceLock::new();
pub fn set_document_base(dir: std::path::PathBuf) {
let _ = DOCUMENT_BASE.set(dir);
}
#[cfg(any(
feature = "egui-backend",
feature = "webview-backend",
feature = "tui-backend"
))]
pub fn document_base_dir(document: &std::path::Path) -> std::path::PathBuf {
base_dir_of(
document,
DOCUMENT_BASE.get().map(std::path::PathBuf::as_path),
)
}
#[cfg(any(
feature = "egui-backend",
feature = "webview-backend",
feature = "tui-backend",
test
))]
fn base_dir_of(
document: &std::path::Path,
override_dir: Option<&std::path::Path>,
) -> std::path::PathBuf {
if let Some(dir) = override_dir {
return dir.to_path_buf();
}
document.parent().map_or_else(
|| std::env::current_dir().unwrap_or_default(),
std::path::Path::to_path_buf,
)
}
pub fn theme() -> Theme {
match THEME.load(Ordering::Relaxed) {
1 => Theme::Dark,
2 => Theme::Light,
_ => Theme::Auto,
}
}
#[macro_export]
macro_rules! vlog {
($($arg:tt)*) => {
if $crate::core::verbose() {
eprintln!("[mdr] {}", format!($($arg)*));
}
};
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::{Path, PathBuf};
#[test]
fn a_document_resolves_relative_paths_next_to_itself() {
assert_eq!(
base_dir_of(Path::new("/home/me/project/README.md"), None),
PathBuf::from("/home/me/project")
);
}
#[test]
fn a_piped_document_resolves_them_where_mdr_was_run() {
assert_eq!(
base_dir_of(
Path::new("/var/folders/tmp/mdr/stdin-1234.md"),
Some(Path::new("/home/me/project")),
),
PathBuf::from("/home/me/project")
);
}
#[test]
fn a_document_with_no_parent_falls_back_to_the_working_directory() {
assert_eq!(
base_dir_of(Path::new("/"), None),
std::env::current_dir().unwrap_or_default()
);
}
}