rustfmt'd the codebase

This commit is contained in:
2026-03-04 19:52:29 -05:00
parent ecd6eda424
commit 7be79a3803
51 changed files with 4926 additions and 4131 deletions

View File

@@ -12,14 +12,30 @@ use nix::unistd::{User, gethostname, getppid};
use regex::Regex;
use crate::{
builtin::{BUILTINS, keymap::{KeyMap, KeyMapFlags, KeyMapMatch}, map::MapNode, trap::TrapTarget}, exec_input, expand::expand_keymap, jobs::JobTab, libsh::{
error::{ShErr, ShErrKind, ShResult}, utils::VecDequeExt
}, parse::{
builtin::{
BUILTINS,
keymap::{KeyMap, KeyMapFlags, KeyMapMatch},
map::MapNode,
trap::TrapTarget,
},
exec_input,
expand::expand_keymap,
jobs::JobTab,
libsh::{
error::{ShErr, ShErrKind, ShResult},
utils::VecDequeExt,
},
parse::{
ConjunctNode, NdRule, Node, ParsedSrc,
lex::{LexFlags, LexStream, Span, Tk},
}, prelude::*, readline::{
complete::{BashCompSpec, CompSpec}, keys::KeyEvent, markers
}, shopt::ShOpts
},
prelude::*,
readline::{
complete::{BashCompSpec, CompSpec},
keys::KeyEvent,
markers,
},
shopt::ShOpts,
};
pub struct Shed {
@@ -71,18 +87,18 @@ impl ShellParam {
)
}
pub fn from_char(c: &char) -> Option<Self> {
match c {
'?' => Some(Self::Status),
'$' => Some(Self::ShPid),
'!' => Some(Self::LastJob),
'0' => Some(Self::ShellName),
'@' => Some(Self::AllArgs),
'*' => Some(Self::AllArgsStr),
'#' => Some(Self::ArgCount),
_ => None,
}
}
pub fn from_char(c: &char) -> Option<Self> {
match c {
'?' => Some(Self::Status),
'$' => Some(Self::ShPid),
'!' => Some(Self::LastJob),
'0' => Some(Self::ShellName),
'@' => Some(Self::AllArgs),
'*' => Some(Self::AllArgsStr),
'#' => Some(Self::ArgCount),
_ => None,
}
}
}
impl Display for ShellParam {
@@ -299,10 +315,12 @@ impl ScopeStack {
{
match var.kind_mut() {
VarKind::Arr(items) => return Ok(items),
_ => return Err(ShErr::simple(
ShErrKind::ExecFail,
format!("Variable '{}' is not an array", var_name),
)),
_ => {
return Err(ShErr::simple(
ShErrKind::ExecFail,
format!("Variable '{}' is not an array", var_name),
));
}
}
}
}
@@ -358,38 +376,37 @@ impl ScopeStack {
}
Ok("".into())
}
pub fn remove_map(&mut self, map_name: &str) -> Option<MapNode> {
for scope in self.scopes.iter_mut().rev() {
if scope.get_map(map_name).is_some() {
return scope.remove_map(map_name);
}
}
None
}
pub fn get_map(&self, map_name: &str) -> Option<&MapNode> {
for scope in self.scopes.iter().rev() {
if let Some(map) = scope.get_map(map_name) {
return Some(map)
}
}
None
}
pub fn get_map_mut(&mut self, map_name: &str) -> Option<&mut MapNode> {
for scope in self.scopes.iter_mut().rev() {
if let Some(map) = scope.get_map_mut(map_name) {
return Some(map)
}
}
None
}
pub fn set_map(&mut self, map_name: &str, map: MapNode, local: bool) {
if local
&& let Some(scope) = self.scopes.last_mut() {
scope.set_map(map_name, map);
} else if let Some(scope) = self.scopes.first_mut() {
scope.set_map(map_name, map);
}
}
pub fn remove_map(&mut self, map_name: &str) -> Option<MapNode> {
for scope in self.scopes.iter_mut().rev() {
if scope.get_map(map_name).is_some() {
return scope.remove_map(map_name);
}
}
None
}
pub fn get_map(&self, map_name: &str) -> Option<&MapNode> {
for scope in self.scopes.iter().rev() {
if let Some(map) = scope.get_map(map_name) {
return Some(map);
}
}
None
}
pub fn get_map_mut(&mut self, map_name: &str) -> Option<&mut MapNode> {
for scope in self.scopes.iter_mut().rev() {
if let Some(map) = scope.get_map_mut(map_name) {
return Some(map);
}
}
None
}
pub fn set_map(&mut self, map_name: &str, map: MapNode, local: bool) {
if local && let Some(scope) = self.scopes.last_mut() {
scope.set_map(map_name, map);
} else if let Some(scope) = self.scopes.first_mut() {
scope.set_map(map_name, map);
}
}
pub fn try_get_var(&self, var_name: &str) -> Option<String> {
// This version of get_var() is mainly used internally
// so that we have access to Option methods
@@ -410,11 +427,11 @@ impl ScopeStack {
None
}
pub fn take_var(&mut self, var_name: &str) -> String {
let var = self.get_var(var_name);
self.unset_var(var_name).ok();
var
}
pub fn take_var(&mut self, var_name: &str) -> String {
let var = self.get_var(var_name);
self.unset_var(var_name).ok();
var
}
pub fn get_var(&self, var_name: &str) -> String {
if let Ok(param) = var_name.parse::<ShellParam>() {
return self.get_param(param);
@@ -480,14 +497,14 @@ thread_local! {
#[derive(Clone, Debug)]
pub struct ShAlias {
pub body: String,
pub source: Span
pub body: String,
pub source: Span,
}
impl Display for ShAlias {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.body)
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.body)
}
}
/// A shell function
@@ -495,14 +512,14 @@ impl Display for ShAlias {
/// Wraps the BraceGrp Node that forms the body of the function, and provides some helper methods to extract it from the parse tree
#[derive(Clone, Debug)]
pub struct ShFunc {
pub body: Node,
pub source: Span
pub body: Node,
pub source: Span,
}
impl ShFunc {
pub fn new(mut src: ParsedSrc, source: Span) -> Self {
let body = Self::extract_brc_grp_hack(src.extract_nodes());
Self{ body, source }
Self { body, source }
}
fn extract_brc_grp_hack(mut tree: Vec<Node>) -> Node {
// FIXME: find a better way to do this
@@ -524,61 +541,61 @@ impl ShFunc {
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum AutoCmdKind {
PreCmd,
PostCmd,
PreChangeDir,
PostChangeDir,
OnJobFinish,
PrePrompt,
PostPrompt,
PreModeChange,
PostModeChange,
OnExit
PreCmd,
PostCmd,
PreChangeDir,
PostChangeDir,
OnJobFinish,
PrePrompt,
PostPrompt,
PreModeChange,
PostModeChange,
OnExit,
}
impl Display for AutoCmdKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::PreCmd => write!(f, "pre-cmd"),
Self::PostCmd => write!(f, "post-cmd"),
Self::PreChangeDir => write!(f, "pre-change-dir"),
Self::PostChangeDir => write!(f, "post-change-dir"),
Self::OnJobFinish => write!(f, "on-job-finish"),
Self::PrePrompt => write!(f, "pre-prompt"),
Self::PostPrompt => write!(f, "post-prompt"),
Self::PreModeChange => write!(f, "pre-mode-change"),
Self::PostModeChange => write!(f, "post-mode-change"),
Self::OnExit => write!(f, "on-exit"),
}
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::PreCmd => write!(f, "pre-cmd"),
Self::PostCmd => write!(f, "post-cmd"),
Self::PreChangeDir => write!(f, "pre-change-dir"),
Self::PostChangeDir => write!(f, "post-change-dir"),
Self::OnJobFinish => write!(f, "on-job-finish"),
Self::PrePrompt => write!(f, "pre-prompt"),
Self::PostPrompt => write!(f, "post-prompt"),
Self::PreModeChange => write!(f, "pre-mode-change"),
Self::PostModeChange => write!(f, "post-mode-change"),
Self::OnExit => write!(f, "on-exit"),
}
}
}
impl FromStr for AutoCmdKind {
type Err = ShErr;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"pre-cmd" => Ok(Self::PreCmd),
"post-cmd" => Ok(Self::PostCmd),
"pre-change-dir" => Ok(Self::PreChangeDir),
"post-change-dir" => Ok(Self::PostChangeDir),
"on-job-finish" => Ok(Self::OnJobFinish),
"pre-prompt" => Ok(Self::PrePrompt),
"post-prompt" => Ok(Self::PostPrompt),
"pre-mode-change" => Ok(Self::PreModeChange),
"post-mode-change" => Ok(Self::PostModeChange),
"on-exit" => Ok(Self::OnExit),
_ => Err(ShErr::simple(
ShErrKind::ParseErr,
format!("Invalid autocmd kind: {}", s),
)),
}
}
type Err = ShErr;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"pre-cmd" => Ok(Self::PreCmd),
"post-cmd" => Ok(Self::PostCmd),
"pre-change-dir" => Ok(Self::PreChangeDir),
"post-change-dir" => Ok(Self::PostChangeDir),
"on-job-finish" => Ok(Self::OnJobFinish),
"pre-prompt" => Ok(Self::PrePrompt),
"post-prompt" => Ok(Self::PostPrompt),
"pre-mode-change" => Ok(Self::PreModeChange),
"post-mode-change" => Ok(Self::PostModeChange),
"on-exit" => Ok(Self::OnExit),
_ => Err(ShErr::simple(
ShErrKind::ParseErr,
format!("Invalid autocmd kind: {}", s),
)),
}
}
}
#[derive(Clone, Debug)]
pub struct AutoCmd {
pub pattern: Option<Regex>,
pub command: String,
pub pattern: Option<Regex>,
pub command: String,
}
/// The logic table for the shell
@@ -589,58 +606,59 @@ pub struct LogTab {
functions: HashMap<String, ShFunc>,
aliases: HashMap<String, ShAlias>,
traps: HashMap<TrapTarget, String>,
keymaps: Vec<KeyMap>,
autocmds: HashMap<AutoCmdKind, Vec<AutoCmd>>
keymaps: Vec<KeyMap>,
autocmds: HashMap<AutoCmdKind, Vec<AutoCmd>>,
}
impl LogTab {
pub fn new() -> Self {
Self::default()
}
pub fn autocmds(&self) -> &HashMap<AutoCmdKind, Vec<AutoCmd>> {
&self.autocmds
}
pub fn autocmds_mut(&mut self) -> &mut HashMap<AutoCmdKind, Vec<AutoCmd>> {
&mut self.autocmds
}
pub fn insert_autocmd(&mut self, kind: AutoCmdKind, cmd: AutoCmd) {
self.autocmds.entry(kind).or_default().push(cmd);
}
pub fn get_autocmds(&self, kind: AutoCmdKind) -> Vec<AutoCmd> {
self.autocmds.get(&kind).cloned().unwrap_or_default()
}
pub fn clear_autocmds(&mut self, kind: AutoCmdKind) {
self.autocmds.remove(&kind);
}
pub fn keymaps(&self) -> &Vec<KeyMap> {
&self.keymaps
}
pub fn keymaps_mut(&mut self) -> &mut Vec<KeyMap> {
&mut self.keymaps
}
pub fn insert_keymap(&mut self, keymap: KeyMap) {
let mut found_dup = false;
for map in self.keymaps.iter_mut() {
if map.keys == keymap.keys {
*map = keymap.clone();
found_dup = true;
break;
}
}
if !found_dup {
self.keymaps.push(keymap);
}
}
pub fn remove_keymap(&mut self, keys: &str) {
self.keymaps.retain(|km| km.keys != keys);
}
pub fn keymaps_filtered(&self, flags: KeyMapFlags, pending: &[KeyEvent]) -> Vec<KeyMap> {
self.keymaps
.iter()
.filter(|km| km.flags.intersects(flags) && km.compare(pending) != KeyMapMatch::NoMatch)
.cloned()
.collect()
}
pub fn autocmds(&self) -> &HashMap<AutoCmdKind, Vec<AutoCmd>> {
&self.autocmds
}
pub fn autocmds_mut(&mut self) -> &mut HashMap<AutoCmdKind, Vec<AutoCmd>> {
&mut self.autocmds
}
pub fn insert_autocmd(&mut self, kind: AutoCmdKind, cmd: AutoCmd) {
self.autocmds.entry(kind).or_default().push(cmd);
}
pub fn get_autocmds(&self, kind: AutoCmdKind) -> Vec<AutoCmd> {
self.autocmds.get(&kind).cloned().unwrap_or_default()
}
pub fn clear_autocmds(&mut self, kind: AutoCmdKind) {
self.autocmds.remove(&kind);
}
pub fn keymaps(&self) -> &Vec<KeyMap> {
&self.keymaps
}
pub fn keymaps_mut(&mut self) -> &mut Vec<KeyMap> {
&mut self.keymaps
}
pub fn insert_keymap(&mut self, keymap: KeyMap) {
let mut found_dup = false;
for map in self.keymaps.iter_mut() {
if map.keys == keymap.keys {
*map = keymap.clone();
found_dup = true;
break;
}
}
if !found_dup {
self.keymaps.push(keymap);
}
}
pub fn remove_keymap(&mut self, keys: &str) {
self.keymaps.retain(|km| km.keys != keys);
}
pub fn keymaps_filtered(&self, flags: KeyMapFlags, pending: &[KeyEvent]) -> Vec<KeyMap> {
self
.keymaps
.iter()
.filter(|km| km.flags.intersects(flags) && km.compare(pending) != KeyMapMatch::NoMatch)
.cloned()
.collect()
}
pub fn insert_func(&mut self, name: &str, src: ShFunc) {
self.functions.insert(name.into(), src);
}
@@ -666,7 +684,13 @@ impl LogTab {
&self.aliases
}
pub fn insert_alias(&mut self, name: &str, body: &str, source: Span) {
self.aliases.insert(name.into(), ShAlias { body: body.into(), source });
self.aliases.insert(
name.into(),
ShAlias {
body: body.into(),
source,
},
);
}
pub fn get_alias(&self, name: &str) -> Option<ShAlias> {
self.aliases.get(name).cloned()
@@ -751,7 +775,7 @@ impl VarFlags {
pub enum ArrIndex {
Literal(usize),
FromBack(usize),
ArgCount,
ArgCount,
AllJoined,
AllSplit,
}
@@ -762,7 +786,7 @@ impl FromStr for ArrIndex {
match s {
"@" => Ok(Self::AllSplit),
"*" => Ok(Self::AllJoined),
"#" => Ok(Self::ArgCount),
"#" => Ok(Self::ArgCount),
_ if s.starts_with('-') && s[1..].chars().all(|c| c.is_digit(1)) => {
let idx = s[1..].parse::<usize>().unwrap();
Ok(Self::FromBack(idx))
@@ -879,15 +903,15 @@ impl Display for Var {
}
impl From<String> for Var {
fn from(value: String) -> Self {
Self::new(VarKind::Str(value), VarFlags::NONE)
}
fn from(value: String) -> Self {
Self::new(VarKind::Str(value), VarFlags::NONE)
}
}
impl From<&str> for Var {
fn from(value: &str) -> Self {
Self::new(VarKind::Str(value.into()), VarFlags::NONE)
}
fn from(value: &str) -> Self {
Self::new(VarKind::Str(value.into()), VarFlags::NONE)
}
}
#[derive(Default, Clone, Debug)]
@@ -896,7 +920,7 @@ pub struct VarTab {
params: HashMap<ShellParam, String>,
sh_argv: VecDeque<String>, /* Using a VecDeque makes the implementation of `shift` straightforward */
maps: HashMap<String, MapNode>
maps: HashMap<String, MapNode>,
}
impl VarTab {
@@ -908,7 +932,7 @@ impl VarTab {
vars,
params,
sh_argv: VecDeque::new(),
maps: HashMap::new(),
maps: HashMap::new(),
};
var_tab.init_sh_argv();
var_tab
@@ -1027,24 +1051,24 @@ impl VarTab {
self.update_arg_params();
arg
}
pub fn set_map(&mut self, map_name: &str, map: MapNode) {
self.maps.insert(map_name.to_string(), map);
}
pub fn remove_map(&mut self, map_name: &str) -> Option<MapNode> {
self.maps.remove(map_name)
}
pub fn get_map(&self, map_name: &str) -> Option<&MapNode> {
self.maps.get(map_name)
}
pub fn get_map_mut(&mut self, map_name: &str) -> Option<&mut MapNode> {
self.maps.get_mut(map_name)
}
pub fn maps(&self) -> &HashMap<String, MapNode> {
&self.maps
}
pub fn maps_mut(&mut self) -> &mut HashMap<String, MapNode> {
&mut self.maps
}
pub fn set_map(&mut self, map_name: &str, map: MapNode) {
self.maps.insert(map_name.to_string(), map);
}
pub fn remove_map(&mut self, map_name: &str) -> Option<MapNode> {
self.maps.remove(map_name)
}
pub fn get_map(&self, map_name: &str) -> Option<&MapNode> {
self.maps.get(map_name)
}
pub fn get_map_mut(&mut self, map_name: &str) -> Option<&mut MapNode> {
self.maps.get_mut(map_name)
}
pub fn maps(&self) -> &HashMap<String, MapNode> {
&self.maps
}
pub fn maps_mut(&mut self) -> &mut HashMap<String, MapNode> {
&mut self.maps
}
pub fn vars(&self) -> &HashMap<String, Var> {
&self.vars
}
@@ -1160,9 +1184,9 @@ impl VarTab {
}
Ok(())
}
pub fn map_exists(&self, map_name: &str) -> bool {
self.maps.contains_key(map_name)
}
pub fn map_exists(&self, map_name: &str) -> bool {
self.maps.contains_key(map_name)
}
pub fn var_exists(&self, var_name: &str) -> bool {
if let Ok(param) = var_name.parse::<ShellParam>() {
return self.params.contains_key(&param);
@@ -1205,8 +1229,8 @@ pub struct MetaTab {
// pushd/popd stack
dir_stack: VecDeque<PathBuf>,
// getopts char offset for opts like -abc
getopts_offset: usize,
// getopts char offset for opts like -abc
getopts_offset: usize,
old_path: Option<String>,
old_pwd: Option<String>,
@@ -1216,8 +1240,8 @@ pub struct MetaTab {
// programmable completion specs
comp_specs: HashMap<String, Box<dyn CompSpec>>,
// pending keys from widget function
pending_widget_keys: Vec<KeyEvent>
// pending keys from widget function
pending_widget_keys: Vec<KeyEvent>,
}
impl MetaTab {
@@ -1227,28 +1251,28 @@ impl MetaTab {
..Default::default()
}
}
pub fn set_pending_widget_keys(&mut self, keys: &str) {
let exp = expand_keymap(keys);
self.pending_widget_keys = exp;
}
pub fn take_pending_widget_keys(&mut self) -> Option<Vec<KeyEvent>> {
if self.pending_widget_keys.is_empty() {
None
} else {
Some(std::mem::take(&mut self.pending_widget_keys))
}
}
pub fn getopts_char_offset(&self) -> usize {
self.getopts_offset
}
pub fn inc_getopts_char_offset(&mut self) -> usize {
let offset = self.getopts_offset;
self.getopts_offset += 1;
offset
}
pub fn reset_getopts_char_offset(&mut self) {
self.getopts_offset = 0;
}
pub fn set_pending_widget_keys(&mut self, keys: &str) {
let exp = expand_keymap(keys);
self.pending_widget_keys = exp;
}
pub fn take_pending_widget_keys(&mut self) -> Option<Vec<KeyEvent>> {
if self.pending_widget_keys.is_empty() {
None
} else {
Some(std::mem::take(&mut self.pending_widget_keys))
}
}
pub fn getopts_char_offset(&self) -> usize {
self.getopts_offset
}
pub fn inc_getopts_char_offset(&mut self) -> usize {
let offset = self.getopts_offset;
self.getopts_offset += 1;
offset
}
pub fn reset_getopts_char_offset(&mut self) {
self.getopts_offset = 0;
}
pub fn get_builtin_comp_specs() -> HashMap<String, Box<dyn CompSpec>> {
let mut map = HashMap::new();
@@ -1280,14 +1304,14 @@ impl MetaTab {
"disown".into(),
Box::new(BashCompSpec::new().jobs(true)) as Box<dyn CompSpec>,
);
map.insert(
"alias".into(),
Box::new(BashCompSpec::new().aliases(true)) as Box<dyn CompSpec>,
);
map.insert(
"trap".into(),
Box::new(BashCompSpec::new().signals(true)) as Box<dyn CompSpec>,
);
map.insert(
"alias".into(),
Box::new(BashCompSpec::new().aliases(true)) as Box<dyn CompSpec>,
);
map.insert(
"trap".into(),
Box::new(BashCompSpec::new().signals(true)) as Box<dyn CompSpec>,
);
map
}
@@ -1312,29 +1336,29 @@ impl MetaTab {
pub fn remove_comp_spec(&mut self, cmd: &str) -> bool {
self.comp_specs.remove(cmd).is_some()
}
pub fn get_cmds_in_path() -> Vec<String> {
pub fn get_cmds_in_path() -> Vec<String> {
let path = env::var("PATH").unwrap_or_default();
let paths = path.split(":").map(PathBuf::from);
let mut cmds = vec![];
for path in paths {
if let Ok(entries) = path.read_dir() {
for entry in entries.flatten() {
let Ok(meta) = std::fs::metadata(entry.path()) else {
continue;
};
let is_exec = meta.permissions().mode() & 0o111 != 0;
let mut cmds = vec![];
for path in paths {
if let Ok(entries) = path.read_dir() {
for entry in entries.flatten() {
let Ok(meta) = std::fs::metadata(entry.path()) else {
continue;
};
let is_exec = meta.permissions().mode() & 0o111 != 0;
if meta.is_file()
&& is_exec
&& let Some(name) = entry.file_name().to_str()
{
cmds.push(name.to_string());
}
}
}
}
cmds
}
if meta.is_file()
&& is_exec
&& let Some(name) = entry.file_name().to_str()
{
cmds.push(name.to_string());
}
}
}
}
cmds
}
pub fn try_rehash_commands(&mut self) {
let path = env::var("PATH").unwrap_or_default();
let cwd = env::var("PWD").unwrap_or_default();
@@ -1350,10 +1374,10 @@ impl MetaTab {
self.path_cache.clear();
self.old_path = Some(path.clone());
self.old_pwd = Some(cwd.clone());
let cmds_in_path = Self::get_cmds_in_path();
for cmd in cmds_in_path {
self.path_cache.insert(cmd);
}
let cmds_in_path = Self::get_cmds_in_path();
for cmd in cmds_in_path {
self.path_cache.insert(cmd);
}
if let Ok(entries) = Path::new(&cwd).read_dir() {
for entry in entries.flatten() {
let Ok(meta) = std::fs::metadata(entry.path()) else {
@@ -1589,63 +1613,86 @@ pub fn get_shopt(path: &str) -> String {
read_shopts(|s| s.get(path)).unwrap().unwrap()
}
pub fn with_vars<F,H,V,T>(vars: H, f: F) -> T
pub fn with_vars<F, H, V, T>(vars: H, f: F) -> T
where
F: FnOnce() -> T,
H: Into<HashMap<String,V>>,
V: Into<Var> {
let snapshot = read_vars(|v| v.clone());
let vars = vars.into();
for (name, val) in vars {
let val = val.into();
write_vars(|v| v.set_var(&name, val.kind, val.flags).unwrap());
}
let _guard = scopeguard::guard(snapshot, |snap| {
write_vars(|v| *v = snap);
});
f()
F: FnOnce() -> T,
H: Into<HashMap<String, V>>,
V: Into<Var>,
{
let snapshot = read_vars(|v| v.clone());
let vars = vars.into();
for (name, val) in vars {
let val = val.into();
write_vars(|v| v.set_var(&name, val.kind, val.flags).unwrap());
}
let _guard = scopeguard::guard(snapshot, |snap| {
write_vars(|v| *v = snap);
});
f()
}
pub fn change_dir<P: AsRef<Path>>(dir: P) -> ShResult<()> {
let dir = dir.as_ref();
let dir_raw = &dir.display().to_string();
let pre_cd = read_logic(|l| l.get_autocmds(AutoCmdKind::PreChangeDir));
let post_cd = read_logic(|l| l.get_autocmds(AutoCmdKind::PostChangeDir));
let dir = dir.as_ref();
let dir_raw = &dir.display().to_string();
let pre_cd = read_logic(|l| l.get_autocmds(AutoCmdKind::PreChangeDir));
let post_cd = read_logic(|l| l.get_autocmds(AutoCmdKind::PostChangeDir));
let current_dir = env::current_dir()?.display().to_string();
with_vars([("_NEW_DIR".into(), dir_raw.as_str()), ("_OLD_DIR".into(), current_dir.as_str())], || {
for cmd in pre_cd {
let AutoCmd { command, pattern } = cmd;
if let Some(pat) = pattern
&& !pat.is_match(dir_raw) {
continue;
}
let current_dir = env::current_dir()?.display().to_string();
with_vars(
[
("_NEW_DIR".into(), dir_raw.as_str()),
("_OLD_DIR".into(), current_dir.as_str()),
],
|| {
for cmd in pre_cd {
let AutoCmd { command, pattern } = cmd;
if let Some(pat) = pattern
&& !pat.is_match(dir_raw)
{
continue;
}
if let Err(e) = exec_input(command.clone(), None, false, Some("autocmd (pre-changedir)".to_string())) {
e.print_error();
};
}
});
if let Err(e) = exec_input(
command.clone(),
None,
false,
Some("autocmd (pre-changedir)".to_string()),
) {
e.print_error();
};
}
},
);
env::set_current_dir(dir)?;
env::set_current_dir(dir)?;
with_vars(
[
("_NEW_DIR".into(), dir_raw.as_str()),
("_OLD_DIR".into(), current_dir.as_str()),
],
|| {
for cmd in post_cd {
let AutoCmd { command, pattern } = cmd;
if let Some(pat) = pattern
&& !pat.is_match(dir_raw)
{
continue;
}
with_vars([("_NEW_DIR".into(), dir_raw.as_str()), ("_OLD_DIR".into(), current_dir.as_str())], || {
for cmd in post_cd {
let AutoCmd { command, pattern } = cmd;
if let Some(pat) = pattern
&& !pat.is_match(dir_raw) {
continue;
}
if let Err(e) = exec_input(
command.clone(),
None,
false,
Some("autocmd (post-changedir)".to_string()),
) {
e.print_error();
};
}
},
);
if let Err(e) = exec_input(command.clone(), None, false, Some("autocmd (post-changedir)".to_string())) {
e.print_error();
};
}
});
Ok(())
Ok(())
}
pub fn get_status() -> i32 {
@@ -1671,7 +1718,7 @@ pub fn source_rc() -> ShResult<()> {
}
pub fn source_file(path: PathBuf) -> ShResult<()> {
let source_name = path.to_string_lossy().to_string();
let source_name = path.to_string_lossy().to_string();
let mut file = OpenOptions::new().read(true).open(path)?;
let mut buf = String::new();