ad_editor/
lib.rs

1//! ad :: the adaptable editor
2#![warn(
3    clippy::complexity,
4    clippy::correctness,
5    clippy::style,
6    future_incompatible,
7    missing_debug_implementations,
8    // missing_docs,
9    rust_2018_idioms,
10    rustdoc::all,
11    clippy::undocumented_unsafe_blocks
12)]
13
14use libc::termios as Termios;
15use std::{
16    io::Stdout,
17    sync::{OnceLock, RwLock},
18};
19
20pub mod buffer;
21pub mod config;
22pub mod dot;
23pub mod editor;
24pub mod exec;
25pub mod fsys;
26pub mod ftype;
27pub mod input;
28pub mod key;
29pub mod log;
30pub mod mode;
31pub mod plumb;
32pub mod regex;
33pub mod system;
34pub mod term;
35pub mod trie;
36pub mod ui;
37pub mod util;
38pub mod ziplist;
39
40pub use buffer::GapBuffer;
41pub use config::Config;
42pub use editor::{Editor, EditorMode};
43pub use exec::{CachedStdin, Edit, Program};
44pub use log::LogBuffer;
45pub use plumb::PlumbingRules;
46
47use term::{disable_alternate_screen, disable_mouse_support, set_termios};
48
49/// The environment variable to set to control logging within ad
50pub const LOG_LEVEL_ENV_VAR: &str = "AD_LOG";
51
52pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION");
53pub(crate) const UNNAMED_BUFFER: &str = "[No Name]";
54pub(crate) const MAX_NAME_LEN: usize = 40;
55
56pub(crate) static ORIGINAL_TERMIOS: OnceLock<Termios> = OnceLock::new();
57
58/// Global config values which are only ever updated from the main editor thread.
59/// This is handled as a static OnceLock rather than being a property on the
60/// Editor itself as it avoids having to thread the Config struct as a parameter
61/// through to everywhere that it is needed outside of the main Editor methods.
62pub(crate) static CONFIG: OnceLock<RwLock<Config>> = OnceLock::new();
63
64pub(crate) fn set_config(cfg: Config) {
65    _ = CONFIG.set(RwLock::new(cfg));
66}
67
68pub(crate) fn replace_config(cfg: Config) {
69    *CONFIG
70        .get_or_init(|| RwLock::new(Config::default()))
71        .write()
72        .unwrap() = cfg;
73}
74
75pub(crate) fn update_config(input: &str) -> Result<(), String> {
76    let mut guard = CONFIG
77        .get_or_init(|| RwLock::new(Config::default()))
78        .write()
79        .unwrap();
80
81    guard.update_from(input)
82}
83
84/// Get a read-only handle to the global Config data
85#[macro_export]
86macro_rules! config_handle {
87    () => {{
88        $crate::CONFIG
89            .get_or_init(|| std::sync::RwLock::new($crate::Config::default()))
90            .read()
91            .unwrap()
92    }};
93}
94
95/// Helper for panicing the program but first ensuring that we have restored the
96/// terminal state in the same way that we do when the Editor is dropped cleanly
97#[macro_export]
98macro_rules! die {
99    ($template:expr $(, $arg:expr)*) => {{
100        $crate::restore_terminal_state(&mut ::std::io::stdout());
101        panic!($template $(, $arg)*)
102    }};
103
104}
105
106/// Restore the terminal state to what we had originally before starting our UI.
107pub(crate) fn restore_terminal_state(so: &mut Stdout) {
108    disable_alternate_screen(so);
109    disable_mouse_support(so);
110    let t = match ORIGINAL_TERMIOS.get() {
111        Some(t) => t,
112        None => return,
113    };
114    set_termios(*t);
115}