mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
Convert more block iteration methods to use iterators
This commit is contained in:
parent
0a8fd05bb0
commit
7d77d7aa84
1 changed files with 66 additions and 81 deletions
147
src/parser.rs
147
src/parser.rs
|
@ -372,30 +372,22 @@ impl Parser {
|
|||
|
||||
/// Return whether we are currently evaluating a function.
|
||||
pub fn is_function(&self) -> bool {
|
||||
let blocks = self.blocks();
|
||||
for b in blocks.iter().rev() {
|
||||
if b.is_function_call() {
|
||||
return true;
|
||||
} else if b.typ() == BlockType::source {
|
||||
// If a function sources a file, don't descend further.
|
||||
break;
|
||||
}
|
||||
}
|
||||
false
|
||||
self.blocks()
|
||||
.iter()
|
||||
.rev()
|
||||
// If a function sources a file, don't descend further.
|
||||
.take_while(|b| b.typ() != BlockType::source)
|
||||
.any(|b| b.is_function_call())
|
||||
}
|
||||
|
||||
/// Return whether we are currently evaluating a command substitution.
|
||||
pub fn is_command_substitution(&self) -> bool {
|
||||
let blocks = self.blocks();
|
||||
for b in blocks.iter().rev() {
|
||||
if b.typ() == BlockType::subst {
|
||||
return true;
|
||||
} else if b.typ() == BlockType::source {
|
||||
// If a function sources a file, don't descend further.
|
||||
break;
|
||||
}
|
||||
}
|
||||
false
|
||||
self.blocks()
|
||||
.iter()
|
||||
.rev()
|
||||
// If a function sources a file, don't descend further.
|
||||
.take_while(|b| b.typ() != BlockType::source)
|
||||
.any(|b| b.typ() == BlockType::subst)
|
||||
}
|
||||
|
||||
/// Get the "principal" parser, whatever that is. Can only be called by the main thread.
|
||||
|
@ -698,24 +690,18 @@ impl Parser {
|
|||
/// This supports 'status is-block'.
|
||||
pub fn is_block(&self) -> bool {
|
||||
// Note historically this has descended into 'source', unlike 'is_function'.
|
||||
let blocks = self.blocks();
|
||||
for b in blocks.iter().rev() {
|
||||
if ![BlockType::top, BlockType::subst].contains(&b.typ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
self.blocks()
|
||||
.iter()
|
||||
.rev()
|
||||
.any(|b| ![BlockType::top, BlockType::subst].contains(&b.typ()))
|
||||
}
|
||||
|
||||
/// Return whether we have a breakpoint block.
|
||||
pub fn is_breakpoint(&self) -> bool {
|
||||
let blocks = self.blocks();
|
||||
for b in blocks.iter().rev() {
|
||||
if b.typ() == BlockType::breakpoint {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
self.blocks()
|
||||
.iter()
|
||||
.rev()
|
||||
.any(|b| b.typ() == BlockType::breakpoint)
|
||||
}
|
||||
|
||||
/// Return the list of blocks. The first block is at the top.
|
||||
|
@ -857,34 +843,33 @@ impl Parser {
|
|||
// Return the function name for the level preceding the most recent breakpoint. If there
|
||||
// isn't one return the function name for the current level.
|
||||
// Walk until we find a breakpoint, then take the next function.
|
||||
let mut found_breakpoint = false;
|
||||
let blocks = self.blocks();
|
||||
for b in blocks.iter().rev() {
|
||||
if b.typ() == BlockType::breakpoint {
|
||||
found_breakpoint = true;
|
||||
} else if found_breakpoint && b.is_function_call() {
|
||||
return Some(b.function_name.clone());
|
||||
}
|
||||
}
|
||||
return None; // couldn't find a breakpoint frame
|
||||
return self
|
||||
.blocks()
|
||||
.iter()
|
||||
.rev()
|
||||
.skip_while(|b| b.typ() != BlockType::breakpoint)
|
||||
.find(|b| b.is_function_call())
|
||||
.map(|b| b.function_name.clone());
|
||||
}
|
||||
|
||||
// Level 1 is the topmost function call. Level 2 is its caller. Etc.
|
||||
let mut funcs_seen = 0;
|
||||
let blocks = self.blocks();
|
||||
for b in blocks.iter().rev() {
|
||||
if b.is_function_call() {
|
||||
funcs_seen += 1;
|
||||
if funcs_seen == level {
|
||||
return Some(b.function_name.clone());
|
||||
self.blocks()
|
||||
.iter()
|
||||
.rev()
|
||||
// Historical: If we want the topmost function, but we are really in a file sourced by a
|
||||
// function, don't consider ourselves to be in a function.
|
||||
.take_while(|b| !(level == 1 && b.typ() == BlockType::source))
|
||||
.map(|b| (b, 0))
|
||||
.map(|(b, level)| {
|
||||
if b.is_function_call() {
|
||||
(b, level + 1)
|
||||
} else {
|
||||
(b, level)
|
||||
}
|
||||
} else if b.typ() == BlockType::source && level == 1 {
|
||||
// Historical: If we want the topmost function, but we are really in a file sourced by a
|
||||
// function, don't consider ourselves to be in a function.
|
||||
break;
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.skip_while(|(_, l)| *l != level)
|
||||
.inspect(|(b, _)| debug_assert!(b.is_function_call()))
|
||||
.map(|(b, _)| b.function_name.clone())
|
||||
.next()
|
||||
}
|
||||
|
||||
/// Promotes a job to the front of the list.
|
||||
|
@ -1011,17 +996,20 @@ impl Parser {
|
|||
/// reader_current_filename, e.g. if we are evaluating a function defined in a different file
|
||||
/// than the one currently read.
|
||||
pub fn current_filename(&self) -> Option<FilenameRef> {
|
||||
let blocks = self.blocks();
|
||||
for b in blocks.iter().rev() {
|
||||
if b.is_function_call() {
|
||||
return function::get_props(&b.function_name)
|
||||
.and_then(|props| props.definition_file.clone());
|
||||
} else if b.typ() == BlockType::source {
|
||||
return b.sourced_file.clone();
|
||||
}
|
||||
}
|
||||
// Fall back to the file being sourced.
|
||||
self.libdata().current_filename.clone()
|
||||
self.blocks()
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|b| {
|
||||
if b.is_function_call() {
|
||||
function::get_props(&b.function_name)
|
||||
.and_then(|props| props.definition_file.clone())
|
||||
} else if b.typ() == BlockType::source {
|
||||
b.sourced_file.clone()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.or_else(|| self.libdata().current_filename.clone())
|
||||
}
|
||||
|
||||
/// Return if we are interactive, which means we are executing a command that the user typed in
|
||||
|
@ -1032,21 +1020,18 @@ impl Parser {
|
|||
|
||||
/// Return a string representing the current stack trace.
|
||||
pub fn stack_trace(&self) -> WString {
|
||||
let mut trace = WString::new();
|
||||
let blocks = self.blocks();
|
||||
for b in blocks.iter().rev() {
|
||||
append_block_description_to_stack_trace(self, b, &mut trace);
|
||||
|
||||
self.blocks()
|
||||
.iter()
|
||||
.rev()
|
||||
// Stop at event handler. No reason to believe that any other code is relevant.
|
||||
//
|
||||
// It might make sense in the future to continue printing the stack trace of the code
|
||||
// that invoked the event, if this is a programmatic event, but we can't currently
|
||||
// detect that.
|
||||
if b.typ() == BlockType::event {
|
||||
break;
|
||||
}
|
||||
}
|
||||
trace
|
||||
.take_while(|b| b.typ() != BlockType::event)
|
||||
.fold(WString::new(), |mut trace, b| {
|
||||
append_block_description_to_stack_trace(self, b, &mut trace);
|
||||
trace
|
||||
})
|
||||
}
|
||||
|
||||
/// Return whether the number of functions in the stack exceeds our stack depth limit.
|
||||
|
|
Loading…
Reference in a new issue