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