Devyn Cairns fdf7f28d07
Address feedback from PR #12229 (#12242)
# Description
@sholderbach left a very helpful review and this just implements the
suggestions he made.

Didn't notice any difference in performance, but there could potentially
be for a long running Nushell session or one that loads a lot of stuff.

I also caught a bug where nu-protocol won't build without `plugin`
because of the previous conditional import. Oops. Fixed.

# User-Facing Changes
`blocks` and `modules` type in `EngineState` changed again. Shouldn't
affect plugins or anything else though really

# Tests + Formatting
- 🟢 `toolkit fmt`
- 🟢 `toolkit clippy`
- 🟢 `toolkit test`
- 🟢 `toolkit test stdlib`

# After Submitting

---------

Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
2024-03-20 20:16:18 +01:00

136 lines
3.9 KiB
Rust

use super::cached_file::CachedFile;
use super::{usage::Usage, Command, EngineState, OverlayFrame, ScopeFrame, Variable, VirtualPath};
use crate::ast::Block;
use crate::Module;
use std::sync::Arc;
#[cfg(feature = "plugin")]
use crate::RegisteredPlugin;
/// A delta (or change set) between the current global state and a possible future global state. Deltas
/// can be applied to the global state to update it to contain both previous state and the state held
/// within the delta.
pub struct StateDelta {
pub(super) files: Vec<CachedFile>,
pub(super) virtual_paths: Vec<(String, VirtualPath)>,
pub(super) vars: Vec<Variable>, // indexed by VarId
pub(super) decls: Vec<Box<dyn Command>>, // indexed by DeclId
pub blocks: Vec<Arc<Block>>, // indexed by BlockId
pub(super) modules: Vec<Arc<Module>>, // indexed by ModuleId
pub(super) usage: Usage,
pub scope: Vec<ScopeFrame>,
#[cfg(feature = "plugin")]
pub(super) plugins_changed: bool, // marks whether plugin file should be updated
#[cfg(feature = "plugin")]
pub(super) plugins: Vec<Arc<dyn RegisteredPlugin>>,
}
impl StateDelta {
pub fn new(engine_state: &EngineState) -> Self {
let last_overlay = engine_state.last_overlay(&[]);
let scope_frame = ScopeFrame::with_empty_overlay(
engine_state.last_overlay_name(&[]).to_owned(),
last_overlay.origin,
last_overlay.prefixed,
);
StateDelta {
files: vec![],
virtual_paths: vec![],
vars: vec![],
decls: vec![],
blocks: vec![],
modules: vec![],
scope: vec![scope_frame],
usage: Usage::new(),
#[cfg(feature = "plugin")]
plugins_changed: false,
#[cfg(feature = "plugin")]
plugins: vec![],
}
}
pub fn num_files(&self) -> usize {
self.files.len()
}
pub fn num_virtual_paths(&self) -> usize {
self.virtual_paths.len()
}
pub fn num_decls(&self) -> usize {
self.decls.len()
}
pub fn num_blocks(&self) -> usize {
self.blocks.len()
}
pub fn num_modules(&self) -> usize {
self.modules.len()
}
pub fn last_scope_frame_mut(&mut self) -> &mut ScopeFrame {
self.scope
.last_mut()
.expect("internal error: missing required scope frame")
}
pub fn last_scope_frame(&self) -> &ScopeFrame {
self.scope
.last()
.expect("internal error: missing required scope frame")
}
pub fn last_overlay_mut(&mut self) -> Option<&mut OverlayFrame> {
let last_scope = self
.scope
.last_mut()
.expect("internal error: missing required scope frame");
if let Some(last_overlay_id) = last_scope.active_overlays.last() {
Some(
&mut last_scope
.overlays
.get_mut(*last_overlay_id)
.expect("internal error: missing required overlay")
.1,
)
} else {
None
}
}
pub fn last_overlay(&self) -> Option<&OverlayFrame> {
let last_scope = self
.scope
.last()
.expect("internal error: missing required scope frame");
if let Some(last_overlay_id) = last_scope.active_overlays.last() {
Some(
&last_scope
.overlays
.get(*last_overlay_id)
.expect("internal error: missing required overlay")
.1,
)
} else {
None
}
}
pub fn enter_scope(&mut self) {
self.scope.push(ScopeFrame::new());
}
pub fn exit_scope(&mut self) {
self.scope.pop();
}
pub fn get_file_contents(&self) -> &[CachedFile] {
&self.files
}
}