mun_language_server/
analysis.rs

1use crate::{
2    cancelation::Canceled, change::AnalysisChange, completion, db::AnalysisDatabase, diagnostics,
3    diagnostics::Diagnostic, file_structure, FilePosition,
4};
5use mun_hir::{line_index::LineIndex, AstDatabase, SourceDatabase};
6use mun_syntax::SourceFile;
7use salsa::{ParallelDatabase, Snapshot};
8use std::sync::Arc;
9
10/// Result of an operation that can be canceled.
11pub type Cancelable<T> = Result<T, Canceled>;
12
13/// The `Analysis` struct is the basis of all language server operations. It maintains the current
14/// state of the source.
15#[derive(Default)]
16pub struct Analysis {
17    db: AnalysisDatabase,
18}
19
20impl Analysis {
21    /// Applies the given changes to the state. If there are outstanding `AnalysisSnapshot`s they
22    /// will be canceled.
23    pub fn apply_change(&mut self, change: AnalysisChange) {
24        self.db.apply_change(change)
25    }
26
27    /// Creates a snapshot of the current `Analysis`. You can query the resulting `AnalysisSnapshot`
28    /// to get analysis and diagnostics.
29    pub fn snapshot(&self) -> AnalysisSnapshot {
30        AnalysisSnapshot {
31            db: self.db.snapshot(),
32        }
33    }
34
35    /// Requests any outstanding snapshot to cancel computations.
36    pub fn request_cancelation(&mut self) {
37        self.db.request_cancelation();
38    }
39}
40
41/// The `AnalysisSnapshot` is a snapshot of the state of the source, it enables querying for
42/// the snapshot in a consistent state.
43///
44/// A `AnalysisSnapshot` is created by calling `Analysis::snapshot`. When applying changes to the
45/// `Analysis` struct through the use of `Analysis::apply_changes` all snapshots are cancelled (most
46/// methods return `Err(Canceled)`).
47pub struct AnalysisSnapshot {
48    db: Snapshot<AnalysisDatabase>,
49}
50
51impl AnalysisSnapshot {
52    /// Returns the syntax tree of the file.
53    pub fn parse(&self, file_id: mun_hir::FileId) -> Cancelable<SourceFile> {
54        self.with_db(|db| db.parse(file_id).tree())
55    }
56
57    /// Computes the set of diagnostics for the given file.
58    pub fn diagnostics(&self, file_id: mun_hir::FileId) -> Cancelable<Vec<Diagnostic>> {
59        self.with_db(|db| diagnostics::diagnostics(db, file_id))
60    }
61
62    /// Returns all the source files of the given package
63    pub fn package_source_files(
64        &self,
65        package_id: mun_hir::PackageId,
66    ) -> Cancelable<Vec<mun_hir::FileId>> {
67        self.with_db(|db| {
68            let packages = db.packages();
69            let source_root = db.source_root(packages[package_id].source_root);
70            source_root.files().collect()
71        })
72    }
73
74    /// Returns the line index for the specified file
75    pub fn file_line_index(&self, file_id: mun_hir::FileId) -> Cancelable<Arc<LineIndex>> {
76        self.with_db(|db| db.line_index(file_id))
77    }
78
79    /// Returns a tree structure of the symbols of a file.
80    pub fn file_structure(
81        &self,
82        file_id: mun_hir::FileId,
83    ) -> Cancelable<Vec<file_structure::StructureNode>> {
84        self.with_db(|db| file_structure::file_structure(&db.parse(file_id).tree()))
85    }
86
87    /// Computes completions at the given position
88    pub fn completions(
89        &self,
90        position: FilePosition,
91    ) -> Cancelable<Option<Vec<completion::CompletionItem>>> {
92        self.with_db(|db| completion::completions(db, position).map(Into::into))
93    }
94
95    /// Performs an operation on that may be Canceled.
96    fn with_db<F: FnOnce(&AnalysisDatabase) -> T + std::panic::UnwindSafe, T>(
97        &self,
98        f: F,
99    ) -> Cancelable<T> {
100        self.db.catch_canceled(f)
101    }
102}