renamed fern.rs back to main.rs
This commit is contained in:
@@ -24,4 +24,3 @@ pretty_assertions = "1.4.1"
|
|||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "fern"
|
name = "fern"
|
||||||
path = "src/fern.rs"
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
use std::mem::take;
|
|
||||||
use std::str::{Chars, FromStr};
|
use std::str::{Chars, FromStr};
|
||||||
|
|
||||||
use glob::Pattern;
|
use glob::Pattern;
|
||||||
@@ -68,11 +67,10 @@ impl Expander {
|
|||||||
pub fn expand(&mut self) -> ShResult<Vec<String>> {
|
pub fn expand(&mut self) -> ShResult<Vec<String>> {
|
||||||
let mut chars = self.raw.chars().peekable();
|
let mut chars = self.raw.chars().peekable();
|
||||||
self.raw = expand_raw(&mut chars)?;
|
self.raw = expand_raw(&mut chars)?;
|
||||||
if let Ok(glob_exp) = expand_glob(&self.raw) {
|
if let Ok(glob_exp) = expand_glob(&self.raw)
|
||||||
if !glob_exp.is_empty() {
|
&& !glob_exp.is_empty() {
|
||||||
self.raw = glob_exp;
|
self.raw = glob_exp;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(self.split_words())
|
Ok(self.split_words())
|
||||||
}
|
}
|
||||||
pub fn split_words(&mut self) -> Vec<String> {
|
pub fn split_words(&mut self) -> Vec<String> {
|
||||||
@@ -776,11 +774,10 @@ pub fn expand_proc_sub(raw: &str, is_input: bool) -> ShResult<String> {
|
|||||||
pub fn expand_cmd_sub(raw: &str) -> ShResult<String> {
|
pub fn expand_cmd_sub(raw: &str) -> ShResult<String> {
|
||||||
flog!(DEBUG, "in expand_cmd_sub");
|
flog!(DEBUG, "in expand_cmd_sub");
|
||||||
flog!(DEBUG, raw);
|
flog!(DEBUG, raw);
|
||||||
if raw.starts_with('(') && raw.ends_with(')') {
|
if raw.starts_with('(') && raw.ends_with(')')
|
||||||
if let Ok(output) = expand_arithmetic(raw) {
|
&& let Ok(output) = expand_arithmetic(raw) {
|
||||||
return Ok(output); // It's actually an arithmetic sub
|
return Ok(output); // It's actually an arithmetic sub
|
||||||
}
|
}
|
||||||
}
|
|
||||||
let (rpipe, wpipe) = IoMode::get_pipes();
|
let (rpipe, wpipe) = IoMode::get_pipes();
|
||||||
let cmd_sub_redir = Redir::new(wpipe, RedirType::Output);
|
let cmd_sub_redir = Redir::new(wpipe, RedirType::Output);
|
||||||
let cmd_sub_io_frame = IoFrame::from_redir(cmd_sub_redir);
|
let cmd_sub_io_frame = IoFrame::from_redir(cmd_sub_redir);
|
||||||
|
|||||||
@@ -507,6 +507,8 @@ impl Job {
|
|||||||
flog!(TRACE, "waiting on children");
|
flog!(TRACE, "waiting on children");
|
||||||
flog!(TRACE, self.children);
|
flog!(TRACE, self.children);
|
||||||
for child in self.children.iter_mut() {
|
for child in self.children.iter_mut() {
|
||||||
|
flog!(TRACE, "shell pid {}", Pid::this());
|
||||||
|
flog!(TRACE, "child pid {}", child.pid);
|
||||||
if child.pid == Pid::this() {
|
if child.pid == Pid::this() {
|
||||||
// TODO: figure out some way to get the exit code of builtins
|
// TODO: figure out some way to get the exit code of builtins
|
||||||
let code = state::get_status();
|
let code = state::get_status();
|
||||||
|
|||||||
@@ -55,12 +55,12 @@ pub fn save_termios() {
|
|||||||
///This function is unsafe because it accesses a public mutable static value.
|
///This function is unsafe because it accesses a public mutable static value.
|
||||||
/// This function should only ever be called after save_termios() has already
|
/// This function should only ever be called after save_termios() has already
|
||||||
/// been called.
|
/// been called.
|
||||||
pub unsafe fn get_saved_termios() -> Option<Termios> {
|
pub unsafe fn get_saved_termios() -> Option<Termios> { unsafe {
|
||||||
// SAVED_TERMIOS should *only ever* be set once and accessed once
|
// SAVED_TERMIOS should *only ever* be set once and accessed once
|
||||||
// Set at the start of the program, and accessed during the exit of the program
|
// Set at the start of the program, and accessed during the exit of the program
|
||||||
// to reset the termios. Do not use this variable anywhere else
|
// to reset the termios. Do not use this variable anywhere else
|
||||||
SAVED_TERMIOS.clone().flatten()
|
SAVED_TERMIOS.clone().flatten()
|
||||||
}
|
}}
|
||||||
|
|
||||||
/// Set termios to not echo control characters, like ^Z for instance
|
/// Set termios to not echo control characters, like ^Z for instance
|
||||||
pub fn set_termios() {
|
pub fn set_termios() {
|
||||||
|
|||||||
@@ -118,12 +118,7 @@ impl ExecArgs {
|
|||||||
|
|
||||||
pub fn exec_input(input: String, io_stack: Option<IoStack>) -> ShResult<()> {
|
pub fn exec_input(input: String, io_stack: Option<IoStack>) -> ShResult<()> {
|
||||||
write_meta(|m| m.start_timer());
|
write_meta(|m| m.start_timer());
|
||||||
let log_tab = {
|
let log_tab = read_logic(|l| l.clone());
|
||||||
let fern = FERN.read().unwrap();
|
|
||||||
// TODO: Is there a better way to do this?
|
|
||||||
// The goal is mainly to not be holding a lock while executing input
|
|
||||||
fern.read_logic().clone()
|
|
||||||
};
|
|
||||||
let input = expand_aliases(input, HashSet::new(), &log_tab);
|
let input = expand_aliases(input, HashSet::new(), &log_tab);
|
||||||
let mut parser = ParsedSrc::new(Arc::new(input));
|
let mut parser = ParsedSrc::new(Arc::new(input));
|
||||||
if let Err(errors) = parser.parse_src() {
|
if let Err(errors) = parser.parse_src() {
|
||||||
|
|||||||
@@ -317,17 +317,16 @@ impl LexStream {
|
|||||||
let slice = self.slice_from_cursor().unwrap().to_string();
|
let slice = self.slice_from_cursor().unwrap().to_string();
|
||||||
let mut pos = self.cursor;
|
let mut pos = self.cursor;
|
||||||
let mut chars = slice.chars().peekable();
|
let mut chars = slice.chars().peekable();
|
||||||
let mut can_be_subshell = chars.peek() == Some(&'(');
|
let can_be_subshell = chars.peek() == Some(&'(');
|
||||||
|
|
||||||
if self.flags.contains(LexFlags::IN_CASE) {
|
if self.flags.contains(LexFlags::IN_CASE)
|
||||||
if let Some(count) = case_pat_lookahead(chars.clone()) {
|
&& let Some(count) = case_pat_lookahead(chars.clone()) {
|
||||||
pos += count;
|
pos += count;
|
||||||
let casepat_tk = self.get_token(self.cursor..pos, TkRule::CasePattern);
|
let casepat_tk = self.get_token(self.cursor..pos, TkRule::CasePattern);
|
||||||
self.cursor = pos;
|
self.cursor = pos;
|
||||||
self.set_next_is_cmd(true);
|
self.set_next_is_cmd(true);
|
||||||
return Ok(casepat_tk);
|
return Ok(casepat_tk);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(ch) = chars.next() {
|
while let Some(ch) = chars.next() {
|
||||||
match ch {
|
match ch {
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
pub mod highlight;
|
pub mod highlight;
|
||||||
pub mod readline;
|
pub mod readline;
|
||||||
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use readline::{FernVi, Readline};
|
use readline::{FernVi, Readline};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
expand::expand_prompt, libsh::error::ShResult, prelude::*, shopt::FernEditMode,
|
expand::expand_prompt, libsh::error::ShResult, prelude::*, shopt::FernEditMode,
|
||||||
state::read_shopts,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Initialize the line editor
|
/// Initialize the line editor
|
||||||
@@ -32,7 +30,7 @@ pub fn readline(edit_mode: FernEditMode, initial: Option<&str>) -> ShResult<Stri
|
|||||||
FernEditMode::Vi => {
|
FernEditMode::Vi => {
|
||||||
let mut fern_vi = FernVi::new(Some(prompt))?;
|
let mut fern_vi = FernVi::new(Some(prompt))?;
|
||||||
if let Some(input) = initial {
|
if let Some(input) = initial {
|
||||||
fern_vi = fern_vi.with_initial(&input)
|
fern_vi = fern_vi.with_initial(input)
|
||||||
}
|
}
|
||||||
Box::new(fern_vi) as Box<dyn Readline>
|
Box::new(fern_vi) as Box<dyn Readline>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -953,11 +953,10 @@ impl LineBuf {
|
|||||||
}
|
}
|
||||||
let start = start.unwrap_or(0);
|
let start = start.unwrap_or(0);
|
||||||
|
|
||||||
if count > 1 {
|
if count > 1
|
||||||
if let Some((_, new_end)) = self.text_obj_sentence(end, count - 1, bound) {
|
&& let Some((_, new_end)) = self.text_obj_sentence(end, count - 1, bound) {
|
||||||
end = new_end;
|
end = new_end;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Some((start, end))
|
Some((start, end))
|
||||||
}
|
}
|
||||||
@@ -2590,8 +2589,8 @@ impl LineBuf {
|
|||||||
self.cursor.add(content.len().saturating_sub(1));
|
self.cursor.add(content.len().saturating_sub(1));
|
||||||
}
|
}
|
||||||
Verb::SwapVisualAnchor => {
|
Verb::SwapVisualAnchor => {
|
||||||
if let Some((start, end)) = self.select_range() {
|
if let Some((start, end)) = self.select_range()
|
||||||
if let Some(mut mode) = self.select_mode {
|
&& let Some(mut mode) = self.select_mode {
|
||||||
mode.invert_anchor();
|
mode.invert_anchor();
|
||||||
let new_cursor_pos = match mode.anchor() {
|
let new_cursor_pos = match mode.anchor() {
|
||||||
SelectAnchor::Start => start,
|
SelectAnchor::Start => start,
|
||||||
@@ -2600,7 +2599,6 @@ impl LineBuf {
|
|||||||
self.cursor.set(new_cursor_pos);
|
self.cursor.set(new_cursor_pos);
|
||||||
self.select_mode = Some(mode)
|
self.select_mode = Some(mode)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Verb::JoinLines => {
|
Verb::JoinLines => {
|
||||||
let start = self.start_of_line();
|
let start = self.start_of_line();
|
||||||
@@ -2748,11 +2746,10 @@ impl LineBuf {
|
|||||||
let edit_is_merging = self.undo_stack.last().is_some_and(|edit| edit.merging);
|
let edit_is_merging = self.undo_stack.last().is_some_and(|edit| edit.merging);
|
||||||
|
|
||||||
// Merge character inserts into one edit
|
// Merge character inserts into one edit
|
||||||
if edit_is_merging && cmd.verb.as_ref().is_none_or(|v| !v.1.is_char_insert()) {
|
if edit_is_merging && cmd.verb.as_ref().is_none_or(|v| !v.1.is_char_insert())
|
||||||
if let Some(edit) = self.undo_stack.last_mut() {
|
&& let Some(edit) = self.undo_stack.last_mut() {
|
||||||
edit.stop_merge();
|
edit.stop_merge();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let ViCmd {
|
let ViCmd {
|
||||||
register,
|
register,
|
||||||
@@ -2839,11 +2836,10 @@ impl LineBuf {
|
|||||||
self.saved_col = None;
|
self.saved_col = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_char_insert {
|
if is_char_insert
|
||||||
if let Some(edit) = self.undo_stack.last_mut() {
|
&& let Some(edit) = self.undo_stack.last_mut() {
|
||||||
edit.start_merge();
|
edit.start_merge();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use history::{History, SearchConstraint, SearchKind};
|
use history::History;
|
||||||
use keys::{KeyCode, KeyEvent, ModKeys};
|
use keys::{KeyCode, KeyEvent, ModKeys};
|
||||||
use linebuf::{LineBuf, SelectAnchor, SelectMode};
|
use linebuf::{LineBuf, SelectAnchor, SelectMode};
|
||||||
use nix::libc::STDOUT_FILENO;
|
use nix::libc::STDOUT_FILENO;
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ use std::{
|
|||||||
env,
|
env,
|
||||||
fmt::{Debug, Write},
|
fmt::{Debug, Write},
|
||||||
io::{BufRead, BufReader, Read},
|
io::{BufRead, BufReader, Read},
|
||||||
iter::Peekable,
|
|
||||||
os::fd::{AsFd, BorrowedFd, RawFd},
|
os::fd::{AsFd, BorrowedFd, RawFd},
|
||||||
str::Chars,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use nix::{
|
use nix::{
|
||||||
|
|||||||
@@ -161,15 +161,14 @@ impl ViCmd {
|
|||||||
}
|
}
|
||||||
/// If a ViCmd has a linewise motion, but no verb, we change it to charwise
|
/// If a ViCmd has a linewise motion, but no verb, we change it to charwise
|
||||||
pub fn alter_line_motion_if_no_verb(&mut self) {
|
pub fn alter_line_motion_if_no_verb(&mut self) {
|
||||||
if self.is_line_motion() && self.verb.is_none() {
|
if self.is_line_motion() && self.verb.is_none()
|
||||||
if let Some(motion) = self.motion.as_mut() {
|
&& let Some(motion) = self.motion.as_mut() {
|
||||||
match motion.1 {
|
match motion.1 {
|
||||||
Motion::LineUp => motion.1 = Motion::LineUpCharwise,
|
Motion::LineUp => motion.1 = Motion::LineUpCharwise,
|
||||||
Motion::LineDown => motion.1 = Motion::LineDownCharwise,
|
Motion::LineDown => motion.1 = Motion::LineDownCharwise,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn is_mode_transition(&self) -> bool {
|
pub fn is_mode_transition(&self) -> bool {
|
||||||
self.verb.as_ref().is_some_and(|v| {
|
self.verb.as_ref().is_some_and(|v| {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use nix::NixPath;
|
|||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
use super::keys::{KeyCode as K, KeyEvent as E, ModKeys as M};
|
use super::keys::{KeyCode as K, KeyEvent as E, ModKeys as M};
|
||||||
use super::linebuf::CharClass;
|
|
||||||
use super::vicmd::{
|
use super::vicmd::{
|
||||||
Anchor, Bound, CmdFlags, Dest, Direction, Motion, MotionCmd, RegisterName, TextObj, To, Verb,
|
Anchor, Bound, CmdFlags, Dest, Direction, Motion, MotionCmd, RegisterName, TextObj, To, Verb,
|
||||||
VerbCmd, ViCmd, Word,
|
VerbCmd, ViCmd, Word,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use nix::sys::signal::{SaFlags, SigAction, sigaction};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
jobs::{JobCmdFlags, JobID, take_term},
|
jobs::{JobCmdFlags, JobID, take_term},
|
||||||
libsh::{error::{ShErr, ShErrKind, ShResult}, sys::sh_quit},
|
libsh::error::{ShErr, ShErrKind, ShResult},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
state::{read_jobs, write_jobs},
|
state::{read_jobs, write_jobs},
|
||||||
};
|
};
|
||||||
@@ -249,8 +249,8 @@ pub fn child_exited(pid: Pid, status: WtStat) -> ShResult<()> {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}) {
|
})
|
||||||
if is_finished {
|
&& is_finished {
|
||||||
if is_fg {
|
if is_fg {
|
||||||
take_term()?;
|
take_term()?;
|
||||||
} else {
|
} else {
|
||||||
@@ -262,6 +262,5 @@ pub fn child_exited(pid: Pid, status: WtStat) -> ShResult<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
98
src/state.rs
98
src/state.rs
@@ -1,5 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, VecDeque}, fmt::Display, ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Deref}, str::FromStr, sync::{LazyLock, RwLock, RwLockReadGuard, RwLockWriteGuard}, time::Duration
|
cell::RefCell, collections::{HashMap, VecDeque}, fmt::Display, ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Deref}, str::FromStr, time::Duration
|
||||||
};
|
};
|
||||||
|
|
||||||
use nix::unistd::{gethostname, getppid, User};
|
use nix::unistd::{gethostname, getppid, User};
|
||||||
@@ -17,53 +17,23 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub struct Fern {
|
pub struct Fern {
|
||||||
pub jobs: JobTab,
|
pub jobs: RefCell<JobTab>,
|
||||||
pub var_scopes: ScopeStack,
|
pub var_scopes: RefCell<ScopeStack>,
|
||||||
pub meta: MetaTab,
|
pub meta: RefCell<MetaTab>,
|
||||||
pub logic: LogTab,
|
pub logic: RefCell<LogTab>,
|
||||||
pub shopts: ShOpts,
|
pub shopts: RefCell<ShOpts>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fern {
|
impl Fern {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
jobs: JobTab::new(),
|
jobs: RefCell::new(JobTab::new()),
|
||||||
var_scopes: ScopeStack::new(),
|
var_scopes: RefCell::new(ScopeStack::new()),
|
||||||
meta: MetaTab::new(),
|
meta: RefCell::new(MetaTab::new()),
|
||||||
logic: LogTab::new(),
|
logic: RefCell::new(LogTab::new()),
|
||||||
shopts: ShOpts::default(),
|
shopts: RefCell::new(ShOpts::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn write_jobs(&mut self) -> &mut JobTab {
|
|
||||||
&mut self.jobs
|
|
||||||
}
|
|
||||||
pub fn write_vars(&mut self) -> &mut ScopeStack {
|
|
||||||
&mut self.var_scopes
|
|
||||||
}
|
|
||||||
pub fn write_meta(&mut self) -> &mut MetaTab {
|
|
||||||
&mut self.meta
|
|
||||||
}
|
|
||||||
pub fn write_logic(&mut self) -> &mut LogTab {
|
|
||||||
&mut self.logic
|
|
||||||
}
|
|
||||||
pub fn write_shopts(&mut self) -> &mut ShOpts {
|
|
||||||
&mut self.shopts
|
|
||||||
}
|
|
||||||
pub fn read_jobs(&self) -> &JobTab {
|
|
||||||
&self.jobs
|
|
||||||
}
|
|
||||||
pub fn read_vars(&self) -> &ScopeStack {
|
|
||||||
&self.var_scopes
|
|
||||||
}
|
|
||||||
pub fn read_meta(&self) -> &MetaTab {
|
|
||||||
&self.meta
|
|
||||||
}
|
|
||||||
pub fn read_logic(&self) -> &LogTab {
|
|
||||||
&self.logic
|
|
||||||
}
|
|
||||||
pub fn read_shopts(&self) -> &ShOpts {
|
|
||||||
&self.shopts
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Fern {
|
impl Default for Fern {
|
||||||
@@ -257,7 +227,9 @@ impl ScopeStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static FERN: LazyLock<RwLock<Fern>> = LazyLock::new(|| RwLock::new(Fern::new()));
|
thread_local! {
|
||||||
|
pub static FERN: Fern = Fern::new();
|
||||||
|
}
|
||||||
|
|
||||||
/// A shell function
|
/// A shell function
|
||||||
///
|
///
|
||||||
@@ -721,69 +693,49 @@ impl MetaTab {
|
|||||||
|
|
||||||
/// Read from the job table
|
/// Read from the job table
|
||||||
pub fn read_jobs<T, F: FnOnce(&JobTab) -> T>(f: F) -> T {
|
pub fn read_jobs<T, F: FnOnce(&JobTab) -> T>(f: F) -> T {
|
||||||
let fern = FERN.read().unwrap();
|
FERN.with(|fern| f(&fern.jobs.borrow()))
|
||||||
let jobs = fern.read_jobs();
|
|
||||||
f(jobs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to the job table
|
/// Write to the job table
|
||||||
pub fn write_jobs<T, F: FnOnce(&mut JobTab) -> T>(f: F) -> T {
|
pub fn write_jobs<T, F: FnOnce(&mut JobTab) -> T>(f: F) -> T {
|
||||||
let mut fern = FERN.write().unwrap();
|
FERN.with(|fern| f(&mut fern.jobs.borrow_mut()))
|
||||||
let jobs = &mut fern.jobs;
|
|
||||||
f(jobs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read from the var scope stack
|
/// Read from the var scope stack
|
||||||
pub fn read_vars<T, F: FnOnce(&ScopeStack) -> T>(f: F) -> T {
|
pub fn read_vars<T, F: FnOnce(&ScopeStack) -> T>(f: F) -> T {
|
||||||
let fern = FERN.read().unwrap();
|
FERN.with(|fern| f(&fern.var_scopes.borrow()))
|
||||||
let vars = fern.read_vars();
|
|
||||||
f(vars)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to the variable table
|
/// Write to the variable table
|
||||||
pub fn write_vars<T, F: FnOnce(&mut ScopeStack) -> T>(f: F) -> T {
|
pub fn write_vars<T, F: FnOnce(&mut ScopeStack) -> T>(f: F) -> T {
|
||||||
let mut fern = FERN.write().unwrap();
|
FERN.with(|fern| f(&mut fern.var_scopes.borrow_mut()))
|
||||||
let vars = fern.write_vars();
|
|
||||||
f(vars)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_meta<T, F: FnOnce(&MetaTab) -> T>(f: F) -> T {
|
pub fn read_meta<T, F: FnOnce(&MetaTab) -> T>(f: F) -> T {
|
||||||
let fern = FERN.read().unwrap();
|
FERN.with(|fern| f(&fern.meta.borrow()))
|
||||||
let meta = fern.read_meta();
|
|
||||||
f(meta)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to the variable table
|
/// Write to the meta table
|
||||||
pub fn write_meta<T, F: FnOnce(&mut MetaTab) -> T>(f: F) -> T {
|
pub fn write_meta<T, F: FnOnce(&mut MetaTab) -> T>(f: F) -> T {
|
||||||
let mut fern = FERN.write().unwrap();
|
FERN.with(|fern| f(&mut fern.meta.borrow_mut()))
|
||||||
let meta = fern.write_meta();
|
|
||||||
f(meta)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read from the logic table
|
/// Read from the logic table
|
||||||
pub fn read_logic<T, F: FnOnce(&LogTab) -> T>(f: F) -> T {
|
pub fn read_logic<T, F: FnOnce(&LogTab) -> T>(f: F) -> T {
|
||||||
let fern = FERN.read().unwrap();
|
FERN.with(|fern| f(&fern.logic.borrow()))
|
||||||
let logic = fern.read_logic();
|
|
||||||
f(logic)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write to the logic table
|
/// Write to the logic table
|
||||||
pub fn write_logic<T, F: FnOnce(&mut LogTab) -> T>(f: F) -> T {
|
pub fn write_logic<T, F: FnOnce(&mut LogTab) -> T>(f: F) -> T {
|
||||||
let mut fern = FERN.write().unwrap();
|
FERN.with(|fern| f(&mut fern.logic.borrow_mut()))
|
||||||
let logic = &mut fern.logic;
|
|
||||||
f(logic)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_shopts<T, F: FnOnce(&ShOpts) -> T>(f: F) -> T {
|
pub fn read_shopts<T, F: FnOnce(&ShOpts) -> T>(f: F) -> T {
|
||||||
let fern = FERN.read().unwrap();
|
FERN.with(|fern| f(&fern.shopts.borrow()))
|
||||||
let shopts = fern.read_shopts();
|
|
||||||
f(shopts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_shopts<T, F: FnOnce(&mut ShOpts) -> T>(f: F) -> T {
|
pub fn write_shopts<T, F: FnOnce(&mut ShOpts) -> T>(f: F) -> T {
|
||||||
let mut fern = FERN.write().unwrap();
|
FERN.with(|fern| f(&mut fern.shopts.borrow_mut()))
|
||||||
let shopts = &mut fern.shopts;
|
|
||||||
f(shopts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn descend_scope(argv: Option<Vec<String>>) {
|
pub fn descend_scope(argv: Option<Vec<String>>) {
|
||||||
|
|||||||
Reference in New Issue
Block a user