summaryrefslogtreecommitdiff
path: root/crates/nu-protocol/src/engine/state_delta.rs
blob: 0204dbe7f1eb781f1a159b1d32ff49356b51f292 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
use crate::{
    ast::Block,
    engine::{
        description::Doccomments, CachedFile, Command, EngineState, OverlayFrame, ScopeFrame,
        Variable, VirtualPath,
    },
    Module, Span,
};
use std::sync::Arc;

#[cfg(feature = "plugin")]
use crate::{PluginRegistryItem, 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 spans: Vec<Span>,                    // indexed by SpanId
    pub(super) doccomments: Doccomments,
    pub scope: Vec<ScopeFrame>,
    #[cfg(feature = "plugin")]
    pub(super) plugins: Vec<Arc<dyn RegisteredPlugin>>,
    #[cfg(feature = "plugin")]
    pub(super) plugin_registry_items: Vec<PluginRegistryItem>,
}

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![],
            spans: vec![],
            scope: vec![scope_frame],
            doccomments: Doccomments::new(),
            #[cfg(feature = "plugin")]
            plugins: vec![],
            #[cfg(feature = "plugin")]
            plugin_registry_items: 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.get())
                    .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.get())
                    .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
    }
}