microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
3fc684b157698c92d12be32ea3c6f7b3521de2b3

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

language_service/src/lib.rs

127lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#![warn(clippy::mod_module_files, clippy::pedantic, clippy::unwrap_used)]
5
6pub mod completion;
7pub mod definition;
8mod display;
9pub mod hover;
10mod qsc_utils;
11#[cfg(test)]
12mod test_utils;
13
14use crate::{
15 completion::CompletionList, definition::Definition, hover::Hover, qsc_utils::compile_document,
16};
17use log::trace;
18use qsc_utils::Compilation;
19use std::collections::HashMap;
20
21pub struct LanguageService<'a> {
22 /// Associate each known document with a separate compilation.
23 document_map: HashMap<String, DocumentState>,
24 /// Callback which will receive diagnostics (compilation errors)
25 /// whenever a (re-)compilation occurs.
26 diagnostics_receiver: Box<DiagnosticsReceiver<'a>>,
27}
28
29struct DocumentState {
30 /// This version is the document version provided by the client.
31 /// It increases strictly with each text change, though this knowledge should
32 /// not be important. The version is only ever used when publishing
33 /// diagnostics to help the client associate the list of diagnostics
34 /// with a snapshot of the document.
35 pub version: u32,
36 pub compilation: Compilation,
37}
38
39type DiagnosticsReceiver<'a> = dyn FnMut(&str, u32, &[qsc::compile::Error]) + 'a;
40
41impl<'a> LanguageService<'a> {
42 pub fn new(diagnostics_receiver: impl FnMut(&str, u32, &[qsc::compile::Error]) + 'a) -> Self {
43 LanguageService {
44 document_map: HashMap::new(),
45 diagnostics_receiver: Box::new(diagnostics_receiver),
46 }
47 }
48
49 /// Indicates that the document has been opened or the source has been updated.
50 /// This should be called before any language service requests have been made
51 /// for the document, typically when the document is first opened in the editor.
52 /// It should also be called whenever the source code is updated.
53 pub fn update_document(&mut self, uri: &str, version: u32, text: &str) {
54 trace!("update_document: {uri:?} {version:?}");
55 let compilation = compile_document(uri, text);
56 let errors = compilation.errors.clone();
57
58 // insert() will update the value if the key already exists
59 self.document_map.insert(
60 uri.to_string(),
61 DocumentState {
62 version,
63 compilation,
64 },
65 );
66
67 trace!("publishing diagnostics for {uri:?}: {errors:?}");
68
69 // Publish diagnostics
70 (self.diagnostics_receiver)(uri, version, &errors);
71 }
72
73 /// Indicates that the client is no longer interested in the document,
74 /// typically occurs when the document is closed in the editor.
75 pub fn close_document(&mut self, uri: &str) {
76 trace!("close_document: {uri:?}");
77 let document_state = self.document_map.remove(uri);
78
79 // Clear the diagnostics, as each document represents
80 // a separate compilation that disappears when the document is closed.
81 (self.diagnostics_receiver)(
82 uri,
83 document_state
84 .expect("close_document received for unknown uri")
85 .version,
86 &[],
87 );
88 }
89
90 #[must_use]
91 pub fn get_completions(&self, uri: &str, offset: u32) -> CompletionList {
92 trace!("get_completions: uri: {uri:?}, offset: {offset:?}");
93 let res = completion::get_completions(
94 &self
95 .document_map.get(uri).as_ref()
96 .expect("get_completions should not be called before document has been initialized with update_document").compilation,
97 uri,
98 offset,
99 );
100 trace!("get_completions result: {res:?}");
101 res
102 }
103
104 #[must_use]
105 pub fn get_definition(&self, uri: &str, offset: u32) -> Option<Definition> {
106 trace!("get_definition: uri: {uri:?}, offset: {offset:?}");
107 let res = definition::get_definition(
108 &self
109 .document_map.get(uri).as_ref()
110 .expect("get_definition should not be called before document has been initialized with update_document").compilation,
111 uri, offset);
112 trace!("get_definition result: {res:?}");
113 res
114 }
115
116 #[must_use]
117 pub fn get_hover(&self, uri: &str, offset: u32) -> Option<Hover> {
118 trace!("get_hover: uri: {uri:?}, offset: {offset:?}");
119 let res = hover::get_hover(
120 &self
121 .document_map.get(uri).as_ref()
122 .expect("get_hover should not be called before document has been initialized with update_document").compilation,
123 uri, offset);
124 trace!("get_hover result: {res:?}");
125 res
126 }
127}