Skip to content

Commit b922051

Browse files
committed
refactor(lsp_server): improve structure and robustness
1 parent 2f945af commit b922051

File tree

1 file changed

+72
-62
lines changed

1 file changed

+72
-62
lines changed

src/app/lsp_server/lsp_server_inner.rs

Lines changed: 72 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use tower_lsp::lsp_types::{
44
CodeActionOrCommand, CodeActionParams, CodeActionProviderCapability, CodeActionResponse,
55
CodeLens, CodeLensOptions, CodeLensParams, Command, DidChangeConfigurationParams,
66
DidChangeTextDocumentParams, DidOpenTextDocumentParams, ExecuteCommandOptions,
7-
ExecuteCommandParams, InitializeParams, InitializeResult, InitializedParams, MessageType,
8-
ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind,
7+
ExecuteCommandParams, InitializeParams, InitializeResult, InitializedParams, Location,
8+
MessageType, ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind,
99
};
1010
use tracing::{debug, info};
1111

@@ -23,7 +23,7 @@ use super::supported_commands::SupportedCommands;
2323
pub struct LSPServerInner<C> {
2424
interactor: LspInteractor<C>,
2525
query_executor: QueryExecutor,
26-
component_factory: ComponentFactory,
26+
component_factory: Option<ComponentFactory>,
2727
}
2828

2929
impl<C> LSPServerInner<C> {
@@ -33,7 +33,7 @@ impl<C> LSPServerInner<C> {
3333
LSPServerInner {
3434
interactor: LspInteractor::new(client, document_database.clone()),
3535
query_executor: QueryExecutor::new(document_database.clone()),
36-
component_factory: Default::default(), // to be initialized in the initialize method of the LSP
36+
component_factory: None, // to be initialized in the initialize method of the LSP
3737
}
3838
}
3939
}
@@ -50,7 +50,9 @@ where
5050

5151
debug!("updating with configuration: {config:?}");
5252

53-
self.component_factory.initialize_with(config);
53+
let mut factory = ComponentFactory::default();
54+
factory.initialize_with(config);
55+
self.component_factory = Some(factory);
5456

5557
debug!("updated configuration");
5658
Ok(())
@@ -61,6 +63,20 @@ impl<C> LSPServerInner<C>
6163
where
6264
C: LSPClient + Send + Sync + 'static,
6365
{
66+
async fn get_commands_for_document(
67+
&self,
68+
uri: &tower_lsp::lsp_types::Url,
69+
) -> Result<Vec<command_generator::CommandInfo>> {
70+
let Some(content) = self.query_executor.get_document_text(uri.as_str()).await else {
71+
return Err(Error::internal_error().with_message(format!(
72+
"unable to extract document content for document: {uri}"
73+
)));
74+
};
75+
76+
let commands = command_generator::generate_commands_for_uri(uri, &content);
77+
Ok(commands)
78+
}
79+
6480
pub async fn initialize(
6581
&mut self,
6682
initialize_params: InitializeParams,
@@ -128,19 +144,9 @@ where
128144
&self,
129145
params: CodeActionParams,
130146
) -> Result<Option<CodeActionResponse>> {
131-
let Some(content) = self
132-
.query_executor
133-
.get_document_text(params.text_document.uri.as_str())
134-
.await
135-
else {
136-
return Err(Error::internal_error().with_message(format!(
137-
"unable to extract document content for document: {}",
138-
&params.text_document.uri
139-
)));
140-
};
141-
142-
let commands =
143-
command_generator::generate_commands_for_uri(&params.text_document.uri, &content);
147+
let commands = self
148+
.get_commands_for_document(&params.text_document.uri)
149+
.await?;
144150
let code_actions: Vec<CodeActionOrCommand> = commands
145151
.into_iter()
146152
.filter(|cmd| cmd.range.start.line == params.range.start.line)
@@ -157,19 +163,9 @@ where
157163
}
158164

159165
pub async fn code_lens(&self, params: CodeLensParams) -> Result<Option<Vec<CodeLens>>> {
160-
let Some(content) = self
161-
.query_executor
162-
.get_document_text(params.text_document.uri.as_str())
163-
.await
164-
else {
165-
return Err(Error::internal_error().with_message(format!(
166-
"unable to extract document content for document: {}",
167-
&params.text_document.uri
168-
)));
169-
};
170-
171-
let commands =
172-
command_generator::generate_commands_for_uri(&params.text_document.uri, &content);
166+
let commands = self
167+
.get_commands_for_document(&params.text_document.uri)
168+
.await?;
173169
let code_lenses = commands
174170
.into_iter()
175171
.map(|cmd| CodeLens {
@@ -186,49 +182,63 @@ where
186182
Ok(Some(code_lenses))
187183
}
188184

185+
fn component_factory_mut(&mut self) -> Result<&mut ComponentFactory> {
186+
self.component_factory
187+
.as_mut()
188+
.ok_or_else(|| Error::internal_error().with_message("LSP not initialized"))
189+
}
190+
191+
async fn execute_base_image_scan(
192+
&mut self,
193+
location: Location,
194+
image: String,
195+
) -> Result<Option<Value>> {
196+
let image_scanner = self.component_factory_mut()?.image_scanner().map_err(|e| {
197+
Error::internal_error().with_message(format!("unable to create image scanner: {e}"))
198+
})?;
199+
let mut command =
200+
ScanBaseImageCommand::new(&image_scanner, &self.interactor, location, image);
201+
command.execute().await.map(|_| None)
202+
}
203+
204+
async fn execute_build_and_scan(&mut self, location: Location) -> Result<Option<Value>> {
205+
let factory = self.component_factory_mut()?;
206+
let image_scanner = factory.image_scanner().map_err(|e| {
207+
Error::internal_error().with_message(format!("unable to create image scanner: {e}"))
208+
})?;
209+
let image_builder = factory.image_builder().map_err(|e| {
210+
Error::internal_error().with_message(format!("unable to create image builder: {e}"))
211+
})?;
212+
let mut command =
213+
BuildAndScanCommand::new(&image_builder, &image_scanner, &self.interactor, location);
214+
command.execute().await.map(|_| None)
215+
}
216+
189217
pub async fn execute_command(&mut self, params: ExecuteCommandParams) -> Result<Option<Value>> {
190218
let command: SupportedCommands = params.try_into()?;
191219

192220
let result = match command.clone() {
193221
SupportedCommands::ExecuteBaseImageScan { location, image } => {
194-
let image_scanner = self.component_factory.image_scanner().map_err(|e| {
195-
Error::internal_error()
196-
.with_message(format!("unable to create image scanner: {e}"))
197-
})?;
198-
let mut command =
199-
ScanBaseImageCommand::new(&image_scanner, &self.interactor, location, image);
200-
command.execute().await.map(|_| None)
222+
self.execute_base_image_scan(location, image).await
201223
}
202224

203225
SupportedCommands::ExecuteBuildAndScan { location } => {
204-
let image_scanner = self.component_factory.image_scanner().map_err(|e| {
205-
Error::internal_error()
206-
.with_message(format!("unable to create image scanner: {e}"))
207-
})?;
208-
let image_builder = self.component_factory.image_builder().map_err(|e| {
209-
Error::internal_error()
210-
.with_message(format!("unable to create image builder: {e}"))
211-
})?;
212-
let mut command = BuildAndScanCommand::new(
213-
&image_builder,
214-
&image_scanner,
215-
&self.interactor,
216-
location,
217-
);
218-
command.execute().await.map(|_| None)
226+
self.execute_build_and_scan(location).await
219227
}
220228
};
221229

222-
match result {
223-
Ok(_) => result,
224-
Err(mut e) => {
225-
self.interactor
226-
.show_message(MessageType::ERROR, e.to_string().as_str())
227-
.await;
228-
e.message = format!("error calling command: '{command}': {e}").into();
229-
Err(e)
230-
}
230+
if let Err(e) = &result {
231+
self.interactor
232+
.show_message(MessageType::ERROR, e.to_string().as_str())
233+
.await;
234+
return Err(Error {
235+
code: e.code,
236+
message: format!("error calling command: '{command}': {}", e.message).into(),
237+
data: e.data.clone(),
238+
});
231239
}
240+
241+
result
232242
}
233243

234244
pub async fn shutdown(&self) -> Result<()> {

0 commit comments

Comments
 (0)