renamed fern.rs back to main.rs

This commit is contained in:
2026-01-28 19:57:14 -05:00
parent ad0e4277cb
commit 7f3e1cfcee
15 changed files with 52 additions and 119 deletions

View File

@@ -24,4 +24,3 @@ pretty_assertions = "1.4.1"
[[bin]]
name = "fern"
path = "src/fern.rs"

View File

@@ -1,6 +1,5 @@
use std::collections::HashSet;
use std::iter::Peekable;
use std::mem::take;
use std::str::{Chars, FromStr};
use glob::Pattern;
@@ -68,11 +67,10 @@ impl Expander {
pub fn expand(&mut self) -> ShResult<Vec<String>> {
let mut chars = self.raw.chars().peekable();
self.raw = expand_raw(&mut chars)?;
if let Ok(glob_exp) = expand_glob(&self.raw) {
if !glob_exp.is_empty() {
if let Ok(glob_exp) = expand_glob(&self.raw)
&& !glob_exp.is_empty() {
self.raw = glob_exp;
}
}
Ok(self.split_words())
}
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> {
flog!(DEBUG, "in expand_cmd_sub");
flog!(DEBUG, raw);
if raw.starts_with('(') && raw.ends_with(')') {
if let Ok(output) = expand_arithmetic(raw) {
if raw.starts_with('(') && raw.ends_with(')')
&& let Ok(output) = expand_arithmetic(raw) {
return Ok(output); // It's actually an arithmetic sub
}
}
let (rpipe, wpipe) = IoMode::get_pipes();
let cmd_sub_redir = Redir::new(wpipe, RedirType::Output);
let cmd_sub_io_frame = IoFrame::from_redir(cmd_sub_redir);

View File

@@ -507,6 +507,8 @@ impl Job {
flog!(TRACE, "waiting on children");
flog!(TRACE, self.children);
for child in self.children.iter_mut() {
flog!(TRACE, "shell pid {}", Pid::this());
flog!(TRACE, "child pid {}", child.pid);
if child.pid == Pid::this() {
// TODO: figure out some way to get the exit code of builtins
let code = state::get_status();

View File

@@ -55,12 +55,12 @@ pub fn save_termios() {
///This function is unsafe because it accesses a public mutable static value.
/// This function should only ever be called after save_termios() has already
/// 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
// 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
SAVED_TERMIOS.clone().flatten()
}
}}
/// Set termios to not echo control characters, like ^Z for instance
pub fn set_termios() {

View File

@@ -118,12 +118,7 @@ impl ExecArgs {
pub fn exec_input(input: String, io_stack: Option<IoStack>) -> ShResult<()> {
write_meta(|m| m.start_timer());
let log_tab = {
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 log_tab = read_logic(|l| l.clone());
let input = expand_aliases(input, HashSet::new(), &log_tab);
let mut parser = ParsedSrc::new(Arc::new(input));
if let Err(errors) = parser.parse_src() {

View File

@@ -317,17 +317,16 @@ impl LexStream {
let slice = self.slice_from_cursor().unwrap().to_string();
let mut pos = self.cursor;
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 let Some(count) = case_pat_lookahead(chars.clone()) {
if self.flags.contains(LexFlags::IN_CASE)
&& let Some(count) = case_pat_lookahead(chars.clone()) {
pos += count;
let casepat_tk = self.get_token(self.cursor..pos, TkRule::CasePattern);
self.cursor = pos;
self.set_next_is_cmd(true);
return Ok(casepat_tk);
}
}
while let Some(ch) = chars.next() {
match ch {

View File

@@ -1,13 +1,11 @@
pub mod highlight;
pub mod readline;
use std::path::Path;
use readline::{FernVi, Readline};
use crate::{
expand::expand_prompt, libsh::error::ShResult, prelude::*, shopt::FernEditMode,
state::read_shopts,
};
/// Initialize the line editor
@@ -32,7 +30,7 @@ pub fn readline(edit_mode: FernEditMode, initial: Option<&str>) -> ShResult<Stri
FernEditMode::Vi => {
let mut fern_vi = FernVi::new(Some(prompt))?;
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>
}

View File

@@ -953,11 +953,10 @@ impl LineBuf {
}
let start = start.unwrap_or(0);
if count > 1 {
if let Some((_, new_end)) = self.text_obj_sentence(end, count - 1, bound) {
if count > 1
&& let Some((_, new_end)) = self.text_obj_sentence(end, count - 1, bound) {
end = new_end;
}
}
Some((start, end))
}
@@ -2590,8 +2589,8 @@ impl LineBuf {
self.cursor.add(content.len().saturating_sub(1));
}
Verb::SwapVisualAnchor => {
if let Some((start, end)) = self.select_range() {
if let Some(mut mode) = self.select_mode {
if let Some((start, end)) = self.select_range()
&& let Some(mut mode) = self.select_mode {
mode.invert_anchor();
let new_cursor_pos = match mode.anchor() {
SelectAnchor::Start => start,
@@ -2600,7 +2599,6 @@ impl LineBuf {
self.cursor.set(new_cursor_pos);
self.select_mode = Some(mode)
}
}
}
Verb::JoinLines => {
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);
// Merge character inserts into one edit
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() {
if edit_is_merging && cmd.verb.as_ref().is_none_or(|v| !v.1.is_char_insert())
&& let Some(edit) = self.undo_stack.last_mut() {
edit.stop_merge();
}
}
let ViCmd {
register,
@@ -2839,11 +2836,10 @@ impl LineBuf {
self.saved_col = None;
}
if is_char_insert {
if let Some(edit) = self.undo_stack.last_mut() {
if is_char_insert
&& let Some(edit) = self.undo_stack.last_mut() {
edit.start_merge();
}
}
Ok(())
}

View File

@@ -1,4 +1,4 @@
use history::{History, SearchConstraint, SearchKind};
use history::History;
use keys::{KeyCode, KeyEvent, ModKeys};
use linebuf::{LineBuf, SelectAnchor, SelectMode};
use nix::libc::STDOUT_FILENO;

View File

@@ -2,9 +2,7 @@ use std::{
env,
fmt::{Debug, Write},
io::{BufRead, BufReader, Read},
iter::Peekable,
os::fd::{AsFd, BorrowedFd, RawFd},
str::Chars,
};
use nix::{

View File

@@ -161,15 +161,14 @@ impl ViCmd {
}
/// 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) {
if self.is_line_motion() && self.verb.is_none() {
if let Some(motion) = self.motion.as_mut() {
if self.is_line_motion() && self.verb.is_none()
&& let Some(motion) = self.motion.as_mut() {
match motion.1 {
Motion::LineUp => motion.1 = Motion::LineUpCharwise,
Motion::LineDown => motion.1 = Motion::LineDownCharwise,
_ => unreachable!(),
}
}
}
}
pub fn is_mode_transition(&self) -> bool {
self.verb.as_ref().is_some_and(|v| {

View File

@@ -5,7 +5,6 @@ use nix::NixPath;
use unicode_segmentation::UnicodeSegmentation;
use super::keys::{KeyCode as K, KeyEvent as E, ModKeys as M};
use super::linebuf::CharClass;
use super::vicmd::{
Anchor, Bound, CmdFlags, Dest, Direction, Motion, MotionCmd, RegisterName, TextObj, To, Verb,
VerbCmd, ViCmd, Word,

View File

@@ -4,7 +4,7 @@ use nix::sys::signal::{SaFlags, SigAction, sigaction};
use crate::{
jobs::{JobCmdFlags, JobID, take_term},
libsh::{error::{ShErr, ShErrKind, ShResult}, sys::sh_quit},
libsh::error::{ShErr, ShErrKind, ShResult},
prelude::*,
state::{read_jobs, write_jobs},
};
@@ -249,8 +249,8 @@ pub fn child_exited(pid: Pid, status: WtStat) -> ShResult<()> {
} else {
None
}
}) {
if is_finished {
})
&& is_finished {
if is_fg {
take_term()?;
} else {
@@ -262,6 +262,5 @@ pub fn child_exited(pid: Pid, status: WtStat) -> ShResult<()> {
}
}
}
}
Ok(())
}

View File

@@ -1,5 +1,5 @@
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};
@@ -17,53 +17,23 @@ use crate::{
};
pub struct Fern {
pub jobs: JobTab,
pub var_scopes: ScopeStack,
pub meta: MetaTab,
pub logic: LogTab,
pub shopts: ShOpts,
pub jobs: RefCell<JobTab>,
pub var_scopes: RefCell<ScopeStack>,
pub meta: RefCell<MetaTab>,
pub logic: RefCell<LogTab>,
pub shopts: RefCell<ShOpts>,
}
impl Fern {
pub fn new() -> Self {
Self {
jobs: JobTab::new(),
var_scopes: ScopeStack::new(),
meta: MetaTab::new(),
logic: LogTab::new(),
shopts: ShOpts::default(),
jobs: RefCell::new(JobTab::new()),
var_scopes: RefCell::new(ScopeStack::new()),
meta: RefCell::new(MetaTab::new()),
logic: RefCell::new(LogTab::new()),
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 {
@@ -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
///
@@ -721,69 +693,49 @@ impl MetaTab {
/// Read from the job table
pub fn read_jobs<T, F: FnOnce(&JobTab) -> T>(f: F) -> T {
let fern = FERN.read().unwrap();
let jobs = fern.read_jobs();
f(jobs)
FERN.with(|fern| f(&fern.jobs.borrow()))
}
/// Write to the job table
pub fn write_jobs<T, F: FnOnce(&mut JobTab) -> T>(f: F) -> T {
let mut fern = FERN.write().unwrap();
let jobs = &mut fern.jobs;
f(jobs)
FERN.with(|fern| f(&mut fern.jobs.borrow_mut()))
}
/// Read from the var scope stack
pub fn read_vars<T, F: FnOnce(&ScopeStack) -> T>(f: F) -> T {
let fern = FERN.read().unwrap();
let vars = fern.read_vars();
f(vars)
FERN.with(|fern| f(&fern.var_scopes.borrow()))
}
/// Write to the variable table
pub fn write_vars<T, F: FnOnce(&mut ScopeStack) -> T>(f: F) -> T {
let mut fern = FERN.write().unwrap();
let vars = fern.write_vars();
f(vars)
FERN.with(|fern| f(&mut fern.var_scopes.borrow_mut()))
}
pub fn read_meta<T, F: FnOnce(&MetaTab) -> T>(f: F) -> T {
let fern = FERN.read().unwrap();
let meta = fern.read_meta();
f(meta)
FERN.with(|fern| f(&fern.meta.borrow()))
}
/// Write to the variable table
/// Write to the meta table
pub fn write_meta<T, F: FnOnce(&mut MetaTab) -> T>(f: F) -> T {
let mut fern = FERN.write().unwrap();
let meta = fern.write_meta();
f(meta)
FERN.with(|fern| f(&mut fern.meta.borrow_mut()))
}
/// Read from the logic table
pub fn read_logic<T, F: FnOnce(&LogTab) -> T>(f: F) -> T {
let fern = FERN.read().unwrap();
let logic = fern.read_logic();
f(logic)
FERN.with(|fern| f(&fern.logic.borrow()))
}
/// Write to the logic table
pub fn write_logic<T, F: FnOnce(&mut LogTab) -> T>(f: F) -> T {
let mut fern = FERN.write().unwrap();
let logic = &mut fern.logic;
f(logic)
FERN.with(|fern| f(&mut fern.logic.borrow_mut()))
}
pub fn read_shopts<T, F: FnOnce(&ShOpts) -> T>(f: F) -> T {
let fern = FERN.read().unwrap();
let shopts = fern.read_shopts();
f(shopts)
FERN.with(|fern| f(&fern.shopts.borrow()))
}
pub fn write_shopts<T, F: FnOnce(&mut ShOpts) -> T>(f: F) -> T {
let mut fern = FERN.write().unwrap();
let shopts = &mut fern.shopts;
f(shopts)
FERN.with(|fern| f(&mut fern.shopts.borrow_mut()))
}
pub fn descend_scope(argv: Option<Vec<String>>) {