1use crate::{
2 buffer_store::{BufferStore, BufferStoreEvent},
3 environment::ProjectEnvironment,
4 lsp_command::{self, *},
5 lsp_ext_command,
6 project_settings::ProjectSettings,
7 relativize_path, resolve_path,
8 worktree_store::{WorktreeStore, WorktreeStoreEvent},
9 yarn::YarnPathStore,
10 CodeAction, Completion, CoreCompletion, Hover, InlayHint, Item as _, ProjectPath,
11 ProjectTransaction, ResolveState, Symbol,
12};
13use anyhow::{anyhow, Context as _, Result};
14use async_trait::async_trait;
15use client::{proto, TypedEnvelope};
16use collections::{btree_map, BTreeMap, HashMap, HashSet};
17use futures::{
18 future::{join_all, Shared},
19 select,
20 stream::FuturesUnordered,
21 Future, FutureExt, StreamExt,
22};
23use globset::{Glob, GlobSet, GlobSetBuilder};
24use gpui::{
25 AppContext, AsyncAppContext, Entity, EventEmitter, Model, ModelContext, PromptLevel, Task,
26 WeakModel,
27};
28use http_client::HttpClient;
29use itertools::Itertools;
30use language::{
31 language_settings::{language_settings, AllLanguageSettings, LanguageSettings},
32 markdown, point_to_lsp, prepare_completion_documentation,
33 proto::{deserialize_anchor, deserialize_version, serialize_anchor, serialize_version},
34 range_from_lsp, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
35 DiagnosticEntry, DiagnosticSet, Documentation, File as _, Language, LanguageRegistry,
36 LanguageServerName, LocalFile, LspAdapterDelegate, Patch, PendingLanguageServer, PointUtf16,
37 TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction, Unclipped,
38};
39use lsp::{
40 CompletionContext, DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions,
41 Edit, FileSystemWatcher, InsertTextFormat, LanguageServer, LanguageServerBinary,
42 LanguageServerId, LspRequestFuture, MessageActionItem, MessageType, OneOf, ServerHealthStatus,
43 ServerStatus, SymbolKind, TextEdit, WorkDoneProgressCancelParams,
44};
45use parking_lot::{Mutex, RwLock};
46use postage::watch;
47use rand::prelude::*;
48
49use rpc::proto::AnyProtoClient;
50use serde::Serialize;
51use settings::{Settings, SettingsLocation, SettingsStore};
52use sha2::{Digest, Sha256};
53use similar::{ChangeTag, TextDiff};
54use smol::channel::Sender;
55use snippet::Snippet;
56use std::{
57 cmp::Ordering,
58 convert::TryInto,
59 ffi::OsStr,
60 iter, mem,
61 ops::Range,
62 path::{self, Path, PathBuf},
63 process::Stdio,
64 str,
65 sync::{atomic::Ordering::SeqCst, Arc},
66 time::{Duration, Instant},
67};
68use text::{Anchor, BufferId, LineEnding};
69use util::{
70 debug_panic, defer, maybe, merge_json_value_into, post_inc, ResultExt, TryFutureExt as _,
71};
72
73pub use fs::*;
74pub use language::Location;
75#[cfg(any(test, feature = "test-support"))]
76pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
77pub use worktree::{
78 Entry, EntryKind, File, LocalWorktree, PathChange, ProjectEntryId, RepositoryEntry,
79 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
80 FS_WATCH_LATENCY,
81};
82
83const MAX_SERVER_REINSTALL_ATTEMPT_COUNT: u64 = 4;
84const SERVER_REINSTALL_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
85const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
86pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
87
88pub struct LspStore {
89 downstream_client: Option<AnyProtoClient>,
90 upstream_client: Option<AnyProtoClient>,
91 project_id: u64,
92 http_client: Option<Arc<dyn HttpClient>>,
93 fs: Arc<dyn Fs>,
94 nonce: u128,
95 buffer_store: Model<BufferStore>,
96 worktree_store: Model<WorktreeStore>,
97 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
98 environment: Option<Model<ProjectEnvironment>>,
99 supplementary_language_servers:
100 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
101 languages: Arc<LanguageRegistry>,
102 language_servers: HashMap<LanguageServerId, LanguageServerState>,
103 language_server_ids: HashMap<(WorktreeId, LanguageServerName), LanguageServerId>,
104 language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
105 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
106 language_server_watched_paths: HashMap<LanguageServerId, HashMap<WorktreeId, GlobSet>>,
107 language_server_watcher_registrations:
108 HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
109 active_entry: Option<ProjectEntryId>,
110 _maintain_workspace_config: Task<Result<()>>,
111 _maintain_buffer_languages: Task<()>,
112 next_diagnostic_group_id: usize,
113 diagnostic_summaries:
114 HashMap<WorktreeId, HashMap<Arc<Path>, HashMap<LanguageServerId, DiagnosticSummary>>>,
115 diagnostics: HashMap<
116 WorktreeId,
117 HashMap<
118 Arc<Path>,
119 Vec<(
120 LanguageServerId,
121 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
122 )>,
123 >,
124 >,
125 yarn: Model<YarnPathStore>,
126 _subscription: gpui::Subscription,
127}
128
129pub enum LspStoreEvent {
130 LanguageServerAdded(LanguageServerId),
131 LanguageServerRemoved(LanguageServerId),
132 LanguageServerUpdate {
133 language_server_id: LanguageServerId,
134 message: proto::update_language_server::Variant,
135 },
136 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
137 LanguageServerPrompt(LanguageServerPromptRequest),
138 LanguageDetected {
139 buffer: Model<Buffer>,
140 new_language: Option<Arc<Language>>,
141 },
142 Notification(String),
143 RefreshInlayHints,
144 DiagnosticsUpdated {
145 language_server_id: LanguageServerId,
146 path: ProjectPath,
147 },
148 DiskBasedDiagnosticsStarted {
149 language_server_id: LanguageServerId,
150 },
151 DiskBasedDiagnosticsFinished {
152 language_server_id: LanguageServerId,
153 },
154 SnippetEdit {
155 buffer_id: BufferId,
156 edits: Vec<(lsp::Range, Snippet)>,
157 most_recent_edit: clock::Lamport,
158 },
159 StartFormattingLocalBuffer(BufferId),
160 FinishFormattingLocalBuffer(BufferId),
161}
162
163#[derive(Clone, Debug, Serialize)]
164pub struct LanguageServerStatus {
165 pub name: String,
166 pub pending_work: BTreeMap<String, LanguageServerProgress>,
167 pub has_pending_diagnostic_updates: bool,
168 progress_tokens: HashSet<String>,
169}
170
171#[derive(Clone, Debug)]
172struct CoreSymbol {
173 pub language_server_name: LanguageServerName,
174 pub source_worktree_id: WorktreeId,
175 pub path: ProjectPath,
176 pub name: String,
177 pub kind: lsp::SymbolKind,
178 pub range: Range<Unclipped<PointUtf16>>,
179 pub signature: [u8; 32],
180}
181
182impl LspStore {
183 pub fn init(client: &AnyProtoClient) {
184 client.add_model_request_handler(Self::handle_multi_lsp_query);
185 client.add_model_request_handler(Self::handle_restart_language_servers);
186 client.add_model_message_handler(Self::handle_start_language_server);
187 client.add_model_message_handler(Self::handle_update_language_server);
188 client.add_model_message_handler(Self::handle_update_diagnostic_summary);
189 client.add_model_request_handler(Self::handle_resolve_completion_documentation);
190 client.add_model_request_handler(Self::handle_apply_code_action);
191 client.add_model_request_handler(Self::handle_inlay_hints);
192 client.add_model_request_handler(Self::handle_get_project_symbols);
193 client.add_model_request_handler(Self::handle_resolve_inlay_hint);
194 client.add_model_request_handler(Self::handle_open_buffer_for_symbol);
195 client.add_model_request_handler(Self::handle_refresh_inlay_hints);
196 client.add_model_request_handler(Self::handle_on_type_formatting);
197 client.add_model_request_handler(Self::handle_apply_additional_edits_for_completion);
198 client.add_model_request_handler(Self::handle_lsp_command::<GetCodeActions>);
199 client.add_model_request_handler(Self::handle_lsp_command::<GetCompletions>);
200 client.add_model_request_handler(Self::handle_lsp_command::<GetHover>);
201 client.add_model_request_handler(Self::handle_lsp_command::<GetDefinition>);
202 client.add_model_request_handler(Self::handle_lsp_command::<GetDeclaration>);
203 client.add_model_request_handler(Self::handle_lsp_command::<GetTypeDefinition>);
204 client.add_model_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
205 client.add_model_request_handler(Self::handle_lsp_command::<GetReferences>);
206 client.add_model_request_handler(Self::handle_lsp_command::<PrepareRename>);
207 client.add_model_request_handler(Self::handle_lsp_command::<PerformRename>);
208 client.add_model_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
209 client.add_model_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
210 }
211
212 #[allow(clippy::too_many_arguments)]
213 pub fn new(
214 buffer_store: Model<BufferStore>,
215 worktree_store: Model<WorktreeStore>,
216 environment: Option<Model<ProjectEnvironment>>,
217 languages: Arc<LanguageRegistry>,
218 http_client: Option<Arc<dyn HttpClient>>,
219 fs: Arc<dyn Fs>,
220 downstream_client: Option<AnyProtoClient>,
221 upstream_client: Option<AnyProtoClient>,
222 remote_id: Option<u64>,
223 cx: &mut ModelContext<Self>,
224 ) -> Self {
225 let yarn = YarnPathStore::new(fs.clone(), cx);
226 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
227 .detach();
228 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
229 .detach();
230
231 Self {
232 downstream_client,
233 upstream_client,
234 http_client,
235 fs,
236 project_id: remote_id.unwrap_or(0),
237 buffer_store,
238 worktree_store,
239 languages: languages.clone(),
240 environment,
241 nonce: StdRng::from_entropy().gen(),
242 buffer_snapshots: Default::default(),
243 supplementary_language_servers: Default::default(),
244 language_servers: Default::default(),
245 language_server_ids: Default::default(),
246 language_server_statuses: Default::default(),
247 last_workspace_edits_by_language_server: Default::default(),
248 language_server_watched_paths: Default::default(),
249 language_server_watcher_registrations: Default::default(),
250 next_diagnostic_group_id: Default::default(),
251 diagnostic_summaries: Default::default(),
252 diagnostics: Default::default(),
253 active_entry: None,
254 yarn,
255 _maintain_workspace_config: Self::maintain_workspace_config(cx),
256 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
257 _subscription: cx.on_app_quit(Self::shutdown_language_servers),
258 }
259 }
260
261 fn on_buffer_store_event(
262 &mut self,
263 _: Model<BufferStore>,
264 event: &BufferStoreEvent,
265 cx: &mut ModelContext<Self>,
266 ) {
267 match event {
268 BufferStoreEvent::BufferAdded(buffer) => {
269 self.register_buffer(buffer, cx).log_err();
270 }
271 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
272 if let Some(old_file) = File::from_dyn(old_file.as_ref()) {
273 self.unregister_buffer_from_language_servers(&buffer, old_file, cx);
274 }
275
276 self.detect_language_for_buffer(&buffer, cx);
277 self.register_buffer_with_language_servers(&buffer, cx);
278 }
279 BufferStoreEvent::BufferDropped(_) => {}
280 }
281 }
282
283 fn on_worktree_store_event(
284 &mut self,
285 _: Model<WorktreeStore>,
286 event: &WorktreeStoreEvent,
287 cx: &mut ModelContext<Self>,
288 ) {
289 match event {
290 WorktreeStoreEvent::WorktreeAdded(worktree) => {
291 if !worktree.read(cx).is_local() {
292 return;
293 }
294 cx.subscribe(worktree, |this, worktree, event, cx| match event {
295 worktree::Event::UpdatedEntries(changes) => {
296 this.update_local_worktree_language_servers(&worktree, changes, cx);
297 }
298 worktree::Event::UpdatedGitRepositories(_)
299 | worktree::Event::DeletedEntry(_) => {}
300 })
301 .detach()
302 }
303 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
304 WorktreeStoreEvent::WorktreeOrderChanged => {}
305 }
306 }
307
308 fn on_buffer_event(
309 &mut self,
310 buffer: Model<Buffer>,
311 event: &language::Event,
312 cx: &mut ModelContext<Self>,
313 ) {
314 match event {
315 language::Event::Edited { .. } => {
316 self.on_buffer_edited(buffer, cx);
317 }
318
319 language::Event::Saved => {
320 self.on_buffer_saved(buffer, cx);
321 }
322
323 _ => {}
324 }
325 }
326
327 fn register_buffer(
328 &mut self,
329 buffer: &Model<Buffer>,
330 cx: &mut ModelContext<Self>,
331 ) -> Result<()> {
332 buffer.update(cx, |buffer, _| {
333 buffer.set_language_registry(self.languages.clone())
334 });
335
336 cx.subscribe(buffer, |this, buffer, event, cx| {
337 this.on_buffer_event(buffer, event, cx);
338 })
339 .detach();
340
341 self.detect_language_for_buffer(buffer, cx);
342 self.register_buffer_with_language_servers(buffer, cx);
343 cx.observe_release(buffer, |this, buffer, cx| {
344 if let Some(file) = File::from_dyn(buffer.file()) {
345 if file.is_local() {
346 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
347 for server in this.language_servers_for_buffer(buffer, cx) {
348 server
349 .1
350 .notify::<lsp::notification::DidCloseTextDocument>(
351 lsp::DidCloseTextDocumentParams {
352 text_document: lsp::TextDocumentIdentifier::new(uri.clone()),
353 },
354 )
355 .log_err();
356 }
357 }
358 }
359 })
360 .detach();
361
362 Ok(())
363 }
364
365 fn maintain_buffer_languages(
366 languages: Arc<LanguageRegistry>,
367 cx: &mut ModelContext<Self>,
368 ) -> Task<()> {
369 let mut subscription = languages.subscribe();
370 let mut prev_reload_count = languages.reload_count();
371 cx.spawn(move |this, mut cx| async move {
372 while let Some(()) = subscription.next().await {
373 if let Some(this) = this.upgrade() {
374 // If the language registry has been reloaded, then remove and
375 // re-assign the languages on all open buffers.
376 let reload_count = languages.reload_count();
377 if reload_count > prev_reload_count {
378 prev_reload_count = reload_count;
379 this.update(&mut cx, |this, cx| {
380 this.buffer_store.clone().update(cx, |buffer_store, cx| {
381 for buffer in buffer_store.buffers() {
382 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
383 {
384 this.unregister_buffer_from_language_servers(
385 &buffer, &f, cx,
386 );
387 buffer
388 .update(cx, |buffer, cx| buffer.set_language(None, cx));
389 }
390 }
391 });
392 })
393 .ok();
394 }
395
396 this.update(&mut cx, |this, cx| {
397 let mut plain_text_buffers = Vec::new();
398 let mut buffers_with_unknown_injections = Vec::new();
399 for handle in this.buffer_store.read(cx).buffers() {
400 let buffer = handle.read(cx);
401 if buffer.language().is_none()
402 || buffer.language() == Some(&*language::PLAIN_TEXT)
403 {
404 plain_text_buffers.push(handle);
405 } else if buffer.contains_unknown_injections() {
406 buffers_with_unknown_injections.push(handle);
407 }
408 }
409
410 for buffer in plain_text_buffers {
411 this.detect_language_for_buffer(&buffer, cx);
412 this.register_buffer_with_language_servers(&buffer, cx);
413 }
414
415 for buffer in buffers_with_unknown_injections {
416 buffer.update(cx, |buffer, cx| buffer.reparse(cx));
417 }
418 })
419 .ok();
420 }
421 }
422 })
423 }
424
425 fn detect_language_for_buffer(
426 &mut self,
427 buffer_handle: &Model<Buffer>,
428 cx: &mut ModelContext<Self>,
429 ) {
430 // If the buffer has a language, set it and start the language server if we haven't already.
431 let buffer = buffer_handle.read(cx);
432 let Some(file) = buffer.file() else {
433 return;
434 };
435 let content = buffer.as_rope();
436 let Some(new_language_result) = self
437 .languages
438 .language_for_file(file, Some(content), cx)
439 .now_or_never()
440 else {
441 return;
442 };
443
444 match new_language_result {
445 Err(e) => {
446 if e.is::<language::LanguageNotFound>() {
447 cx.emit(LspStoreEvent::LanguageDetected {
448 buffer: buffer_handle.clone(),
449 new_language: None,
450 });
451 }
452 }
453 Ok(new_language) => {
454 self.set_language_for_buffer(buffer_handle, new_language, cx);
455 }
456 };
457 }
458
459 pub fn set_language_for_buffer(
460 &mut self,
461 buffer: &Model<Buffer>,
462 new_language: Arc<Language>,
463 cx: &mut ModelContext<Self>,
464 ) {
465 buffer.update(cx, |buffer, cx| {
466 if buffer.language().map_or(true, |old_language| {
467 !Arc::ptr_eq(old_language, &new_language)
468 }) {
469 buffer.set_language(Some(new_language.clone()), cx);
470 }
471 });
472
473 let buffer_file = buffer.read(cx).file().cloned();
474 let buffer_file = File::from_dyn(buffer_file.as_ref());
475
476 if let Some(file) = buffer_file {
477 let worktree = file.worktree.clone();
478 if worktree.read(cx).is_local() {
479 self.start_language_servers(&worktree, new_language.clone(), cx)
480 }
481 }
482
483 cx.emit(LspStoreEvent::LanguageDetected {
484 buffer: buffer.clone(),
485 new_language: Some(new_language),
486 })
487 }
488
489 pub fn buffer_store(&self) -> Model<BufferStore> {
490 self.buffer_store.clone()
491 }
492
493 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
494 self.active_entry = active_entry;
495 }
496
497 fn shutdown_language_servers(
498 &mut self,
499 _cx: &mut ModelContext<Self>,
500 ) -> impl Future<Output = ()> {
501 let shutdown_futures = self
502 .language_servers
503 .drain()
504 .map(|(_, server_state)| async {
505 use LanguageServerState::*;
506 match server_state {
507 Running { server, .. } => server.shutdown()?.await,
508 Starting(task) => task.await?.shutdown()?.await,
509 }
510 })
511 .collect::<Vec<_>>();
512
513 async move {
514 futures::future::join_all(shutdown_futures).await;
515 }
516 }
517
518 pub(crate) fn send_diagnostic_summaries(
519 &self,
520 worktree: &mut Worktree,
521 ) -> Result<(), anyhow::Error> {
522 if let Some(client) = self.downstream_client.clone() {
523 if let Some(summaries) = self.diagnostic_summaries.get(&worktree.id()) {
524 for (path, summaries) in summaries {
525 for (&server_id, summary) in summaries {
526 client.send(proto::UpdateDiagnosticSummary {
527 project_id: self.project_id,
528 worktree_id: worktree.id().to_proto(),
529 summary: Some(summary.to_proto(server_id, path)),
530 })?;
531 }
532 }
533 }
534 }
535 Ok(())
536 }
537
538 pub fn request_lsp<R: LspCommand>(
539 &self,
540 buffer_handle: Model<Buffer>,
541 server: LanguageServerToQuery,
542 request: R,
543 cx: &mut ModelContext<Self>,
544 ) -> Task<Result<R::Response>>
545 where
546 <R::LspRequest as lsp::request::Request>::Result: Send,
547 <R::LspRequest as lsp::request::Request>::Params: Send,
548 {
549 let buffer = buffer_handle.read(cx);
550 if self.upstream_client.is_some() {
551 return self.send_lsp_proto_request(buffer_handle, self.project_id, request, cx);
552 }
553 let language_server = match server {
554 LanguageServerToQuery::Primary => {
555 match self.primary_language_server_for_buffer(buffer, cx) {
556 Some((_, server)) => Some(Arc::clone(server)),
557 None => return Task::ready(Ok(Default::default())),
558 }
559 }
560 LanguageServerToQuery::Other(id) => self
561 .language_server_for_buffer(buffer, id, cx)
562 .map(|(_, server)| Arc::clone(server)),
563 };
564 let file = File::from_dyn(buffer.file()).and_then(File::as_local);
565 if let (Some(file), Some(language_server)) = (file, language_server) {
566 let lsp_params = request.to_lsp(&file.abs_path(cx), buffer, &language_server, cx);
567 let status = request.status();
568 return cx.spawn(move |this, cx| async move {
569 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
570 return Ok(Default::default());
571 }
572
573 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
574
575 let id = lsp_request.id();
576 let _cleanup = if status.is_some() {
577 cx.update(|cx| {
578 this.update(cx, |this, cx| {
579 this.on_lsp_work_start(
580 language_server.server_id(),
581 id.to_string(),
582 LanguageServerProgress {
583 is_disk_based_diagnostics_progress: false,
584 is_cancellable: false,
585 title: None,
586 message: status.clone(),
587 percentage: None,
588 last_update_at: cx.background_executor().now(),
589 },
590 cx,
591 );
592 })
593 })
594 .log_err();
595
596 Some(defer(|| {
597 cx.update(|cx| {
598 this.update(cx, |this, cx| {
599 this.on_lsp_work_end(
600 language_server.server_id(),
601 id.to_string(),
602 cx,
603 );
604 })
605 })
606 .log_err();
607 }))
608 } else {
609 None
610 };
611
612 let result = lsp_request.await;
613
614 let response = result.map_err(|err| {
615 log::warn!(
616 "Generic lsp request to {} failed: {}",
617 language_server.name(),
618 err
619 );
620 err
621 })?;
622
623 request
624 .response_from_lsp(
625 response,
626 this.upgrade().ok_or_else(|| anyhow!("no app context"))?,
627 buffer_handle,
628 language_server.server_id(),
629 cx.clone(),
630 )
631 .await
632 });
633 }
634
635 Task::ready(Ok(Default::default()))
636 }
637
638 fn send_lsp_proto_request<R: LspCommand>(
639 &self,
640 buffer: Model<Buffer>,
641 project_id: u64,
642 request: R,
643 cx: &mut ModelContext<'_, Self>,
644 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
645 let Some(upstream_client) = self.upstream_client.clone() else {
646 return Task::ready(Err(anyhow!("disconnected before completing request")));
647 };
648 let message = request.to_proto(project_id, buffer.read(cx));
649 cx.spawn(move |this, cx| async move {
650 let response = upstream_client.request(message).await?;
651 let this = this.upgrade().context("project dropped")?;
652 request
653 .response_from_proto(response, this, buffer, cx)
654 .await
655 })
656 }
657
658 pub async fn execute_code_actions_on_servers(
659 this: &WeakModel<LspStore>,
660 adapters_and_servers: &Vec<(Arc<CachedLspAdapter>, Arc<LanguageServer>)>,
661 code_actions: Vec<lsp::CodeActionKind>,
662 buffer: &Model<Buffer>,
663 push_to_history: bool,
664 project_transaction: &mut ProjectTransaction,
665 cx: &mut AsyncAppContext,
666 ) -> Result<(), anyhow::Error> {
667 for (lsp_adapter, language_server) in adapters_and_servers.iter() {
668 let code_actions = code_actions.clone();
669
670 let actions = this
671 .update(cx, move |this, cx| {
672 let request = GetCodeActions {
673 range: text::Anchor::MIN..text::Anchor::MAX,
674 kinds: Some(code_actions),
675 };
676 let server = LanguageServerToQuery::Other(language_server.server_id());
677 this.request_lsp(buffer.clone(), server, request, cx)
678 })?
679 .await?;
680
681 for mut action in actions {
682 Self::try_resolve_code_action(&language_server, &mut action)
683 .await
684 .context("resolving a formatting code action")?;
685
686 if let Some(edit) = action.lsp_action.edit {
687 if edit.changes.is_none() && edit.document_changes.is_none() {
688 continue;
689 }
690
691 let new = Self::deserialize_workspace_edit(
692 this.upgrade().ok_or_else(|| anyhow!("project dropped"))?,
693 edit,
694 push_to_history,
695 lsp_adapter.clone(),
696 language_server.clone(),
697 cx,
698 )
699 .await?;
700 project_transaction.0.extend(new.0);
701 }
702
703 if let Some(command) = action.lsp_action.command {
704 this.update(cx, |this, _| {
705 this.last_workspace_edits_by_language_server
706 .remove(&language_server.server_id());
707 })?;
708
709 language_server
710 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
711 command: command.command,
712 arguments: command.arguments.unwrap_or_default(),
713 ..Default::default()
714 })
715 .await?;
716
717 this.update(cx, |this, _| {
718 project_transaction.0.extend(
719 this.last_workspace_edits_by_language_server
720 .remove(&language_server.server_id())
721 .unwrap_or_default()
722 .0,
723 )
724 })?;
725 }
726 }
727 }
728
729 Ok(())
730 }
731
732 async fn try_resolve_code_action(
733 lang_server: &LanguageServer,
734 action: &mut CodeAction,
735 ) -> anyhow::Result<()> {
736 if GetCodeActions::can_resolve_actions(&lang_server.capabilities()) {
737 if action.lsp_action.data.is_some()
738 && (action.lsp_action.command.is_none() || action.lsp_action.edit.is_none())
739 {
740 action.lsp_action = lang_server
741 .request::<lsp::request::CodeActionResolveRequest>(action.lsp_action.clone())
742 .await?;
743 }
744 }
745
746 anyhow::Ok(())
747 }
748
749 pub fn apply_code_action(
750 &self,
751 buffer_handle: Model<Buffer>,
752 mut action: CodeAction,
753 push_to_history: bool,
754 cx: &mut ModelContext<Self>,
755 ) -> Task<Result<ProjectTransaction>> {
756 if let Some(upstream_client) = self.upstream_client.clone() {
757 let request = proto::ApplyCodeAction {
758 project_id: self.project_id,
759 buffer_id: buffer_handle.read(cx).remote_id().into(),
760 action: Some(Self::serialize_code_action(&action)),
761 };
762 cx.spawn(move |this, cx| async move {
763 let response = upstream_client
764 .request(request)
765 .await?
766 .transaction
767 .ok_or_else(|| anyhow!("missing transaction"))?;
768 BufferStore::deserialize_project_transaction(
769 this.read_with(&cx, |this, _| this.buffer_store.downgrade())?,
770 response,
771 push_to_history,
772 cx,
773 )
774 .await
775 })
776 } else {
777 let buffer = buffer_handle.read(cx);
778 let (lsp_adapter, lang_server) = if let Some((adapter, server)) =
779 self.language_server_for_buffer(buffer, action.server_id, cx)
780 {
781 (adapter.clone(), server.clone())
782 } else {
783 return Task::ready(Ok(Default::default()));
784 };
785 cx.spawn(move |this, mut cx| async move {
786 Self::try_resolve_code_action(&lang_server, &mut action)
787 .await
788 .context("resolving a code action")?;
789 if let Some(edit) = action.lsp_action.edit {
790 if edit.changes.is_some() || edit.document_changes.is_some() {
791 return Self::deserialize_workspace_edit(
792 this.upgrade().ok_or_else(|| anyhow!("no app present"))?,
793 edit,
794 push_to_history,
795 lsp_adapter.clone(),
796 lang_server.clone(),
797 &mut cx,
798 )
799 .await;
800 }
801 }
802
803 if let Some(command) = action.lsp_action.command {
804 this.update(&mut cx, |this, _| {
805 this.last_workspace_edits_by_language_server
806 .remove(&lang_server.server_id());
807 })?;
808
809 let result = lang_server
810 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
811 command: command.command,
812 arguments: command.arguments.unwrap_or_default(),
813 ..Default::default()
814 })
815 .await;
816
817 if let Err(err) = result {
818 // TODO: LSP ERROR
819 return Err(err);
820 }
821
822 return this.update(&mut cx, |this, _| {
823 this.last_workspace_edits_by_language_server
824 .remove(&lang_server.server_id())
825 .unwrap_or_default()
826 });
827 }
828
829 Ok(ProjectTransaction::default())
830 })
831 }
832 }
833
834 pub fn resolve_inlay_hint(
835 &self,
836 hint: InlayHint,
837 buffer_handle: Model<Buffer>,
838 server_id: LanguageServerId,
839 cx: &mut ModelContext<Self>,
840 ) -> Task<anyhow::Result<InlayHint>> {
841 if let Some(upstream_client) = self.upstream_client.clone() {
842 let request = proto::ResolveInlayHint {
843 project_id: self.project_id,
844 buffer_id: buffer_handle.read(cx).remote_id().into(),
845 language_server_id: server_id.0 as u64,
846 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
847 };
848 cx.spawn(move |_, _| async move {
849 let response = upstream_client
850 .request(request)
851 .await
852 .context("inlay hints proto request")?;
853 match response.hint {
854 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
855 .context("inlay hints proto resolve response conversion"),
856 None => Ok(hint),
857 }
858 })
859 } else {
860 let buffer = buffer_handle.read(cx);
861 let (_, lang_server) = if let Some((adapter, server)) =
862 self.language_server_for_buffer(buffer, server_id, cx)
863 {
864 (adapter.clone(), server.clone())
865 } else {
866 return Task::ready(Ok(hint));
867 };
868 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
869 return Task::ready(Ok(hint));
870 }
871
872 let buffer_snapshot = buffer.snapshot();
873 cx.spawn(move |_, mut cx| async move {
874 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
875 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
876 );
877 let resolved_hint = resolve_task
878 .await
879 .context("inlay hint resolve LSP request")?;
880 let resolved_hint = InlayHints::lsp_to_project_hint(
881 resolved_hint,
882 &buffer_handle,
883 server_id,
884 ResolveState::Resolved,
885 false,
886 &mut cx,
887 )
888 .await?;
889 Ok(resolved_hint)
890 })
891 }
892 }
893
894 pub(crate) fn linked_edit(
895 &self,
896 buffer: &Model<Buffer>,
897 position: Anchor,
898 cx: &mut ModelContext<Self>,
899 ) -> Task<Result<Vec<Range<Anchor>>>> {
900 let snapshot = buffer.read(cx).snapshot();
901 let scope = snapshot.language_scope_at(position);
902 let Some(server_id) = self
903 .language_servers_for_buffer(buffer.read(cx), cx)
904 .filter(|(_, server)| {
905 server
906 .capabilities()
907 .linked_editing_range_provider
908 .is_some()
909 })
910 .filter(|(adapter, _)| {
911 scope
912 .as_ref()
913 .map(|scope| scope.language_allowed(&adapter.name))
914 .unwrap_or(true)
915 })
916 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
917 .next()
918 .or_else(|| {
919 self.upstream_client
920 .is_some()
921 .then_some(LanguageServerToQuery::Primary)
922 })
923 .filter(|_| {
924 maybe!({
925 let language_name = buffer.read(cx).language_at(position)?.name();
926 Some(
927 AllLanguageSettings::get_global(cx)
928 .language(Some(&language_name))
929 .linked_edits,
930 )
931 }) == Some(true)
932 })
933 else {
934 return Task::ready(Ok(vec![]));
935 };
936
937 self.request_lsp(
938 buffer.clone(),
939 server_id,
940 LinkedEditingRange { position },
941 cx,
942 )
943 }
944
945 fn apply_on_type_formatting(
946 &self,
947 buffer: Model<Buffer>,
948 position: Anchor,
949 trigger: String,
950 cx: &mut ModelContext<Self>,
951 ) -> Task<Result<Option<Transaction>>> {
952 if let Some(client) = self.upstream_client.clone() {
953 let request = proto::OnTypeFormatting {
954 project_id: self.project_id,
955 buffer_id: buffer.read(cx).remote_id().into(),
956 position: Some(serialize_anchor(&position)),
957 trigger,
958 version: serialize_version(&buffer.read(cx).version()),
959 };
960 cx.spawn(move |_, _| async move {
961 client
962 .request(request)
963 .await?
964 .transaction
965 .map(language::proto::deserialize_transaction)
966 .transpose()
967 })
968 } else {
969 cx.spawn(move |this, mut cx| async move {
970 // Do not allow multiple concurrent formatting requests for the
971 // same buffer.
972 this.update(&mut cx, |_, cx| {
973 cx.emit(LspStoreEvent::StartFormattingLocalBuffer(
974 buffer.read(cx).remote_id(),
975 ));
976 })?;
977
978 let _cleanup = defer({
979 let this = this.clone();
980 let mut cx = cx.clone();
981 let closure_buffer = buffer.clone();
982 move || {
983 this.update(&mut cx, |_, cx| {
984 cx.emit(LspStoreEvent::FinishFormattingLocalBuffer(
985 closure_buffer.read(cx).remote_id(),
986 ))
987 })
988 .ok();
989 }
990 });
991
992 buffer
993 .update(&mut cx, |buffer, _| {
994 buffer.wait_for_edits(Some(position.timestamp))
995 })?
996 .await?;
997 this.update(&mut cx, |this, cx| {
998 let position = position.to_point_utf16(buffer.read(cx));
999 this.on_type_format(buffer, position, trigger, false, cx)
1000 })?
1001 .await
1002 })
1003 }
1004 }
1005
1006 pub fn on_type_format<T: ToPointUtf16>(
1007 &mut self,
1008 buffer: Model<Buffer>,
1009 position: T,
1010 trigger: String,
1011 push_to_history: bool,
1012 cx: &mut ModelContext<Self>,
1013 ) -> Task<Result<Option<Transaction>>> {
1014 let position = position.to_point_utf16(buffer.read(cx));
1015 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
1016 }
1017
1018 fn on_type_format_impl(
1019 &mut self,
1020 buffer: Model<Buffer>,
1021 position: PointUtf16,
1022 trigger: String,
1023 push_to_history: bool,
1024 cx: &mut ModelContext<Self>,
1025 ) -> Task<Result<Option<Transaction>>> {
1026 let options = buffer.update(cx, |buffer, cx| {
1027 lsp_command::lsp_formatting_options(language_settings(
1028 buffer.language_at(position).as_ref(),
1029 buffer.file(),
1030 cx,
1031 ))
1032 });
1033 self.request_lsp(
1034 buffer.clone(),
1035 LanguageServerToQuery::Primary,
1036 OnTypeFormatting {
1037 position,
1038 trigger,
1039 options,
1040 push_to_history,
1041 },
1042 cx,
1043 )
1044 }
1045
1046 pub async fn format_via_lsp(
1047 this: &WeakModel<Self>,
1048 buffer: &Model<Buffer>,
1049 abs_path: &Path,
1050 language_server: &Arc<LanguageServer>,
1051 settings: &LanguageSettings,
1052 cx: &mut AsyncAppContext,
1053 ) -> Result<Vec<(Range<Anchor>, String)>> {
1054 let uri = lsp::Url::from_file_path(abs_path)
1055 .map_err(|_| anyhow!("failed to convert abs path to uri"))?;
1056 let text_document = lsp::TextDocumentIdentifier::new(uri);
1057 let capabilities = &language_server.capabilities();
1058
1059 let formatting_provider = capabilities.document_formatting_provider.as_ref();
1060 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
1061
1062 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1063 language_server
1064 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
1065 text_document,
1066 options: lsp_command::lsp_formatting_options(settings),
1067 work_done_progress_params: Default::default(),
1068 })
1069 .await?
1070 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
1071 let buffer_start = lsp::Position::new(0, 0);
1072 let buffer_end = buffer.update(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
1073
1074 language_server
1075 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
1076 text_document,
1077 range: lsp::Range::new(buffer_start, buffer_end),
1078 options: lsp_command::lsp_formatting_options(settings),
1079 work_done_progress_params: Default::default(),
1080 })
1081 .await?
1082 } else {
1083 None
1084 };
1085
1086 if let Some(lsp_edits) = lsp_edits {
1087 this.update(cx, |this, cx| {
1088 this.edits_from_lsp(buffer, lsp_edits, language_server.server_id(), None, cx)
1089 })?
1090 .await
1091 } else {
1092 Ok(Vec::new())
1093 }
1094 }
1095
1096 pub fn code_actions(
1097 &mut self,
1098 buffer_handle: &Model<Buffer>,
1099 range: Range<Anchor>,
1100 cx: &mut ModelContext<Self>,
1101 ) -> Task<Vec<CodeAction>> {
1102 if let Some(upstream_client) = self.upstream_client.as_ref() {
1103 let request_task = upstream_client.request(proto::MultiLspQuery {
1104 buffer_id: buffer_handle.read(cx).remote_id().into(),
1105 version: serialize_version(&buffer_handle.read(cx).version()),
1106 project_id: self.project_id,
1107 strategy: Some(proto::multi_lsp_query::Strategy::All(
1108 proto::AllLanguageServers {},
1109 )),
1110 request: Some(proto::multi_lsp_query::Request::GetCodeActions(
1111 GetCodeActions {
1112 range: range.clone(),
1113 kinds: None,
1114 }
1115 .to_proto(self.project_id, buffer_handle.read(cx)),
1116 )),
1117 });
1118 let buffer = buffer_handle.clone();
1119 cx.spawn(|weak_project, cx| async move {
1120 let Some(project) = weak_project.upgrade() else {
1121 return Vec::new();
1122 };
1123 join_all(
1124 request_task
1125 .await
1126 .log_err()
1127 .map(|response| response.responses)
1128 .unwrap_or_default()
1129 .into_iter()
1130 .filter_map(|lsp_response| match lsp_response.response? {
1131 proto::lsp_response::Response::GetCodeActionsResponse(response) => {
1132 Some(response)
1133 }
1134 unexpected => {
1135 debug_panic!("Unexpected response: {unexpected:?}");
1136 None
1137 }
1138 })
1139 .map(|code_actions_response| {
1140 let response = GetCodeActions {
1141 range: range.clone(),
1142 kinds: None,
1143 }
1144 .response_from_proto(
1145 code_actions_response,
1146 project.clone(),
1147 buffer.clone(),
1148 cx.clone(),
1149 );
1150 async move { response.await.log_err().unwrap_or_default() }
1151 }),
1152 )
1153 .await
1154 .into_iter()
1155 .flatten()
1156 .collect()
1157 })
1158 } else {
1159 let all_actions_task = self.request_multiple_lsp_locally(
1160 &buffer_handle,
1161 Some(range.start),
1162 GetCodeActions {
1163 range: range.clone(),
1164 kinds: None,
1165 },
1166 cx,
1167 );
1168 cx.spawn(|_, _| async move { all_actions_task.await.into_iter().flatten().collect() })
1169 }
1170 }
1171
1172 #[inline(never)]
1173 pub fn completions(
1174 &self,
1175 buffer: &Model<Buffer>,
1176 position: PointUtf16,
1177 context: CompletionContext,
1178 cx: &mut ModelContext<Self>,
1179 ) -> Task<Result<Vec<Completion>>> {
1180 let language_registry = self.languages.clone();
1181
1182 if let Some(_) = self.upstream_client.clone() {
1183 let task = self.send_lsp_proto_request(
1184 buffer.clone(),
1185 self.project_id,
1186 GetCompletions { position, context },
1187 cx,
1188 );
1189 let language = buffer.read(cx).language().cloned();
1190
1191 // In the future, we should provide project guests with the names of LSP adapters,
1192 // so that they can use the correct LSP adapter when computing labels. For now,
1193 // guests just use the first LSP adapter associated with the buffer's language.
1194 let lsp_adapter = language
1195 .as_ref()
1196 .and_then(|language| language_registry.lsp_adapters(language).first().cloned());
1197
1198 cx.foreground_executor().spawn(async move {
1199 let completions = task.await?;
1200 let mut result = Vec::new();
1201 populate_labels_for_completions(
1202 completions,
1203 &language_registry,
1204 language,
1205 lsp_adapter,
1206 &mut result,
1207 )
1208 .await;
1209 Ok(result)
1210 })
1211 } else {
1212 let snapshot = buffer.read(cx).snapshot();
1213 let offset = position.to_offset(&snapshot);
1214 let scope = snapshot.language_scope_at(offset);
1215 let language = snapshot.language().cloned();
1216
1217 let server_ids: Vec<_> = self
1218 .language_servers_for_buffer(buffer.read(cx), cx)
1219 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
1220 .filter(|(adapter, _)| {
1221 scope
1222 .as_ref()
1223 .map(|scope| scope.language_allowed(&adapter.name))
1224 .unwrap_or(true)
1225 })
1226 .map(|(_, server)| server.server_id())
1227 .collect();
1228
1229 let buffer = buffer.clone();
1230 cx.spawn(move |this, mut cx| async move {
1231 let mut tasks = Vec::with_capacity(server_ids.len());
1232 this.update(&mut cx, |this, cx| {
1233 for server_id in server_ids {
1234 let lsp_adapter = this.language_server_adapter_for_id(server_id);
1235 tasks.push((
1236 lsp_adapter,
1237 this.request_lsp(
1238 buffer.clone(),
1239 LanguageServerToQuery::Other(server_id),
1240 GetCompletions {
1241 position,
1242 context: context.clone(),
1243 },
1244 cx,
1245 ),
1246 ));
1247 }
1248 })?;
1249
1250 let mut completions = Vec::new();
1251 for (lsp_adapter, task) in tasks {
1252 if let Ok(new_completions) = task.await {
1253 populate_labels_for_completions(
1254 new_completions,
1255 &language_registry,
1256 language.clone(),
1257 lsp_adapter,
1258 &mut completions,
1259 )
1260 .await;
1261 }
1262 }
1263
1264 Ok(completions)
1265 })
1266 }
1267 }
1268
1269 pub fn resolve_completions(
1270 &self,
1271 buffer: Model<Buffer>,
1272 completion_indices: Vec<usize>,
1273 completions: Arc<RwLock<Box<[Completion]>>>,
1274 cx: &mut ModelContext<Self>,
1275 ) -> Task<Result<bool>> {
1276 let client = self.upstream_client.clone();
1277 let language_registry = self.languages.clone();
1278 let project_id = self.project_id;
1279
1280 let buffer_id = buffer.read(cx).remote_id();
1281 let buffer_snapshot = buffer.read(cx).snapshot();
1282
1283 cx.spawn(move |this, mut cx| async move {
1284 let mut did_resolve = false;
1285 if let Some(client) = client {
1286 for completion_index in completion_indices {
1287 let (server_id, completion) = {
1288 let completions_guard = completions.read();
1289 let completion = &completions_guard[completion_index];
1290 if completion.documentation.is_some() {
1291 continue;
1292 }
1293
1294 did_resolve = true;
1295 let server_id = completion.server_id;
1296 let completion = completion.lsp_completion.clone();
1297
1298 (server_id, completion)
1299 };
1300
1301 Self::resolve_completion_remote(
1302 project_id,
1303 server_id,
1304 buffer_id,
1305 completions.clone(),
1306 completion_index,
1307 completion,
1308 client.clone(),
1309 language_registry.clone(),
1310 )
1311 .await;
1312 }
1313 } else {
1314 for completion_index in completion_indices {
1315 let (server_id, completion) = {
1316 let completions_guard = completions.read();
1317 let completion = &completions_guard[completion_index];
1318 if completion.documentation.is_some() {
1319 continue;
1320 }
1321
1322 let server_id = completion.server_id;
1323 let completion = completion.lsp_completion.clone();
1324
1325 (server_id, completion)
1326 };
1327
1328 let server = this
1329 .read_with(&mut cx, |this, _| this.language_server_for_id(server_id))
1330 .ok()
1331 .flatten();
1332 let Some(server) = server else {
1333 continue;
1334 };
1335
1336 did_resolve = true;
1337 Self::resolve_completion_local(
1338 server,
1339 &buffer_snapshot,
1340 completions.clone(),
1341 completion_index,
1342 completion,
1343 language_registry.clone(),
1344 )
1345 .await;
1346 }
1347 }
1348
1349 Ok(did_resolve)
1350 })
1351 }
1352
1353 async fn resolve_completion_local(
1354 server: Arc<lsp::LanguageServer>,
1355 snapshot: &BufferSnapshot,
1356 completions: Arc<RwLock<Box<[Completion]>>>,
1357 completion_index: usize,
1358 completion: lsp::CompletionItem,
1359 language_registry: Arc<LanguageRegistry>,
1360 ) {
1361 let can_resolve = server
1362 .capabilities()
1363 .completion_provider
1364 .as_ref()
1365 .and_then(|options| options.resolve_provider)
1366 .unwrap_or(false);
1367 if !can_resolve {
1368 return;
1369 }
1370
1371 let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
1372 let Some(completion_item) = request.await.log_err() else {
1373 return;
1374 };
1375
1376 if let Some(lsp_documentation) = completion_item.documentation.as_ref() {
1377 let documentation = language::prepare_completion_documentation(
1378 lsp_documentation,
1379 &language_registry,
1380 None, // TODO: Try to reasonably work out which language the completion is for
1381 )
1382 .await;
1383
1384 let mut completions = completions.write();
1385 let completion = &mut completions[completion_index];
1386 completion.documentation = Some(documentation);
1387 } else {
1388 let mut completions = completions.write();
1389 let completion = &mut completions[completion_index];
1390 completion.documentation = Some(Documentation::Undocumented);
1391 }
1392
1393 if let Some(text_edit) = completion_item.text_edit.as_ref() {
1394 // Technically we don't have to parse the whole `text_edit`, since the only
1395 // language server we currently use that does update `text_edit` in `completionItem/resolve`
1396 // is `typescript-language-server` and they only update `text_edit.new_text`.
1397 // But we should not rely on that.
1398 let edit = parse_completion_text_edit(text_edit, snapshot);
1399
1400 if let Some((old_range, mut new_text)) = edit {
1401 LineEnding::normalize(&mut new_text);
1402
1403 let mut completions = completions.write();
1404 let completion = &mut completions[completion_index];
1405
1406 completion.new_text = new_text;
1407 completion.old_range = old_range;
1408 }
1409 }
1410 if completion_item.insert_text_format == Some(InsertTextFormat::SNIPPET) {
1411 // vtsls might change the type of completion after resolution.
1412 let mut completions = completions.write();
1413 let completion = &mut completions[completion_index];
1414 if completion_item.insert_text_format != completion.lsp_completion.insert_text_format {
1415 completion.lsp_completion.insert_text_format = completion_item.insert_text_format;
1416 }
1417 }
1418 }
1419
1420 #[allow(clippy::too_many_arguments)]
1421 async fn resolve_completion_remote(
1422 project_id: u64,
1423 server_id: LanguageServerId,
1424 buffer_id: BufferId,
1425 completions: Arc<RwLock<Box<[Completion]>>>,
1426 completion_index: usize,
1427 completion: lsp::CompletionItem,
1428 client: AnyProtoClient,
1429 language_registry: Arc<LanguageRegistry>,
1430 ) {
1431 let request = proto::ResolveCompletionDocumentation {
1432 project_id,
1433 language_server_id: server_id.0 as u64,
1434 lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
1435 buffer_id: buffer_id.into(),
1436 };
1437
1438 let Some(response) = client
1439 .request(request)
1440 .await
1441 .context("completion documentation resolve proto request")
1442 .log_err()
1443 else {
1444 return;
1445 };
1446
1447 let documentation = if response.documentation.is_empty() {
1448 Documentation::Undocumented
1449 } else if response.documentation_is_markdown {
1450 Documentation::MultiLineMarkdown(
1451 markdown::parse_markdown(&response.documentation, &language_registry, None).await,
1452 )
1453 } else if response.documentation.lines().count() <= 1 {
1454 Documentation::SingleLine(response.documentation)
1455 } else {
1456 Documentation::MultiLinePlainText(response.documentation)
1457 };
1458
1459 let mut completions = completions.write();
1460 let completion = &mut completions[completion_index];
1461 completion.documentation = Some(documentation);
1462
1463 let old_range = response
1464 .old_start
1465 .and_then(deserialize_anchor)
1466 .zip(response.old_end.and_then(deserialize_anchor));
1467 if let Some((old_start, old_end)) = old_range {
1468 if !response.new_text.is_empty() {
1469 completion.new_text = response.new_text;
1470 completion.old_range = old_start..old_end;
1471 }
1472 }
1473 }
1474
1475 pub fn apply_additional_edits_for_completion(
1476 &self,
1477 buffer_handle: Model<Buffer>,
1478 completion: Completion,
1479 push_to_history: bool,
1480 cx: &mut ModelContext<Self>,
1481 ) -> Task<Result<Option<Transaction>>> {
1482 let buffer = buffer_handle.read(cx);
1483 let buffer_id = buffer.remote_id();
1484
1485 if let Some(client) = self.upstream_client.clone() {
1486 let project_id = self.project_id;
1487 cx.spawn(move |_, mut cx| async move {
1488 let response = client
1489 .request(proto::ApplyCompletionAdditionalEdits {
1490 project_id,
1491 buffer_id: buffer_id.into(),
1492 completion: Some(Self::serialize_completion(&CoreCompletion {
1493 old_range: completion.old_range,
1494 new_text: completion.new_text,
1495 server_id: completion.server_id,
1496 lsp_completion: completion.lsp_completion,
1497 })),
1498 })
1499 .await?;
1500
1501 if let Some(transaction) = response.transaction {
1502 let transaction = language::proto::deserialize_transaction(transaction)?;
1503 buffer_handle
1504 .update(&mut cx, |buffer, _| {
1505 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
1506 })?
1507 .await?;
1508 if push_to_history {
1509 buffer_handle.update(&mut cx, |buffer, _| {
1510 buffer.push_transaction(transaction.clone(), Instant::now());
1511 })?;
1512 }
1513 Ok(Some(transaction))
1514 } else {
1515 Ok(None)
1516 }
1517 })
1518 } else {
1519 let server_id = completion.server_id;
1520 let lang_server = match self.language_server_for_buffer(buffer, server_id, cx) {
1521 Some((_, server)) => server.clone(),
1522 _ => return Task::ready(Ok(Default::default())),
1523 };
1524
1525 cx.spawn(move |this, mut cx| async move {
1526 let can_resolve = lang_server
1527 .capabilities()
1528 .completion_provider
1529 .as_ref()
1530 .and_then(|options| options.resolve_provider)
1531 .unwrap_or(false);
1532 let additional_text_edits = if can_resolve {
1533 lang_server
1534 .request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
1535 .await?
1536 .additional_text_edits
1537 } else {
1538 completion.lsp_completion.additional_text_edits
1539 };
1540 if let Some(edits) = additional_text_edits {
1541 let edits = this
1542 .update(&mut cx, |this, cx| {
1543 this.edits_from_lsp(
1544 &buffer_handle,
1545 edits,
1546 lang_server.server_id(),
1547 None,
1548 cx,
1549 )
1550 })?
1551 .await?;
1552
1553 buffer_handle.update(&mut cx, |buffer, cx| {
1554 buffer.finalize_last_transaction();
1555 buffer.start_transaction();
1556
1557 for (range, text) in edits {
1558 let primary = &completion.old_range;
1559 let start_within = primary.start.cmp(&range.start, buffer).is_le()
1560 && primary.end.cmp(&range.start, buffer).is_ge();
1561 let end_within = range.start.cmp(&primary.end, buffer).is_le()
1562 && range.end.cmp(&primary.end, buffer).is_ge();
1563
1564 //Skip additional edits which overlap with the primary completion edit
1565 //https://github.com/zed-industries/zed/pull/1871
1566 if !start_within && !end_within {
1567 buffer.edit([(range, text)], None, cx);
1568 }
1569 }
1570
1571 let transaction = if buffer.end_transaction(cx).is_some() {
1572 let transaction = buffer.finalize_last_transaction().unwrap().clone();
1573 if !push_to_history {
1574 buffer.forget_transaction(transaction.id);
1575 }
1576 Some(transaction)
1577 } else {
1578 None
1579 };
1580 Ok(transaction)
1581 })?
1582 } else {
1583 Ok(None)
1584 }
1585 })
1586 }
1587 }
1588
1589 pub fn inlay_hints(
1590 &mut self,
1591 buffer_handle: Model<Buffer>,
1592 range: Range<Anchor>,
1593 cx: &mut ModelContext<Self>,
1594 ) -> Task<anyhow::Result<Vec<InlayHint>>> {
1595 let buffer = buffer_handle.read(cx);
1596 let range_start = range.start;
1597 let range_end = range.end;
1598 let buffer_id = buffer.remote_id().into();
1599 let lsp_request = InlayHints { range };
1600
1601 if let Some(client) = self.upstream_client.clone() {
1602 let request = proto::InlayHints {
1603 project_id: self.project_id,
1604 buffer_id,
1605 start: Some(serialize_anchor(&range_start)),
1606 end: Some(serialize_anchor(&range_end)),
1607 version: serialize_version(&buffer_handle.read(cx).version()),
1608 };
1609 cx.spawn(move |project, cx| async move {
1610 let response = client
1611 .request(request)
1612 .await
1613 .context("inlay hints proto request")?;
1614 LspCommand::response_from_proto(
1615 lsp_request,
1616 response,
1617 project.upgrade().ok_or_else(|| anyhow!("No project"))?,
1618 buffer_handle.clone(),
1619 cx.clone(),
1620 )
1621 .await
1622 .context("inlay hints proto response conversion")
1623 })
1624 } else {
1625 let lsp_request_task = self.request_lsp(
1626 buffer_handle.clone(),
1627 LanguageServerToQuery::Primary,
1628 lsp_request,
1629 cx,
1630 );
1631 cx.spawn(move |_, mut cx| async move {
1632 buffer_handle
1633 .update(&mut cx, |buffer, _| {
1634 buffer.wait_for_edits(vec![range_start.timestamp, range_end.timestamp])
1635 })?
1636 .await
1637 .context("waiting for inlay hint request range edits")?;
1638 lsp_request_task.await.context("inlay hints LSP request")
1639 })
1640 }
1641 }
1642
1643 pub fn signature_help<T: ToPointUtf16>(
1644 &self,
1645 buffer: &Model<Buffer>,
1646 position: T,
1647 cx: &mut ModelContext<Self>,
1648 ) -> Task<Vec<SignatureHelp>> {
1649 let position = position.to_point_utf16(buffer.read(cx));
1650
1651 if let Some(client) = self.upstream_client.clone() {
1652 let request_task = client.request(proto::MultiLspQuery {
1653 buffer_id: buffer.read(cx).remote_id().into(),
1654 version: serialize_version(&buffer.read(cx).version()),
1655 project_id: self.project_id,
1656 strategy: Some(proto::multi_lsp_query::Strategy::All(
1657 proto::AllLanguageServers {},
1658 )),
1659 request: Some(proto::multi_lsp_query::Request::GetSignatureHelp(
1660 GetSignatureHelp { position }.to_proto(self.project_id, buffer.read(cx)),
1661 )),
1662 });
1663 let buffer = buffer.clone();
1664 cx.spawn(|weak_project, cx| async move {
1665 let Some(project) = weak_project.upgrade() else {
1666 return Vec::new();
1667 };
1668 join_all(
1669 request_task
1670 .await
1671 .log_err()
1672 .map(|response| response.responses)
1673 .unwrap_or_default()
1674 .into_iter()
1675 .filter_map(|lsp_response| match lsp_response.response? {
1676 proto::lsp_response::Response::GetSignatureHelpResponse(response) => {
1677 Some(response)
1678 }
1679 unexpected => {
1680 debug_panic!("Unexpected response: {unexpected:?}");
1681 None
1682 }
1683 })
1684 .map(|signature_response| {
1685 let response = GetSignatureHelp { position }.response_from_proto(
1686 signature_response,
1687 project.clone(),
1688 buffer.clone(),
1689 cx.clone(),
1690 );
1691 async move { response.await.log_err().flatten() }
1692 }),
1693 )
1694 .await
1695 .into_iter()
1696 .flatten()
1697 .collect()
1698 })
1699 } else {
1700 let all_actions_task = self.request_multiple_lsp_locally(
1701 buffer,
1702 Some(position),
1703 GetSignatureHelp { position },
1704 cx,
1705 );
1706 cx.spawn(|_, _| async move {
1707 all_actions_task
1708 .await
1709 .into_iter()
1710 .flatten()
1711 .filter(|help| !help.markdown.is_empty())
1712 .collect::<Vec<_>>()
1713 })
1714 }
1715 }
1716
1717 pub fn hover(
1718 &self,
1719 buffer: &Model<Buffer>,
1720 position: PointUtf16,
1721 cx: &mut ModelContext<Self>,
1722 ) -> Task<Vec<Hover>> {
1723 if let Some(client) = self.upstream_client.clone() {
1724 let request_task = client.request(proto::MultiLspQuery {
1725 buffer_id: buffer.read(cx).remote_id().into(),
1726 version: serialize_version(&buffer.read(cx).version()),
1727 project_id: self.project_id,
1728 strategy: Some(proto::multi_lsp_query::Strategy::All(
1729 proto::AllLanguageServers {},
1730 )),
1731 request: Some(proto::multi_lsp_query::Request::GetHover(
1732 GetHover { position }.to_proto(self.project_id, buffer.read(cx)),
1733 )),
1734 });
1735 let buffer = buffer.clone();
1736 cx.spawn(|weak_project, cx| async move {
1737 let Some(project) = weak_project.upgrade() else {
1738 return Vec::new();
1739 };
1740 join_all(
1741 request_task
1742 .await
1743 .log_err()
1744 .map(|response| response.responses)
1745 .unwrap_or_default()
1746 .into_iter()
1747 .filter_map(|lsp_response| match lsp_response.response? {
1748 proto::lsp_response::Response::GetHoverResponse(response) => {
1749 Some(response)
1750 }
1751 unexpected => {
1752 debug_panic!("Unexpected response: {unexpected:?}");
1753 None
1754 }
1755 })
1756 .map(|hover_response| {
1757 let response = GetHover { position }.response_from_proto(
1758 hover_response,
1759 project.clone(),
1760 buffer.clone(),
1761 cx.clone(),
1762 );
1763 async move {
1764 response
1765 .await
1766 .log_err()
1767 .flatten()
1768 .and_then(remove_empty_hover_blocks)
1769 }
1770 }),
1771 )
1772 .await
1773 .into_iter()
1774 .flatten()
1775 .collect()
1776 })
1777 } else {
1778 let all_actions_task = self.request_multiple_lsp_locally(
1779 &buffer,
1780 Some(position),
1781 GetHover { position },
1782 cx,
1783 );
1784 cx.spawn(|_, _| async move {
1785 all_actions_task
1786 .await
1787 .into_iter()
1788 .filter_map(|hover| remove_empty_hover_blocks(hover?))
1789 .collect::<Vec<Hover>>()
1790 })
1791 }
1792 }
1793
1794 pub fn symbols(&self, query: &str, cx: &mut ModelContext<Self>) -> Task<Result<Vec<Symbol>>> {
1795 let language_registry = self.languages.clone();
1796
1797 if let Some(upstream_client) = self.upstream_client.as_ref() {
1798 let request = upstream_client.request(proto::GetProjectSymbols {
1799 project_id: self.project_id,
1800 query: query.to_string(),
1801 });
1802 cx.foreground_executor().spawn(async move {
1803 let response = request.await?;
1804 let mut symbols = Vec::new();
1805 let core_symbols = response
1806 .symbols
1807 .into_iter()
1808 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
1809 .collect::<Vec<_>>();
1810 populate_labels_for_symbols(
1811 core_symbols,
1812 &language_registry,
1813 None,
1814 None,
1815 &mut symbols,
1816 )
1817 .await;
1818 Ok(symbols)
1819 })
1820 } else {
1821 struct WorkspaceSymbolsResult {
1822 lsp_adapter: Arc<CachedLspAdapter>,
1823 language: Arc<Language>,
1824 worktree: WeakModel<Worktree>,
1825 worktree_abs_path: Arc<Path>,
1826 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
1827 }
1828
1829 let mut requests = Vec::new();
1830 for ((worktree_id, _), server_id) in self.language_server_ids.iter() {
1831 let Some(worktree_handle) = self
1832 .worktree_store
1833 .read(cx)
1834 .worktree_for_id(*worktree_id, cx)
1835 else {
1836 continue;
1837 };
1838 let worktree = worktree_handle.read(cx);
1839 if !worktree.is_visible() {
1840 continue;
1841 }
1842 let worktree_abs_path = worktree.abs_path().clone();
1843
1844 let (lsp_adapter, language, server) = match self.language_servers.get(server_id) {
1845 Some(LanguageServerState::Running {
1846 adapter,
1847 language,
1848 server,
1849 ..
1850 }) => (adapter.clone(), language.clone(), server),
1851
1852 _ => continue,
1853 };
1854
1855 requests.push(
1856 server
1857 .request::<lsp::request::WorkspaceSymbolRequest>(
1858 lsp::WorkspaceSymbolParams {
1859 query: query.to_string(),
1860 ..Default::default()
1861 },
1862 )
1863 .log_err()
1864 .map(move |response| {
1865 let lsp_symbols = response.flatten().map(|symbol_response| match symbol_response {
1866 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
1867 flat_responses.into_iter().map(|lsp_symbol| {
1868 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
1869 }).collect::<Vec<_>>()
1870 }
1871 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
1872 nested_responses.into_iter().filter_map(|lsp_symbol| {
1873 let location = match lsp_symbol.location {
1874 OneOf::Left(location) => location,
1875 OneOf::Right(_) => {
1876 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
1877 return None
1878 }
1879 };
1880 Some((lsp_symbol.name, lsp_symbol.kind, location))
1881 }).collect::<Vec<_>>()
1882 }
1883 }).unwrap_or_default();
1884
1885 WorkspaceSymbolsResult {
1886 lsp_adapter,
1887 language,
1888 worktree: worktree_handle.downgrade(),
1889 worktree_abs_path,
1890 lsp_symbols,
1891 }
1892 }),
1893 );
1894 }
1895
1896 cx.spawn(move |this, mut cx| async move {
1897 let responses = futures::future::join_all(requests).await;
1898 let this = match this.upgrade() {
1899 Some(this) => this,
1900 None => return Ok(Vec::new()),
1901 };
1902
1903 let mut symbols = Vec::new();
1904 for result in responses {
1905 let core_symbols = this.update(&mut cx, |this, cx| {
1906 result
1907 .lsp_symbols
1908 .into_iter()
1909 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
1910 let abs_path = symbol_location.uri.to_file_path().ok()?;
1911 let source_worktree = result.worktree.upgrade()?;
1912 let source_worktree_id = source_worktree.read(cx).id();
1913
1914 let path;
1915 let worktree;
1916 if let Some((tree, rel_path)) =
1917 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
1918 {
1919 worktree = tree;
1920 path = rel_path;
1921 } else {
1922 worktree = source_worktree.clone();
1923 path = relativize_path(&result.worktree_abs_path, &abs_path);
1924 }
1925
1926 let worktree_id = worktree.read(cx).id();
1927 let project_path = ProjectPath {
1928 worktree_id,
1929 path: path.into(),
1930 };
1931 let signature = this.symbol_signature(&project_path);
1932 Some(CoreSymbol {
1933 language_server_name: result.lsp_adapter.name.clone(),
1934 source_worktree_id,
1935 path: project_path,
1936 kind: symbol_kind,
1937 name: symbol_name,
1938 range: range_from_lsp(symbol_location.range),
1939 signature,
1940 })
1941 })
1942 .collect()
1943 })?;
1944
1945 populate_labels_for_symbols(
1946 core_symbols,
1947 &language_registry,
1948 Some(result.language),
1949 Some(result.lsp_adapter),
1950 &mut symbols,
1951 )
1952 .await;
1953 }
1954
1955 Ok(symbols)
1956 })
1957 }
1958 }
1959
1960 pub fn diagnostic_summaries<'a>(
1961 &'a self,
1962 include_ignored: bool,
1963 cx: &'a AppContext,
1964 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
1965 self.worktree_store
1966 .read(cx)
1967 .visible_worktrees(cx)
1968 .filter_map(|worktree| {
1969 let worktree = worktree.read(cx);
1970 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
1971 })
1972 .flat_map(move |(worktree, summaries)| {
1973 let worktree_id = worktree.id();
1974 summaries
1975 .iter()
1976 .filter(move |(path, _)| {
1977 include_ignored
1978 || worktree
1979 .entry_for_path(path.as_ref())
1980 .map_or(false, |entry| !entry.is_ignored)
1981 })
1982 .flat_map(move |(path, summaries)| {
1983 summaries.iter().map(move |(server_id, summary)| {
1984 (
1985 ProjectPath {
1986 worktree_id,
1987 path: path.clone(),
1988 },
1989 *server_id,
1990 *summary,
1991 )
1992 })
1993 })
1994 })
1995 }
1996
1997 pub fn started_language_servers(&self) -> Vec<(WorktreeId, LanguageServerName)> {
1998 self.language_server_ids.keys().cloned().collect()
1999 }
2000
2001 pub fn on_buffer_edited(
2002 &mut self,
2003 buffer: Model<Buffer>,
2004 cx: &mut ModelContext<Self>,
2005 ) -> Option<()> {
2006 let buffer = buffer.read(cx);
2007 let file = File::from_dyn(buffer.file())?;
2008 let abs_path = file.as_local()?.abs_path(cx);
2009 let uri = lsp::Url::from_file_path(abs_path).unwrap();
2010 let next_snapshot = buffer.text_snapshot();
2011
2012 let language_servers: Vec<_> = self
2013 .language_servers_for_buffer(buffer, cx)
2014 .map(|i| i.1.clone())
2015 .collect();
2016
2017 for language_server in language_servers {
2018 let language_server = language_server.clone();
2019
2020 let buffer_snapshots = self
2021 .buffer_snapshots
2022 .get_mut(&buffer.remote_id())
2023 .and_then(|m| m.get_mut(&language_server.server_id()))?;
2024 let previous_snapshot = buffer_snapshots.last()?;
2025
2026 let build_incremental_change = || {
2027 buffer
2028 .edits_since::<(PointUtf16, usize)>(previous_snapshot.snapshot.version())
2029 .map(|edit| {
2030 let edit_start = edit.new.start.0;
2031 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
2032 let new_text = next_snapshot
2033 .text_for_range(edit.new.start.1..edit.new.end.1)
2034 .collect();
2035 lsp::TextDocumentContentChangeEvent {
2036 range: Some(lsp::Range::new(
2037 point_to_lsp(edit_start),
2038 point_to_lsp(edit_end),
2039 )),
2040 range_length: None,
2041 text: new_text,
2042 }
2043 })
2044 .collect()
2045 };
2046
2047 let document_sync_kind = language_server
2048 .capabilities()
2049 .text_document_sync
2050 .as_ref()
2051 .and_then(|sync| match sync {
2052 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
2053 lsp::TextDocumentSyncCapability::Options(options) => options.change,
2054 });
2055
2056 let content_changes: Vec<_> = match document_sync_kind {
2057 Some(lsp::TextDocumentSyncKind::FULL) => {
2058 vec![lsp::TextDocumentContentChangeEvent {
2059 range: None,
2060 range_length: None,
2061 text: next_snapshot.text(),
2062 }]
2063 }
2064 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
2065 _ => {
2066 #[cfg(any(test, feature = "test-support"))]
2067 {
2068 build_incremental_change()
2069 }
2070
2071 #[cfg(not(any(test, feature = "test-support")))]
2072 {
2073 continue;
2074 }
2075 }
2076 };
2077
2078 let next_version = previous_snapshot.version + 1;
2079 buffer_snapshots.push(LspBufferSnapshot {
2080 version: next_version,
2081 snapshot: next_snapshot.clone(),
2082 });
2083
2084 language_server
2085 .notify::<lsp::notification::DidChangeTextDocument>(
2086 lsp::DidChangeTextDocumentParams {
2087 text_document: lsp::VersionedTextDocumentIdentifier::new(
2088 uri.clone(),
2089 next_version,
2090 ),
2091 content_changes,
2092 },
2093 )
2094 .log_err();
2095 }
2096
2097 None
2098 }
2099
2100 pub fn on_buffer_saved(
2101 &mut self,
2102 buffer: Model<Buffer>,
2103 cx: &mut ModelContext<Self>,
2104 ) -> Option<()> {
2105 let file = File::from_dyn(buffer.read(cx).file())?;
2106 let worktree_id = file.worktree_id(cx);
2107 let abs_path = file.as_local()?.abs_path(cx);
2108 let text_document = lsp::TextDocumentIdentifier {
2109 uri: lsp::Url::from_file_path(abs_path).log_err()?,
2110 };
2111
2112 for (_, _, server) in self.language_servers_for_worktree(worktree_id) {
2113 if let Some(include_text) = include_text(server.as_ref()) {
2114 let text = if include_text {
2115 Some(buffer.read(cx).text())
2116 } else {
2117 None
2118 };
2119 server
2120 .notify::<lsp::notification::DidSaveTextDocument>(
2121 lsp::DidSaveTextDocumentParams {
2122 text_document: text_document.clone(),
2123 text,
2124 },
2125 )
2126 .log_err();
2127 }
2128 }
2129
2130 for language_server_id in self.language_server_ids_for_buffer(buffer.read(cx), cx) {
2131 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
2132 }
2133
2134 None
2135 }
2136
2137 fn maintain_workspace_config(cx: &mut ModelContext<Self>) -> Task<Result<()>> {
2138 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
2139 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
2140
2141 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
2142 *settings_changed_tx.borrow_mut() = ();
2143 });
2144
2145 cx.spawn(move |this, mut cx| async move {
2146 while let Some(()) = settings_changed_rx.next().await {
2147 let servers = this.update(&mut cx, |this, cx| {
2148 this.language_server_ids
2149 .iter()
2150 .filter_map(|((worktree_id, _), server_id)| {
2151 let worktree = this
2152 .worktree_store
2153 .read(cx)
2154 .worktree_for_id(*worktree_id, cx)?;
2155 let state = this.language_servers.get(server_id)?;
2156 let delegate = ProjectLspAdapterDelegate::new(this, &worktree, cx);
2157 match state {
2158 LanguageServerState::Starting(_) => None,
2159 LanguageServerState::Running {
2160 adapter, server, ..
2161 } => Some((
2162 adapter.adapter.clone(),
2163 server.clone(),
2164 delegate as Arc<dyn LspAdapterDelegate>,
2165 )),
2166 }
2167 })
2168 .collect::<Vec<_>>()
2169 })?;
2170
2171 for (adapter, server, delegate) in servers {
2172 let settings = adapter.workspace_configuration(&delegate, &mut cx).await?;
2173
2174 server
2175 .notify::<lsp::notification::DidChangeConfiguration>(
2176 lsp::DidChangeConfigurationParams { settings },
2177 )
2178 .ok();
2179 }
2180 }
2181
2182 drop(settings_observation);
2183 anyhow::Ok(())
2184 })
2185 }
2186
2187 pub fn primary_language_server_for_buffer<'a>(
2188 &'a self,
2189 buffer: &'a Buffer,
2190 cx: &'a AppContext,
2191 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
2192 // The list of language servers is ordered based on the `language_servers` setting
2193 // for each language, thus we can consider the first one in the list to be the
2194 // primary one.
2195 self.language_servers_for_buffer(buffer, cx).next()
2196 }
2197
2198 pub fn language_server_for_buffer<'a>(
2199 &'a self,
2200 buffer: &'a Buffer,
2201 server_id: LanguageServerId,
2202 cx: &'a AppContext,
2203 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
2204 self.language_servers_for_buffer(buffer, cx)
2205 .find(|(_, s)| s.server_id() == server_id)
2206 }
2207
2208 fn language_servers_for_worktree(
2209 &self,
2210 worktree_id: WorktreeId,
2211 ) -> impl Iterator<Item = (&Arc<CachedLspAdapter>, &Arc<Language>, &Arc<LanguageServer>)> {
2212 self.language_server_ids
2213 .iter()
2214 .filter_map(move |((language_server_worktree_id, _), id)| {
2215 if *language_server_worktree_id == worktree_id {
2216 if let Some(LanguageServerState::Running {
2217 adapter,
2218 language,
2219 server,
2220 ..
2221 }) = self.language_servers.get(id)
2222 {
2223 return Some((adapter, language, server));
2224 }
2225 }
2226 None
2227 })
2228 }
2229
2230 pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
2231 self.diagnostics.remove(&id_to_remove);
2232 self.diagnostic_summaries.remove(&id_to_remove);
2233
2234 let mut servers_to_remove = HashMap::default();
2235 let mut servers_to_preserve = HashSet::default();
2236 for ((worktree_id, server_name), &server_id) in &self.language_server_ids {
2237 if worktree_id == &id_to_remove {
2238 servers_to_remove.insert(server_id, server_name.clone());
2239 } else {
2240 servers_to_preserve.insert(server_id);
2241 }
2242 }
2243 servers_to_remove.retain(|server_id, _| !servers_to_preserve.contains(server_id));
2244 for (server_id_to_remove, server_name) in servers_to_remove {
2245 self.language_server_ids
2246 .remove(&(id_to_remove, server_name));
2247 self.language_server_statuses.remove(&server_id_to_remove);
2248 self.language_server_watched_paths
2249 .remove(&server_id_to_remove);
2250 self.last_workspace_edits_by_language_server
2251 .remove(&server_id_to_remove);
2252 self.language_servers.remove(&server_id_to_remove);
2253 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id_to_remove));
2254 }
2255 }
2256
2257 pub fn shared(
2258 &mut self,
2259 project_id: u64,
2260 downstream_client: AnyProtoClient,
2261 _: &mut ModelContext<Self>,
2262 ) {
2263 self.project_id = project_id;
2264 self.downstream_client = Some(downstream_client.clone());
2265
2266 for (server_id, status) in &self.language_server_statuses {
2267 downstream_client
2268 .send(proto::StartLanguageServer {
2269 project_id,
2270 server: Some(proto::LanguageServer {
2271 id: server_id.0 as u64,
2272 name: status.name.clone(),
2273 }),
2274 })
2275 .log_err();
2276 }
2277 }
2278
2279 pub fn disconnected_from_host(&mut self) {
2280 self.downstream_client.take();
2281 }
2282
2283 pub(crate) fn set_language_server_statuses_from_proto(
2284 &mut self,
2285 language_servers: Vec<proto::LanguageServer>,
2286 ) {
2287 self.language_server_statuses = language_servers
2288 .into_iter()
2289 .map(|server| {
2290 (
2291 LanguageServerId(server.id as usize),
2292 LanguageServerStatus {
2293 name: server.name,
2294 pending_work: Default::default(),
2295 has_pending_diagnostic_updates: false,
2296 progress_tokens: Default::default(),
2297 },
2298 )
2299 })
2300 .collect();
2301 }
2302
2303 pub(crate) fn register_language_server(
2304 &mut self,
2305 worktree_id: WorktreeId,
2306 language_server_name: LanguageServerName,
2307 language_server_id: LanguageServerId,
2308 ) {
2309 self.language_server_ids
2310 .insert((worktree_id, language_server_name), language_server_id);
2311 }
2312
2313 pub(crate) fn register_buffer_with_language_servers(
2314 &mut self,
2315 buffer_handle: &Model<Buffer>,
2316 cx: &mut ModelContext<Self>,
2317 ) {
2318 let buffer = buffer_handle.read(cx);
2319 let buffer_id = buffer.remote_id();
2320
2321 if let Some(file) = File::from_dyn(buffer.file()) {
2322 if !file.is_local() {
2323 return;
2324 }
2325
2326 let abs_path = file.abs_path(cx);
2327 let Some(uri) = lsp::Url::from_file_path(&abs_path).log_err() else {
2328 return;
2329 };
2330 let initial_snapshot = buffer.text_snapshot();
2331 let language = buffer.language().cloned();
2332 let worktree_id = file.worktree_id(cx);
2333
2334 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2335 for (server_id, diagnostics) in
2336 diagnostics.get(file.path()).cloned().unwrap_or_default()
2337 {
2338 self.update_buffer_diagnostics(buffer_handle, server_id, None, diagnostics, cx)
2339 .log_err();
2340 }
2341 }
2342
2343 if let Some(language) = language {
2344 for adapter in self.languages.lsp_adapters(&language) {
2345 let server = self
2346 .language_server_ids
2347 .get(&(worktree_id, adapter.name.clone()))
2348 .and_then(|id| self.language_servers.get(id))
2349 .and_then(|server_state| {
2350 if let LanguageServerState::Running { server, .. } = server_state {
2351 Some(server.clone())
2352 } else {
2353 None
2354 }
2355 });
2356 let server = match server {
2357 Some(server) => server,
2358 None => continue,
2359 };
2360
2361 server
2362 .notify::<lsp::notification::DidOpenTextDocument>(
2363 lsp::DidOpenTextDocumentParams {
2364 text_document: lsp::TextDocumentItem::new(
2365 uri.clone(),
2366 adapter.language_id(&language),
2367 0,
2368 initial_snapshot.text(),
2369 ),
2370 },
2371 )
2372 .log_err();
2373
2374 buffer_handle.update(cx, |buffer, cx| {
2375 buffer.set_completion_triggers(
2376 server
2377 .capabilities()
2378 .completion_provider
2379 .as_ref()
2380 .and_then(|provider| provider.trigger_characters.clone())
2381 .unwrap_or_default(),
2382 cx,
2383 );
2384 });
2385
2386 let snapshot = LspBufferSnapshot {
2387 version: 0,
2388 snapshot: initial_snapshot.clone(),
2389 };
2390 self.buffer_snapshots
2391 .entry(buffer_id)
2392 .or_default()
2393 .insert(server.server_id(), vec![snapshot]);
2394 }
2395 }
2396 }
2397 }
2398
2399 pub(crate) fn unregister_buffer_from_language_servers(
2400 &mut self,
2401 buffer: &Model<Buffer>,
2402 old_file: &File,
2403 cx: &mut AppContext,
2404 ) {
2405 let old_path = match old_file.as_local() {
2406 Some(local) => local.abs_path(cx),
2407 None => return,
2408 };
2409
2410 buffer.update(cx, |buffer, cx| {
2411 let worktree_id = old_file.worktree_id(cx);
2412
2413 let ids = &self.language_server_ids;
2414
2415 if let Some(language) = buffer.language().cloned() {
2416 for adapter in self.languages.lsp_adapters(&language) {
2417 if let Some(server_id) = ids.get(&(worktree_id, adapter.name.clone())) {
2418 buffer.update_diagnostics(*server_id, Default::default(), cx);
2419 }
2420 }
2421 }
2422
2423 self.buffer_snapshots.remove(&buffer.remote_id());
2424 let file_url = lsp::Url::from_file_path(old_path).unwrap();
2425 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2426 language_server
2427 .notify::<lsp::notification::DidCloseTextDocument>(
2428 lsp::DidCloseTextDocumentParams {
2429 text_document: lsp::TextDocumentIdentifier::new(file_url.clone()),
2430 },
2431 )
2432 .log_err();
2433 }
2434 });
2435 }
2436
2437 pub fn update_diagnostic_entries(
2438 &mut self,
2439 server_id: LanguageServerId,
2440 abs_path: PathBuf,
2441 version: Option<i32>,
2442 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2443 cx: &mut ModelContext<Self>,
2444 ) -> Result<(), anyhow::Error> {
2445 let (worktree, relative_path) =
2446 self.worktree_store
2447 .read(cx)
2448 .find_worktree(&abs_path, cx)
2449 .ok_or_else(|| anyhow!("no worktree found for diagnostics path {abs_path:?}"))?;
2450
2451 let project_path = ProjectPath {
2452 worktree_id: worktree.read(cx).id(),
2453 path: relative_path.into(),
2454 };
2455
2456 if let Some(buffer) = self.buffer_store.read(cx).get_by_path(&project_path, cx) {
2457 self.update_buffer_diagnostics(&buffer, server_id, version, diagnostics.clone(), cx)?;
2458 }
2459
2460 let updated = worktree.update(cx, |worktree, cx| {
2461 self.update_worktree_diagnostics(
2462 worktree.id(),
2463 server_id,
2464 project_path.path.clone(),
2465 diagnostics,
2466 cx,
2467 )
2468 })?;
2469 if updated {
2470 cx.emit(LspStoreEvent::DiagnosticsUpdated {
2471 language_server_id: server_id,
2472 path: project_path,
2473 })
2474 }
2475 Ok(())
2476 }
2477
2478 pub fn update_worktree_diagnostics(
2479 &mut self,
2480 worktree_id: WorktreeId,
2481 server_id: LanguageServerId,
2482 worktree_path: Arc<Path>,
2483 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2484 _: &mut ModelContext<Worktree>,
2485 ) -> Result<bool> {
2486 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
2487 let diagnostics_for_tree = self.diagnostics.entry(worktree_id).or_default();
2488 let summaries_by_server_id = summaries_for_tree.entry(worktree_path.clone()).or_default();
2489
2490 let old_summary = summaries_by_server_id
2491 .remove(&server_id)
2492 .unwrap_or_default();
2493
2494 let new_summary = DiagnosticSummary::new(&diagnostics);
2495 if new_summary.is_empty() {
2496 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&worktree_path) {
2497 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
2498 diagnostics_by_server_id.remove(ix);
2499 }
2500 if diagnostics_by_server_id.is_empty() {
2501 diagnostics_for_tree.remove(&worktree_path);
2502 }
2503 }
2504 } else {
2505 summaries_by_server_id.insert(server_id, new_summary);
2506 let diagnostics_by_server_id = diagnostics_for_tree
2507 .entry(worktree_path.clone())
2508 .or_default();
2509 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
2510 Ok(ix) => {
2511 diagnostics_by_server_id[ix] = (server_id, diagnostics);
2512 }
2513 Err(ix) => {
2514 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
2515 }
2516 }
2517 }
2518
2519 if !old_summary.is_empty() || !new_summary.is_empty() {
2520 if let Some(downstream_client) = &self.downstream_client {
2521 downstream_client
2522 .send(proto::UpdateDiagnosticSummary {
2523 project_id: self.project_id,
2524 worktree_id: worktree_id.to_proto(),
2525 summary: Some(proto::DiagnosticSummary {
2526 path: worktree_path.to_string_lossy().to_string(),
2527 language_server_id: server_id.0 as u64,
2528 error_count: new_summary.error_count as u32,
2529 warning_count: new_summary.warning_count as u32,
2530 }),
2531 })
2532 .log_err();
2533 }
2534 }
2535
2536 Ok(!old_summary.is_empty() || !new_summary.is_empty())
2537 }
2538
2539 pub fn open_buffer_for_symbol(
2540 &mut self,
2541 symbol: &Symbol,
2542 cx: &mut ModelContext<Self>,
2543 ) -> Task<Result<Model<Buffer>>> {
2544 if let Some(client) = self.upstream_client.clone() {
2545 let request = client.request(proto::OpenBufferForSymbol {
2546 project_id: self.project_id,
2547 symbol: Some(Self::serialize_symbol(symbol)),
2548 });
2549 cx.spawn(move |this, mut cx| async move {
2550 let response = request.await?;
2551 let buffer_id = BufferId::new(response.buffer_id)?;
2552 this.update(&mut cx, |this, cx| {
2553 this.wait_for_remote_buffer(buffer_id, cx)
2554 })?
2555 .await
2556 })
2557 } else {
2558 let Some(&language_server_id) = self.language_server_ids.get(&(
2559 symbol.source_worktree_id,
2560 symbol.language_server_name.clone(),
2561 )) else {
2562 return Task::ready(Err(anyhow!(
2563 "language server for worktree and language not found"
2564 )));
2565 };
2566
2567 let worktree_abs_path = if let Some(worktree_abs_path) = self
2568 .worktree_store
2569 .read(cx)
2570 .worktree_for_id(symbol.path.worktree_id, cx)
2571 .map(|worktree| worktree.read(cx).abs_path())
2572 {
2573 worktree_abs_path
2574 } else {
2575 return Task::ready(Err(anyhow!("worktree not found for symbol")));
2576 };
2577
2578 let symbol_abs_path = resolve_path(&worktree_abs_path, &symbol.path.path);
2579 let symbol_uri = if let Ok(uri) = lsp::Url::from_file_path(symbol_abs_path) {
2580 uri
2581 } else {
2582 return Task::ready(Err(anyhow!("invalid symbol path")));
2583 };
2584
2585 self.open_local_buffer_via_lsp(
2586 symbol_uri,
2587 language_server_id,
2588 symbol.language_server_name.clone(),
2589 cx,
2590 )
2591 }
2592 }
2593
2594 pub fn open_local_buffer_via_lsp(
2595 &mut self,
2596 mut abs_path: lsp::Url,
2597 language_server_id: LanguageServerId,
2598 language_server_name: LanguageServerName,
2599 cx: &mut ModelContext<Self>,
2600 ) -> Task<Result<Model<Buffer>>> {
2601 cx.spawn(move |this, mut cx| async move {
2602 // Escape percent-encoded string.
2603 let current_scheme = abs_path.scheme().to_owned();
2604 let _ = abs_path.set_scheme("file");
2605
2606 let abs_path = abs_path
2607 .to_file_path()
2608 .map_err(|_| anyhow!("can't convert URI to path"))?;
2609 let p = abs_path.clone();
2610 let yarn_worktree = this
2611 .update(&mut cx, move |this, cx| {
2612 this.yarn.update(cx, |_, cx| {
2613 cx.spawn(|this, mut cx| async move {
2614 let t = this
2615 .update(&mut cx, |this, cx| {
2616 this.process_path(&p, ¤t_scheme, cx)
2617 })
2618 .ok()?;
2619 t.await
2620 })
2621 })
2622 })?
2623 .await;
2624 let (worktree_root_target, known_relative_path) =
2625 if let Some((zip_root, relative_path)) = yarn_worktree {
2626 (zip_root, Some(relative_path))
2627 } else {
2628 (Arc::<Path>::from(abs_path.as_path()), None)
2629 };
2630 let (worktree, relative_path) = if let Some(result) =
2631 this.update(&mut cx, |this, cx| {
2632 this.worktree_store.update(cx, |worktree_store, cx| {
2633 worktree_store.find_worktree(&worktree_root_target, cx)
2634 })
2635 })? {
2636 let relative_path =
2637 known_relative_path.unwrap_or_else(|| Arc::<Path>::from(result.1));
2638 (result.0, relative_path)
2639 } else {
2640 let worktree = this
2641 .update(&mut cx, |this, cx| {
2642 this.worktree_store.update(cx, |worktree_store, cx| {
2643 worktree_store.create_worktree(&worktree_root_target, false, cx)
2644 })
2645 })?
2646 .await?;
2647 this.update(&mut cx, |this, cx| {
2648 this.register_language_server(
2649 worktree.read(cx).id(),
2650 language_server_name,
2651 language_server_id,
2652 )
2653 })
2654 .ok();
2655 let worktree_root = worktree.update(&mut cx, |this, _| this.abs_path())?;
2656 let relative_path = if let Some(known_path) = known_relative_path {
2657 known_path
2658 } else {
2659 abs_path.strip_prefix(worktree_root)?.into()
2660 };
2661 (worktree, relative_path)
2662 };
2663 let project_path = ProjectPath {
2664 worktree_id: worktree.update(&mut cx, |worktree, _| worktree.id())?,
2665 path: relative_path,
2666 };
2667 this.update(&mut cx, |this, cx| {
2668 this.buffer_store().update(cx, |buffer_store, cx| {
2669 buffer_store.open_buffer(project_path, cx)
2670 })
2671 })?
2672 .await
2673 })
2674 }
2675
2676 pub(crate) fn update_buffer_diagnostics(
2677 &mut self,
2678 buffer: &Model<Buffer>,
2679 server_id: LanguageServerId,
2680 version: Option<i32>,
2681 mut diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2682 cx: &mut ModelContext<Self>,
2683 ) -> Result<()> {
2684 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2685 Ordering::Equal
2686 .then_with(|| b.is_primary.cmp(&a.is_primary))
2687 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2688 .then_with(|| a.severity.cmp(&b.severity))
2689 .then_with(|| a.message.cmp(&b.message))
2690 }
2691
2692 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2693
2694 diagnostics.sort_unstable_by(|a, b| {
2695 Ordering::Equal
2696 .then_with(|| a.range.start.cmp(&b.range.start))
2697 .then_with(|| b.range.end.cmp(&a.range.end))
2698 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2699 });
2700
2701 let mut sanitized_diagnostics = Vec::new();
2702 let edits_since_save = Patch::new(
2703 snapshot
2704 .edits_since::<Unclipped<PointUtf16>>(buffer.read(cx).saved_version())
2705 .collect(),
2706 );
2707 for entry in diagnostics {
2708 let start;
2709 let end;
2710 if entry.diagnostic.is_disk_based {
2711 // Some diagnostics are based on files on disk instead of buffers'
2712 // current contents. Adjust these diagnostics' ranges to reflect
2713 // any unsaved edits.
2714 start = edits_since_save.old_to_new(entry.range.start);
2715 end = edits_since_save.old_to_new(entry.range.end);
2716 } else {
2717 start = entry.range.start;
2718 end = entry.range.end;
2719 }
2720
2721 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2722 ..snapshot.clip_point_utf16(end, Bias::Right);
2723
2724 // Expand empty ranges by one codepoint
2725 if range.start == range.end {
2726 // This will be go to the next boundary when being clipped
2727 range.end.column += 1;
2728 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2729 if range.start == range.end && range.end.column > 0 {
2730 range.start.column -= 1;
2731 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2732 }
2733 }
2734
2735 sanitized_diagnostics.push(DiagnosticEntry {
2736 range,
2737 diagnostic: entry.diagnostic,
2738 });
2739 }
2740 drop(edits_since_save);
2741
2742 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2743 buffer.update(cx, |buffer, cx| {
2744 buffer.update_diagnostics(server_id, set, cx)
2745 });
2746 Ok(())
2747 }
2748
2749 fn request_multiple_lsp_locally<P, R>(
2750 &self,
2751 buffer: &Model<Buffer>,
2752 position: Option<P>,
2753 request: R,
2754 cx: &mut ModelContext<'_, Self>,
2755 ) -> Task<Vec<R::Response>>
2756 where
2757 P: ToOffset,
2758 R: LspCommand + Clone,
2759 <R::LspRequest as lsp::request::Request>::Result: Send,
2760 <R::LspRequest as lsp::request::Request>::Params: Send,
2761 {
2762 debug_assert!(self.upstream_client.is_none());
2763
2764 let snapshot = buffer.read(cx).snapshot();
2765 let scope = position.and_then(|position| snapshot.language_scope_at(position));
2766 let server_ids = self
2767 .language_servers_for_buffer(buffer.read(cx), cx)
2768 .filter(|(adapter, _)| {
2769 scope
2770 .as_ref()
2771 .map(|scope| scope.language_allowed(&adapter.name))
2772 .unwrap_or(true)
2773 })
2774 .map(|(_, server)| server.server_id())
2775 .collect::<Vec<_>>();
2776 let mut response_results = server_ids
2777 .into_iter()
2778 .map(|server_id| {
2779 self.request_lsp(
2780 buffer.clone(),
2781 LanguageServerToQuery::Other(server_id),
2782 request.clone(),
2783 cx,
2784 )
2785 })
2786 .collect::<FuturesUnordered<_>>();
2787
2788 return cx.spawn(|_, _| async move {
2789 let mut responses = Vec::with_capacity(response_results.len());
2790 while let Some(response_result) = response_results.next().await {
2791 if let Some(response) = response_result.log_err() {
2792 responses.push(response);
2793 }
2794 }
2795 responses
2796 });
2797 }
2798
2799 async fn handle_lsp_command<T: LspCommand>(
2800 this: Model<Self>,
2801 envelope: TypedEnvelope<T::ProtoRequest>,
2802 mut cx: AsyncAppContext,
2803 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
2804 where
2805 <T::LspRequest as lsp::request::Request>::Params: Send,
2806 <T::LspRequest as lsp::request::Request>::Result: Send,
2807 {
2808 let sender_id = envelope.original_sender_id()?;
2809 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
2810 let buffer_handle = this.update(&mut cx, |this, cx| {
2811 this.buffer_store.read(cx).get_existing(buffer_id)
2812 })??;
2813 let request = T::from_proto(
2814 envelope.payload,
2815 this.clone(),
2816 buffer_handle.clone(),
2817 cx.clone(),
2818 )
2819 .await?;
2820 let response = this
2821 .update(&mut cx, |this, cx| {
2822 this.request_lsp(
2823 buffer_handle.clone(),
2824 LanguageServerToQuery::Primary,
2825 request,
2826 cx,
2827 )
2828 })?
2829 .await?;
2830 this.update(&mut cx, |this, cx| {
2831 Ok(T::response_to_proto(
2832 response,
2833 this,
2834 sender_id,
2835 &buffer_handle.read(cx).version(),
2836 cx,
2837 ))
2838 })?
2839 }
2840
2841 async fn handle_multi_lsp_query(
2842 this: Model<Self>,
2843 envelope: TypedEnvelope<proto::MultiLspQuery>,
2844 mut cx: AsyncAppContext,
2845 ) -> Result<proto::MultiLspQueryResponse> {
2846 let sender_id = envelope.original_sender_id()?;
2847 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
2848 let version = deserialize_version(&envelope.payload.version);
2849 let buffer = this.update(&mut cx, |this, cx| {
2850 this.buffer_store.read(cx).get_existing(buffer_id)
2851 })??;
2852 buffer
2853 .update(&mut cx, |buffer, _| {
2854 buffer.wait_for_version(version.clone())
2855 })?
2856 .await?;
2857 let buffer_version = buffer.update(&mut cx, |buffer, _| buffer.version())?;
2858 match envelope
2859 .payload
2860 .strategy
2861 .context("invalid request without the strategy")?
2862 {
2863 proto::multi_lsp_query::Strategy::All(_) => {
2864 // currently, there's only one multiple language servers query strategy,
2865 // so just ensure it's specified correctly
2866 }
2867 }
2868 match envelope.payload.request {
2869 Some(proto::multi_lsp_query::Request::GetHover(get_hover)) => {
2870 let get_hover =
2871 GetHover::from_proto(get_hover, this.clone(), buffer.clone(), cx.clone())
2872 .await?;
2873 let all_hovers = this
2874 .update(&mut cx, |this, cx| {
2875 this.request_multiple_lsp_locally(
2876 &buffer,
2877 Some(get_hover.position),
2878 get_hover,
2879 cx,
2880 )
2881 })?
2882 .await
2883 .into_iter()
2884 .filter_map(|hover| remove_empty_hover_blocks(hover?));
2885 this.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
2886 responses: all_hovers
2887 .map(|hover| proto::LspResponse {
2888 response: Some(proto::lsp_response::Response::GetHoverResponse(
2889 GetHover::response_to_proto(
2890 Some(hover),
2891 project,
2892 sender_id,
2893 &buffer_version,
2894 cx,
2895 ),
2896 )),
2897 })
2898 .collect(),
2899 })
2900 }
2901 Some(proto::multi_lsp_query::Request::GetCodeActions(get_code_actions)) => {
2902 let get_code_actions = GetCodeActions::from_proto(
2903 get_code_actions,
2904 this.clone(),
2905 buffer.clone(),
2906 cx.clone(),
2907 )
2908 .await?;
2909
2910 let all_actions = this
2911 .update(&mut cx, |project, cx| {
2912 project.request_multiple_lsp_locally(
2913 &buffer,
2914 Some(get_code_actions.range.start),
2915 get_code_actions,
2916 cx,
2917 )
2918 })?
2919 .await
2920 .into_iter();
2921
2922 this.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
2923 responses: all_actions
2924 .map(|code_actions| proto::LspResponse {
2925 response: Some(proto::lsp_response::Response::GetCodeActionsResponse(
2926 GetCodeActions::response_to_proto(
2927 code_actions,
2928 project,
2929 sender_id,
2930 &buffer_version,
2931 cx,
2932 ),
2933 )),
2934 })
2935 .collect(),
2936 })
2937 }
2938 Some(proto::multi_lsp_query::Request::GetSignatureHelp(get_signature_help)) => {
2939 let get_signature_help = GetSignatureHelp::from_proto(
2940 get_signature_help,
2941 this.clone(),
2942 buffer.clone(),
2943 cx.clone(),
2944 )
2945 .await?;
2946
2947 let all_signatures = this
2948 .update(&mut cx, |project, cx| {
2949 project.request_multiple_lsp_locally(
2950 &buffer,
2951 Some(get_signature_help.position),
2952 get_signature_help,
2953 cx,
2954 )
2955 })?
2956 .await
2957 .into_iter();
2958
2959 this.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
2960 responses: all_signatures
2961 .map(|signature_help| proto::LspResponse {
2962 response: Some(
2963 proto::lsp_response::Response::GetSignatureHelpResponse(
2964 GetSignatureHelp::response_to_proto(
2965 signature_help,
2966 project,
2967 sender_id,
2968 &buffer_version,
2969 cx,
2970 ),
2971 ),
2972 ),
2973 })
2974 .collect(),
2975 })
2976 }
2977 None => anyhow::bail!("empty multi lsp query request"),
2978 }
2979 }
2980
2981 async fn handle_apply_code_action(
2982 this: Model<Self>,
2983 envelope: TypedEnvelope<proto::ApplyCodeAction>,
2984 mut cx: AsyncAppContext,
2985 ) -> Result<proto::ApplyCodeActionResponse> {
2986 let sender_id = envelope.original_sender_id()?;
2987 let action = Self::deserialize_code_action(
2988 envelope
2989 .payload
2990 .action
2991 .ok_or_else(|| anyhow!("invalid action"))?,
2992 )?;
2993 let apply_code_action = this.update(&mut cx, |this, cx| {
2994 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
2995 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
2996 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
2997 })??;
2998
2999 let project_transaction = apply_code_action.await?;
3000 let project_transaction = this.update(&mut cx, |this, cx| {
3001 this.buffer_store.update(cx, |buffer_store, cx| {
3002 buffer_store.serialize_project_transaction_for_peer(
3003 project_transaction,
3004 sender_id,
3005 cx,
3006 )
3007 })
3008 })?;
3009 Ok(proto::ApplyCodeActionResponse {
3010 transaction: Some(project_transaction),
3011 })
3012 }
3013
3014 async fn handle_update_diagnostic_summary(
3015 this: Model<Self>,
3016 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
3017 mut cx: AsyncAppContext,
3018 ) -> Result<()> {
3019 this.update(&mut cx, |this, cx| {
3020 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
3021 if let Some(message) = envelope.payload.summary {
3022 let project_path = ProjectPath {
3023 worktree_id,
3024 path: Path::new(&message.path).into(),
3025 };
3026 let path = project_path.path.clone();
3027 let server_id = LanguageServerId(message.language_server_id as usize);
3028 let summary = DiagnosticSummary {
3029 error_count: message.error_count as usize,
3030 warning_count: message.warning_count as usize,
3031 };
3032
3033 if summary.is_empty() {
3034 if let Some(worktree_summaries) =
3035 this.diagnostic_summaries.get_mut(&worktree_id)
3036 {
3037 if let Some(summaries) = worktree_summaries.get_mut(&path) {
3038 summaries.remove(&server_id);
3039 if summaries.is_empty() {
3040 worktree_summaries.remove(&path);
3041 }
3042 }
3043 }
3044 } else {
3045 this.diagnostic_summaries
3046 .entry(worktree_id)
3047 .or_default()
3048 .entry(path)
3049 .or_default()
3050 .insert(server_id, summary);
3051 }
3052 cx.emit(LspStoreEvent::DiagnosticsUpdated {
3053 language_server_id: LanguageServerId(message.language_server_id as usize),
3054 path: project_path,
3055 });
3056 }
3057 Ok(())
3058 })?
3059 }
3060
3061 async fn handle_start_language_server(
3062 this: Model<Self>,
3063 envelope: TypedEnvelope<proto::StartLanguageServer>,
3064 mut cx: AsyncAppContext,
3065 ) -> Result<()> {
3066 let server = envelope
3067 .payload
3068 .server
3069 .ok_or_else(|| anyhow!("invalid server"))?;
3070 this.update(&mut cx, |this, cx| {
3071 this.language_server_statuses.insert(
3072 LanguageServerId(server.id as usize),
3073 LanguageServerStatus {
3074 name: server.name,
3075 pending_work: Default::default(),
3076 has_pending_diagnostic_updates: false,
3077 progress_tokens: Default::default(),
3078 },
3079 );
3080 cx.notify();
3081 })?;
3082 Ok(())
3083 }
3084
3085 async fn handle_update_language_server(
3086 this: Model<Self>,
3087 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
3088 mut cx: AsyncAppContext,
3089 ) -> Result<()> {
3090 this.update(&mut cx, |this, cx| {
3091 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
3092
3093 match envelope
3094 .payload
3095 .variant
3096 .ok_or_else(|| anyhow!("invalid variant"))?
3097 {
3098 proto::update_language_server::Variant::WorkStart(payload) => {
3099 this.on_lsp_work_start(
3100 language_server_id,
3101 payload.token,
3102 LanguageServerProgress {
3103 title: payload.title,
3104 is_disk_based_diagnostics_progress: false,
3105 is_cancellable: false,
3106 message: payload.message,
3107 percentage: payload.percentage.map(|p| p as usize),
3108 last_update_at: cx.background_executor().now(),
3109 },
3110 cx,
3111 );
3112 }
3113
3114 proto::update_language_server::Variant::WorkProgress(payload) => {
3115 this.on_lsp_work_progress(
3116 language_server_id,
3117 payload.token,
3118 LanguageServerProgress {
3119 title: None,
3120 is_disk_based_diagnostics_progress: false,
3121 is_cancellable: false,
3122 message: payload.message,
3123 percentage: payload.percentage.map(|p| p as usize),
3124 last_update_at: cx.background_executor().now(),
3125 },
3126 cx,
3127 );
3128 }
3129
3130 proto::update_language_server::Variant::WorkEnd(payload) => {
3131 this.on_lsp_work_end(language_server_id, payload.token, cx);
3132 }
3133
3134 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
3135 this.disk_based_diagnostics_started(language_server_id, cx);
3136 }
3137
3138 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
3139 this.disk_based_diagnostics_finished(language_server_id, cx)
3140 }
3141 }
3142
3143 Ok(())
3144 })?
3145 }
3146
3147 pub fn disk_based_diagnostics_started(
3148 &mut self,
3149 language_server_id: LanguageServerId,
3150 cx: &mut ModelContext<Self>,
3151 ) {
3152 if let Some(language_server_status) =
3153 self.language_server_statuses.get_mut(&language_server_id)
3154 {
3155 language_server_status.has_pending_diagnostic_updates = true;
3156 }
3157
3158 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
3159 }
3160
3161 pub fn disk_based_diagnostics_finished(
3162 &mut self,
3163 language_server_id: LanguageServerId,
3164 cx: &mut ModelContext<Self>,
3165 ) {
3166 if let Some(language_server_status) =
3167 self.language_server_statuses.get_mut(&language_server_id)
3168 {
3169 language_server_status.has_pending_diagnostic_updates = false;
3170 }
3171
3172 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
3173 }
3174
3175 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
3176 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
3177 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
3178 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
3179 // the language server might take some time to publish diagnostics.
3180 fn simulate_disk_based_diagnostics_events_if_needed(
3181 &mut self,
3182 language_server_id: LanguageServerId,
3183 cx: &mut ModelContext<Self>,
3184 ) {
3185 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
3186
3187 let Some(LanguageServerState::Running {
3188 simulate_disk_based_diagnostics_completion,
3189 adapter,
3190 ..
3191 }) = self.language_servers.get_mut(&language_server_id)
3192 else {
3193 return;
3194 };
3195
3196 if adapter.disk_based_diagnostics_progress_token.is_some() {
3197 return;
3198 }
3199
3200 let prev_task = simulate_disk_based_diagnostics_completion.replace(cx.spawn(
3201 move |this, mut cx| async move {
3202 cx.background_executor()
3203 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
3204 .await;
3205
3206 this.update(&mut cx, |this, cx| {
3207 this.disk_based_diagnostics_finished(language_server_id, cx);
3208
3209 if let Some(LanguageServerState::Running {
3210 simulate_disk_based_diagnostics_completion,
3211 ..
3212 }) = this.language_servers.get_mut(&language_server_id)
3213 {
3214 *simulate_disk_based_diagnostics_completion = None;
3215 }
3216 })
3217 .ok();
3218 },
3219 ));
3220
3221 if prev_task.is_none() {
3222 self.disk_based_diagnostics_started(language_server_id, cx);
3223 }
3224 }
3225
3226 pub fn language_server_statuses(
3227 &self,
3228 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
3229 self.language_server_statuses
3230 .iter()
3231 .map(|(key, value)| (*key, value))
3232 }
3233
3234 fn rebuild_watched_paths(
3235 &mut self,
3236 language_server_id: LanguageServerId,
3237 cx: &mut ModelContext<Self>,
3238 ) {
3239 let Some(watchers) = self
3240 .language_server_watcher_registrations
3241 .get(&language_server_id)
3242 else {
3243 return;
3244 };
3245
3246 let watched_paths = self
3247 .language_server_watched_paths
3248 .entry(language_server_id)
3249 .or_default();
3250
3251 let mut builders = HashMap::default();
3252 for watcher in watchers.values().flatten() {
3253 for worktree in self.worktree_store.read(cx).worktrees().collect::<Vec<_>>() {
3254 let glob_is_inside_worktree = worktree.update(cx, |tree, _| {
3255 if let Some(abs_path) = tree.abs_path().to_str() {
3256 let relative_glob_pattern = match &watcher.glob_pattern {
3257 lsp::GlobPattern::String(s) => Some(
3258 s.strip_prefix(abs_path)
3259 .unwrap_or(s)
3260 .strip_prefix(std::path::MAIN_SEPARATOR)
3261 .unwrap_or(s),
3262 ),
3263 lsp::GlobPattern::Relative(rp) => {
3264 let base_uri = match &rp.base_uri {
3265 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3266 lsp::OneOf::Right(base_uri) => base_uri,
3267 };
3268 base_uri.to_file_path().ok().and_then(|file_path| {
3269 (file_path.to_str() == Some(abs_path))
3270 .then_some(rp.pattern.as_str())
3271 })
3272 }
3273 };
3274 if let Some(relative_glob_pattern) = relative_glob_pattern {
3275 let literal_prefix = glob_literal_prefix(relative_glob_pattern);
3276 tree.as_local_mut()
3277 .unwrap()
3278 .add_path_prefix_to_scan(Path::new(literal_prefix).into());
3279 if let Some(glob) = Glob::new(relative_glob_pattern).log_err() {
3280 builders
3281 .entry(tree.id())
3282 .or_insert_with(|| GlobSetBuilder::new())
3283 .add(glob);
3284 }
3285 return true;
3286 }
3287 }
3288 false
3289 });
3290 if glob_is_inside_worktree {
3291 break;
3292 }
3293 }
3294 }
3295
3296 watched_paths.clear();
3297 for (worktree_id, builder) in builders {
3298 if let Ok(globset) = builder.build() {
3299 watched_paths.insert(worktree_id, globset);
3300 }
3301 }
3302
3303 cx.notify();
3304 }
3305
3306 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3307 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3308 Some(server.clone())
3309 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3310 Some(Arc::clone(server))
3311 } else {
3312 None
3313 }
3314 }
3315
3316 async fn on_lsp_workspace_edit(
3317 this: WeakModel<Self>,
3318 params: lsp::ApplyWorkspaceEditParams,
3319 server_id: LanguageServerId,
3320 adapter: Arc<CachedLspAdapter>,
3321 mut cx: AsyncAppContext,
3322 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3323 let this = this
3324 .upgrade()
3325 .ok_or_else(|| anyhow!("project project closed"))?;
3326 let language_server = this
3327 .update(&mut cx, |this, _| this.language_server_for_id(server_id))?
3328 .ok_or_else(|| anyhow!("language server not found"))?;
3329 let transaction = Self::deserialize_workspace_edit(
3330 this.clone(),
3331 params.edit,
3332 true,
3333 adapter.clone(),
3334 language_server.clone(),
3335 &mut cx,
3336 )
3337 .await
3338 .log_err();
3339 this.update(&mut cx, |this, _| {
3340 if let Some(transaction) = transaction {
3341 this.last_workspace_edits_by_language_server
3342 .insert(server_id, transaction);
3343 }
3344 })?;
3345 Ok(lsp::ApplyWorkspaceEditResponse {
3346 applied: true,
3347 failed_change: None,
3348 failure_reason: None,
3349 })
3350 }
3351
3352 fn on_lsp_progress(
3353 &mut self,
3354 progress: lsp::ProgressParams,
3355 language_server_id: LanguageServerId,
3356 disk_based_diagnostics_progress_token: Option<String>,
3357 cx: &mut ModelContext<Self>,
3358 ) {
3359 let token = match progress.token {
3360 lsp::NumberOrString::String(token) => token,
3361 lsp::NumberOrString::Number(token) => {
3362 log::info!("skipping numeric progress token {}", token);
3363 return;
3364 }
3365 };
3366
3367 let lsp::ProgressParamsValue::WorkDone(progress) = progress.value;
3368 let language_server_status =
3369 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3370 status
3371 } else {
3372 return;
3373 };
3374
3375 if !language_server_status.progress_tokens.contains(&token) {
3376 return;
3377 }
3378
3379 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
3380 .as_ref()
3381 .map_or(false, |disk_based_token| {
3382 token.starts_with(disk_based_token)
3383 });
3384
3385 match progress {
3386 lsp::WorkDoneProgress::Begin(report) => {
3387 if is_disk_based_diagnostics_progress {
3388 self.disk_based_diagnostics_started(language_server_id, cx);
3389 }
3390 self.on_lsp_work_start(
3391 language_server_id,
3392 token.clone(),
3393 LanguageServerProgress {
3394 title: Some(report.title),
3395 is_disk_based_diagnostics_progress,
3396 is_cancellable: report.cancellable.unwrap_or(false),
3397 message: report.message.clone(),
3398 percentage: report.percentage.map(|p| p as usize),
3399 last_update_at: cx.background_executor().now(),
3400 },
3401 cx,
3402 );
3403 }
3404 lsp::WorkDoneProgress::Report(report) => {
3405 if self.on_lsp_work_progress(
3406 language_server_id,
3407 token.clone(),
3408 LanguageServerProgress {
3409 title: None,
3410 is_disk_based_diagnostics_progress,
3411 is_cancellable: report.cancellable.unwrap_or(false),
3412 message: report.message.clone(),
3413 percentage: report.percentage.map(|p| p as usize),
3414 last_update_at: cx.background_executor().now(),
3415 },
3416 cx,
3417 ) {
3418 cx.emit(LspStoreEvent::LanguageServerUpdate {
3419 language_server_id,
3420 message: proto::update_language_server::Variant::WorkProgress(
3421 proto::LspWorkProgress {
3422 token,
3423 message: report.message,
3424 percentage: report.percentage,
3425 },
3426 ),
3427 })
3428 }
3429 }
3430 lsp::WorkDoneProgress::End(_) => {
3431 language_server_status.progress_tokens.remove(&token);
3432 self.on_lsp_work_end(language_server_id, token.clone(), cx);
3433 if is_disk_based_diagnostics_progress {
3434 self.disk_based_diagnostics_finished(language_server_id, cx);
3435 }
3436 }
3437 }
3438 }
3439
3440 fn on_lsp_work_start(
3441 &mut self,
3442 language_server_id: LanguageServerId,
3443 token: String,
3444 progress: LanguageServerProgress,
3445 cx: &mut ModelContext<Self>,
3446 ) {
3447 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3448 status.pending_work.insert(token.clone(), progress.clone());
3449 cx.notify();
3450 }
3451 cx.emit(LspStoreEvent::LanguageServerUpdate {
3452 language_server_id,
3453 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
3454 token,
3455 title: progress.title,
3456 message: progress.message,
3457 percentage: progress.percentage.map(|p| p as u32),
3458 }),
3459 })
3460 }
3461
3462 fn on_lsp_work_progress(
3463 &mut self,
3464 language_server_id: LanguageServerId,
3465 token: String,
3466 progress: LanguageServerProgress,
3467 cx: &mut ModelContext<Self>,
3468 ) -> bool {
3469 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3470 match status.pending_work.entry(token) {
3471 btree_map::Entry::Vacant(entry) => {
3472 entry.insert(progress);
3473 cx.notify();
3474 return true;
3475 }
3476 btree_map::Entry::Occupied(mut entry) => {
3477 let entry = entry.get_mut();
3478 if (progress.last_update_at - entry.last_update_at)
3479 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
3480 {
3481 entry.last_update_at = progress.last_update_at;
3482 if progress.message.is_some() {
3483 entry.message = progress.message;
3484 }
3485 if progress.percentage.is_some() {
3486 entry.percentage = progress.percentage;
3487 }
3488 cx.notify();
3489 return true;
3490 }
3491 }
3492 }
3493 }
3494
3495 false
3496 }
3497
3498 fn on_lsp_work_end(
3499 &mut self,
3500 language_server_id: LanguageServerId,
3501 token: String,
3502 cx: &mut ModelContext<Self>,
3503 ) {
3504 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3505 if let Some(work) = status.pending_work.remove(&token) {
3506 if !work.is_disk_based_diagnostics_progress {
3507 cx.emit(LspStoreEvent::RefreshInlayHints);
3508 }
3509 }
3510 cx.notify();
3511 }
3512
3513 cx.emit(LspStoreEvent::LanguageServerUpdate {
3514 language_server_id,
3515 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
3516 })
3517 }
3518
3519 fn on_lsp_did_change_watched_files(
3520 &mut self,
3521 language_server_id: LanguageServerId,
3522 registration_id: &str,
3523 params: DidChangeWatchedFilesRegistrationOptions,
3524 cx: &mut ModelContext<Self>,
3525 ) {
3526 let registrations = self
3527 .language_server_watcher_registrations
3528 .entry(language_server_id)
3529 .or_default();
3530
3531 registrations.insert(registration_id.to_string(), params.watchers);
3532
3533 self.rebuild_watched_paths(language_server_id, cx);
3534 }
3535
3536 fn on_lsp_unregister_did_change_watched_files(
3537 &mut self,
3538 language_server_id: LanguageServerId,
3539 registration_id: &str,
3540 cx: &mut ModelContext<Self>,
3541 ) {
3542 let registrations = self
3543 .language_server_watcher_registrations
3544 .entry(language_server_id)
3545 .or_default();
3546
3547 if registrations.remove(registration_id).is_some() {
3548 log::info!(
3549 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3550 language_server_id,
3551 registration_id
3552 );
3553 } else {
3554 log::warn!(
3555 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3556 language_server_id,
3557 registration_id
3558 );
3559 }
3560
3561 self.rebuild_watched_paths(language_server_id, cx);
3562 }
3563
3564 #[allow(clippy::type_complexity)]
3565 pub(crate) fn edits_from_lsp(
3566 &mut self,
3567 buffer: &Model<Buffer>,
3568 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3569 server_id: LanguageServerId,
3570 version: Option<i32>,
3571 cx: &mut ModelContext<Self>,
3572 ) -> Task<Result<Vec<(Range<Anchor>, String)>>> {
3573 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3574 cx.background_executor().spawn(async move {
3575 let snapshot = snapshot?;
3576 let mut lsp_edits = lsp_edits
3577 .into_iter()
3578 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3579 .collect::<Vec<_>>();
3580 lsp_edits.sort_by_key(|(range, _)| range.start);
3581
3582 let mut lsp_edits = lsp_edits.into_iter().peekable();
3583 let mut edits = Vec::new();
3584 while let Some((range, mut new_text)) = lsp_edits.next() {
3585 // Clip invalid ranges provided by the language server.
3586 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3587 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3588
3589 // Combine any LSP edits that are adjacent.
3590 //
3591 // Also, combine LSP edits that are separated from each other by only
3592 // a newline. This is important because for some code actions,
3593 // Rust-analyzer rewrites the entire buffer via a series of edits that
3594 // are separated by unchanged newline characters.
3595 //
3596 // In order for the diffing logic below to work properly, any edits that
3597 // cancel each other out must be combined into one.
3598 while let Some((next_range, next_text)) = lsp_edits.peek() {
3599 if next_range.start.0 > range.end {
3600 if next_range.start.0.row > range.end.row + 1
3601 || next_range.start.0.column > 0
3602 || snapshot.clip_point_utf16(
3603 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3604 Bias::Left,
3605 ) > range.end
3606 {
3607 break;
3608 }
3609 new_text.push('\n');
3610 }
3611 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3612 new_text.push_str(next_text);
3613 lsp_edits.next();
3614 }
3615
3616 // For multiline edits, perform a diff of the old and new text so that
3617 // we can identify the changes more precisely, preserving the locations
3618 // of any anchors positioned in the unchanged regions.
3619 if range.end.row > range.start.row {
3620 let mut offset = range.start.to_offset(&snapshot);
3621 let old_text = snapshot.text_for_range(range).collect::<String>();
3622
3623 let diff = TextDiff::from_lines(old_text.as_str(), &new_text);
3624 let mut moved_since_edit = true;
3625 for change in diff.iter_all_changes() {
3626 let tag = change.tag();
3627 let value = change.value();
3628 match tag {
3629 ChangeTag::Equal => {
3630 offset += value.len();
3631 moved_since_edit = true;
3632 }
3633 ChangeTag::Delete => {
3634 let start = snapshot.anchor_after(offset);
3635 let end = snapshot.anchor_before(offset + value.len());
3636 if moved_since_edit {
3637 edits.push((start..end, String::new()));
3638 } else {
3639 edits.last_mut().unwrap().0.end = end;
3640 }
3641 offset += value.len();
3642 moved_since_edit = false;
3643 }
3644 ChangeTag::Insert => {
3645 if moved_since_edit {
3646 let anchor = snapshot.anchor_after(offset);
3647 edits.push((anchor..anchor, value.to_string()));
3648 } else {
3649 edits.last_mut().unwrap().1.push_str(value);
3650 }
3651 moved_since_edit = false;
3652 }
3653 }
3654 }
3655 } else if range.end == range.start {
3656 let anchor = snapshot.anchor_after(range.start);
3657 edits.push((anchor..anchor, new_text));
3658 } else {
3659 let edit_start = snapshot.anchor_after(range.start);
3660 let edit_end = snapshot.anchor_before(range.end);
3661 edits.push((edit_start..edit_end, new_text));
3662 }
3663 }
3664
3665 Ok(edits)
3666 })
3667 }
3668
3669 pub async fn handle_resolve_completion_documentation(
3670 this: Model<Self>,
3671 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
3672 mut cx: AsyncAppContext,
3673 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
3674 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
3675
3676 let completion = this
3677 .read_with(&mut cx, |this, _| {
3678 let id = LanguageServerId(envelope.payload.language_server_id as usize);
3679 let Some(server) = this.language_server_for_id(id) else {
3680 return Err(anyhow!("No language server {id}"));
3681 };
3682
3683 Ok(server.request::<lsp::request::ResolveCompletionItem>(lsp_completion))
3684 })??
3685 .await?;
3686
3687 let mut documentation_is_markdown = false;
3688 let documentation = match completion.documentation {
3689 Some(lsp::Documentation::String(text)) => text,
3690
3691 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
3692 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
3693 value
3694 }
3695
3696 _ => String::new(),
3697 };
3698
3699 // If we have a new buffer_id, that means we're talking to a new client
3700 // and want to check for new text_edits in the completion too.
3701 let mut old_start = None;
3702 let mut old_end = None;
3703 let mut new_text = String::default();
3704 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
3705 let buffer_snapshot = this.update(&mut cx, |this, cx| {
3706 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
3707 anyhow::Ok(buffer.read(cx).snapshot())
3708 })??;
3709
3710 if let Some(text_edit) = completion.text_edit.as_ref() {
3711 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
3712
3713 if let Some((old_range, mut text_edit_new_text)) = edit {
3714 LineEnding::normalize(&mut text_edit_new_text);
3715
3716 new_text = text_edit_new_text;
3717 old_start = Some(serialize_anchor(&old_range.start));
3718 old_end = Some(serialize_anchor(&old_range.end));
3719 }
3720 }
3721 }
3722
3723 Ok(proto::ResolveCompletionDocumentationResponse {
3724 documentation,
3725 documentation_is_markdown,
3726 old_start,
3727 old_end,
3728 new_text,
3729 })
3730 }
3731
3732 async fn handle_on_type_formatting(
3733 this: Model<Self>,
3734 envelope: TypedEnvelope<proto::OnTypeFormatting>,
3735 mut cx: AsyncAppContext,
3736 ) -> Result<proto::OnTypeFormattingResponse> {
3737 let on_type_formatting = this.update(&mut cx, |this, cx| {
3738 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
3739 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
3740 let position = envelope
3741 .payload
3742 .position
3743 .and_then(deserialize_anchor)
3744 .ok_or_else(|| anyhow!("invalid position"))?;
3745 Ok::<_, anyhow::Error>(this.apply_on_type_formatting(
3746 buffer,
3747 position,
3748 envelope.payload.trigger.clone(),
3749 cx,
3750 ))
3751 })??;
3752
3753 let transaction = on_type_formatting
3754 .await?
3755 .as_ref()
3756 .map(language::proto::serialize_transaction);
3757 Ok(proto::OnTypeFormattingResponse { transaction })
3758 }
3759
3760 async fn handle_refresh_inlay_hints(
3761 this: Model<Self>,
3762 _: TypedEnvelope<proto::RefreshInlayHints>,
3763 mut cx: AsyncAppContext,
3764 ) -> Result<proto::Ack> {
3765 this.update(&mut cx, |_, cx| {
3766 cx.emit(LspStoreEvent::RefreshInlayHints);
3767 })?;
3768 Ok(proto::Ack {})
3769 }
3770
3771 async fn handle_inlay_hints(
3772 this: Model<Self>,
3773 envelope: TypedEnvelope<proto::InlayHints>,
3774 mut cx: AsyncAppContext,
3775 ) -> Result<proto::InlayHintsResponse> {
3776 let sender_id = envelope.original_sender_id()?;
3777 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
3778 let buffer = this.update(&mut cx, |this, cx| {
3779 this.buffer_store.read(cx).get_existing(buffer_id)
3780 })??;
3781 buffer
3782 .update(&mut cx, |buffer, _| {
3783 buffer.wait_for_version(deserialize_version(&envelope.payload.version))
3784 })?
3785 .await
3786 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
3787
3788 let start = envelope
3789 .payload
3790 .start
3791 .and_then(deserialize_anchor)
3792 .context("missing range start")?;
3793 let end = envelope
3794 .payload
3795 .end
3796 .and_then(deserialize_anchor)
3797 .context("missing range end")?;
3798 let buffer_hints = this
3799 .update(&mut cx, |lsp_store, cx| {
3800 lsp_store.inlay_hints(buffer.clone(), start..end, cx)
3801 })?
3802 .await
3803 .context("inlay hints fetch")?;
3804
3805 this.update(&mut cx, |project, cx| {
3806 InlayHints::response_to_proto(
3807 buffer_hints,
3808 project,
3809 sender_id,
3810 &buffer.read(cx).version(),
3811 cx,
3812 )
3813 })
3814 }
3815
3816 async fn handle_resolve_inlay_hint(
3817 this: Model<Self>,
3818 envelope: TypedEnvelope<proto::ResolveInlayHint>,
3819 mut cx: AsyncAppContext,
3820 ) -> Result<proto::ResolveInlayHintResponse> {
3821 let proto_hint = envelope
3822 .payload
3823 .hint
3824 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
3825 let hint = InlayHints::proto_to_project_hint(proto_hint)
3826 .context("resolved proto inlay hint conversion")?;
3827 let buffer = this.update(&mut cx, |this, cx| {
3828 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
3829 this.buffer_store.read(cx).get_existing(buffer_id)
3830 })??;
3831 let response_hint = this
3832 .update(&mut cx, |this, cx| {
3833 this.resolve_inlay_hint(
3834 hint,
3835 buffer,
3836 LanguageServerId(envelope.payload.language_server_id as usize),
3837 cx,
3838 )
3839 })?
3840 .await
3841 .context("inlay hints fetch")?;
3842 Ok(proto::ResolveInlayHintResponse {
3843 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
3844 })
3845 }
3846
3847 async fn handle_open_buffer_for_symbol(
3848 this: Model<Self>,
3849 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
3850 mut cx: AsyncAppContext,
3851 ) -> Result<proto::OpenBufferForSymbolResponse> {
3852 let peer_id = envelope.original_sender_id()?;
3853 let symbol = envelope
3854 .payload
3855 .symbol
3856 .ok_or_else(|| anyhow!("invalid symbol"))?;
3857 let symbol = Self::deserialize_symbol(symbol)?;
3858 let symbol = this.update(&mut cx, |this, _| {
3859 let signature = this.symbol_signature(&symbol.path);
3860 if signature == symbol.signature {
3861 Ok(symbol)
3862 } else {
3863 Err(anyhow!("invalid symbol signature"))
3864 }
3865 })??;
3866 let buffer = this
3867 .update(&mut cx, |this, cx| {
3868 this.open_buffer_for_symbol(
3869 &Symbol {
3870 language_server_name: symbol.language_server_name,
3871 source_worktree_id: symbol.source_worktree_id,
3872 path: symbol.path,
3873 name: symbol.name,
3874 kind: symbol.kind,
3875 range: symbol.range,
3876 signature: symbol.signature,
3877 label: CodeLabel {
3878 text: Default::default(),
3879 runs: Default::default(),
3880 filter_range: Default::default(),
3881 },
3882 },
3883 cx,
3884 )
3885 })?
3886 .await?;
3887
3888 this.update(&mut cx, |this, cx| {
3889 let is_private = buffer
3890 .read(cx)
3891 .file()
3892 .map(|f| f.is_private())
3893 .unwrap_or_default();
3894 if is_private {
3895 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
3896 } else {
3897 this.buffer_store
3898 .update(cx, |buffer_store, cx| {
3899 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
3900 })
3901 .detach_and_log_err(cx);
3902 let buffer_id = buffer.read(cx).remote_id().to_proto();
3903 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
3904 }
3905 })?
3906 }
3907
3908 fn symbol_signature(&self, project_path: &ProjectPath) -> [u8; 32] {
3909 let mut hasher = Sha256::new();
3910 hasher.update(project_path.worktree_id.to_proto().to_be_bytes());
3911 hasher.update(project_path.path.to_string_lossy().as_bytes());
3912 hasher.update(self.nonce.to_be_bytes());
3913 hasher.finalize().as_slice().try_into().unwrap()
3914 }
3915
3916 pub async fn handle_get_project_symbols(
3917 this: Model<Self>,
3918 envelope: TypedEnvelope<proto::GetProjectSymbols>,
3919 mut cx: AsyncAppContext,
3920 ) -> Result<proto::GetProjectSymbolsResponse> {
3921 let symbols = this
3922 .update(&mut cx, |this, cx| {
3923 this.symbols(&envelope.payload.query, cx)
3924 })?
3925 .await?;
3926
3927 Ok(proto::GetProjectSymbolsResponse {
3928 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
3929 })
3930 }
3931
3932 pub async fn handle_restart_language_servers(
3933 this: Model<Self>,
3934 envelope: TypedEnvelope<proto::RestartLanguageServers>,
3935 mut cx: AsyncAppContext,
3936 ) -> Result<proto::Ack> {
3937 this.update(&mut cx, |this, cx| {
3938 let buffers: Vec<_> = envelope
3939 .payload
3940 .buffer_ids
3941 .into_iter()
3942 .flat_map(|buffer_id| {
3943 this.buffer_store
3944 .read(cx)
3945 .get(BufferId::new(buffer_id).log_err()?)
3946 })
3947 .collect();
3948 this.restart_language_servers_for_buffers(buffers, cx)
3949 })?;
3950
3951 Ok(proto::Ack {})
3952 }
3953
3954 async fn handle_apply_additional_edits_for_completion(
3955 this: Model<Self>,
3956 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
3957 mut cx: AsyncAppContext,
3958 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
3959 let (buffer, completion) = this.update(&mut cx, |this, cx| {
3960 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
3961 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
3962 let completion = Self::deserialize_completion(
3963 envelope
3964 .payload
3965 .completion
3966 .ok_or_else(|| anyhow!("invalid completion"))?,
3967 )?;
3968 anyhow::Ok((buffer, completion))
3969 })??;
3970
3971 let apply_additional_edits = this.update(&mut cx, |this, cx| {
3972 this.apply_additional_edits_for_completion(
3973 buffer,
3974 Completion {
3975 old_range: completion.old_range,
3976 new_text: completion.new_text,
3977 lsp_completion: completion.lsp_completion,
3978 server_id: completion.server_id,
3979 documentation: None,
3980 label: CodeLabel {
3981 text: Default::default(),
3982 runs: Default::default(),
3983 filter_range: Default::default(),
3984 },
3985 confirm: None,
3986 },
3987 false,
3988 cx,
3989 )
3990 })?;
3991
3992 Ok(proto::ApplyCompletionAdditionalEditsResponse {
3993 transaction: apply_additional_edits
3994 .await?
3995 .as_ref()
3996 .map(language::proto::serialize_transaction),
3997 })
3998 }
3999
4000 pub fn start_language_servers(
4001 &mut self,
4002 worktree: &Model<Worktree>,
4003 language: Arc<Language>,
4004 cx: &mut ModelContext<Self>,
4005 ) {
4006 let (root_file, is_local) =
4007 worktree.update(cx, |tree, cx| (tree.root_file(cx), tree.is_local()));
4008 let settings = language_settings(Some(&language), root_file.map(|f| f as _).as_ref(), cx);
4009 if !settings.enable_language_server || !is_local {
4010 return;
4011 }
4012
4013 let available_lsp_adapters = self.languages.clone().lsp_adapters(&language);
4014 let available_language_servers = available_lsp_adapters
4015 .iter()
4016 .map(|lsp_adapter| lsp_adapter.name.clone())
4017 .collect::<Vec<_>>();
4018
4019 let desired_language_servers =
4020 settings.customized_language_servers(&available_language_servers);
4021
4022 let mut enabled_lsp_adapters: Vec<Arc<CachedLspAdapter>> = Vec::new();
4023 for desired_language_server in desired_language_servers {
4024 if let Some(adapter) = available_lsp_adapters
4025 .iter()
4026 .find(|adapter| adapter.name == desired_language_server)
4027 {
4028 enabled_lsp_adapters.push(adapter.clone());
4029 continue;
4030 }
4031
4032 if let Some(adapter) = self
4033 .languages
4034 .load_available_lsp_adapter(&desired_language_server)
4035 {
4036 self.languages
4037 .register_lsp_adapter(language.name(), adapter.adapter.clone());
4038 enabled_lsp_adapters.push(adapter);
4039 continue;
4040 }
4041
4042 log::warn!(
4043 "no language server found matching '{}'",
4044 desired_language_server.0
4045 );
4046 }
4047
4048 log::info!(
4049 "starting language servers for {language}: {adapters}",
4050 language = language.name(),
4051 adapters = enabled_lsp_adapters
4052 .iter()
4053 .map(|adapter| adapter.name.0.as_ref())
4054 .join(", ")
4055 );
4056
4057 for adapter in &enabled_lsp_adapters {
4058 self.start_language_server(worktree, adapter.clone(), language.clone(), cx);
4059 }
4060
4061 // After starting all the language servers, reorder them to reflect the desired order
4062 // based on the settings.
4063 //
4064 // This is done, in part, to ensure that language servers loaded at different points
4065 // (e.g., native vs extension) still end up in the right order at the end, rather than
4066 // it being based on which language server happened to be loaded in first.
4067 self.languages
4068 .reorder_language_servers(&language, enabled_lsp_adapters);
4069 }
4070
4071 fn start_language_server(
4072 &mut self,
4073 worktree_handle: &Model<Worktree>,
4074 adapter: Arc<CachedLspAdapter>,
4075 language: Arc<Language>,
4076 cx: &mut ModelContext<Self>,
4077 ) {
4078 if adapter.reinstall_attempt_count.load(SeqCst) > MAX_SERVER_REINSTALL_ATTEMPT_COUNT {
4079 return;
4080 }
4081
4082 let worktree = worktree_handle.read(cx);
4083 let worktree_id = worktree.id();
4084 let worktree_path = worktree.abs_path();
4085 let key = (worktree_id, adapter.name.clone());
4086 if self.language_server_ids.contains_key(&key) {
4087 return;
4088 }
4089
4090 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
4091 let lsp_adapter_delegate = ProjectLspAdapterDelegate::new(self, worktree_handle, cx);
4092 let cli_environment = self
4093 .environment
4094 .as_ref()
4095 .and_then(|environment| environment.read(cx).get_cli_environment());
4096 let pending_server = match self.languages.create_pending_language_server(
4097 stderr_capture.clone(),
4098 language.clone(),
4099 adapter.clone(),
4100 Arc::clone(&worktree_path),
4101 lsp_adapter_delegate.clone(),
4102 cli_environment,
4103 cx,
4104 ) {
4105 Some(pending_server) => pending_server,
4106 None => return,
4107 };
4108
4109 let project_settings = ProjectSettings::get(
4110 Some(SettingsLocation {
4111 worktree_id: worktree_id.to_proto() as usize,
4112 path: Path::new(""),
4113 }),
4114 cx,
4115 );
4116 let lsp = project_settings.lsp.get(&adapter.name.0);
4117 let override_options = lsp.and_then(|s| s.initialization_options.clone());
4118
4119 let server_id = pending_server.server_id;
4120 let container_dir = pending_server.container_dir.clone();
4121 let state = LanguageServerState::Starting({
4122 let adapter = adapter.clone();
4123 let server_name = adapter.name.0.clone();
4124 let language = language.clone();
4125 let key = key.clone();
4126
4127 cx.spawn(move |this, mut cx| async move {
4128 let result = Self::setup_and_insert_language_server(
4129 this.clone(),
4130 lsp_adapter_delegate,
4131 override_options,
4132 pending_server,
4133 adapter.clone(),
4134 language.clone(),
4135 server_id,
4136 key,
4137 &mut cx,
4138 )
4139 .await;
4140
4141 match result {
4142 Ok(server) => {
4143 stderr_capture.lock().take();
4144 server
4145 }
4146
4147 Err(err) => {
4148 log::error!("failed to start language server {server_name:?}: {err}");
4149 log::error!("server stderr: {:?}", stderr_capture.lock().take());
4150
4151 let this = this.upgrade()?;
4152 let container_dir = container_dir?;
4153
4154 let attempt_count = adapter.reinstall_attempt_count.fetch_add(1, SeqCst);
4155 if attempt_count >= MAX_SERVER_REINSTALL_ATTEMPT_COUNT {
4156 let max = MAX_SERVER_REINSTALL_ATTEMPT_COUNT;
4157 log::error!("Hit {max} reinstallation attempts for {server_name:?}");
4158 return None;
4159 }
4160
4161 log::info!(
4162 "retrying installation of language server {server_name:?} in {}s",
4163 SERVER_REINSTALL_DEBOUNCE_TIMEOUT.as_secs()
4164 );
4165 cx.background_executor()
4166 .timer(SERVER_REINSTALL_DEBOUNCE_TIMEOUT)
4167 .await;
4168
4169 let installation_test_binary = adapter
4170 .installation_test_binary(container_dir.to_path_buf())
4171 .await;
4172
4173 this.update(&mut cx, |_, cx| {
4174 Self::check_errored_server(
4175 language,
4176 adapter,
4177 server_id,
4178 installation_test_binary,
4179 cx,
4180 )
4181 })
4182 .ok();
4183
4184 None
4185 }
4186 }
4187 })
4188 });
4189
4190 self.language_servers.insert(server_id, state);
4191 self.language_server_ids.insert(key, server_id);
4192 }
4193
4194 #[allow(clippy::too_many_arguments)]
4195 async fn setup_and_insert_language_server(
4196 this: WeakModel<Self>,
4197 delegate: Arc<dyn LspAdapterDelegate>,
4198 override_initialization_options: Option<serde_json::Value>,
4199 pending_server: PendingLanguageServer,
4200 adapter: Arc<CachedLspAdapter>,
4201 language: Arc<Language>,
4202 server_id: LanguageServerId,
4203 key: (WorktreeId, LanguageServerName),
4204 cx: &mut AsyncAppContext,
4205 ) -> Result<Option<Arc<LanguageServer>>> {
4206 let language_server = Self::setup_pending_language_server(
4207 this.clone(),
4208 override_initialization_options,
4209 pending_server,
4210 delegate,
4211 adapter.clone(),
4212 server_id,
4213 cx,
4214 )
4215 .await?;
4216
4217 let this = match this.upgrade() {
4218 Some(this) => this,
4219 None => return Err(anyhow!("failed to upgrade project handle")),
4220 };
4221
4222 this.update(cx, |this, cx| {
4223 this.insert_newly_running_language_server(
4224 language,
4225 adapter,
4226 language_server.clone(),
4227 server_id,
4228 key,
4229 cx,
4230 )
4231 })??;
4232
4233 Ok(Some(language_server))
4234 }
4235
4236 fn reinstall_language_server(
4237 &mut self,
4238 language: Arc<Language>,
4239 adapter: Arc<CachedLspAdapter>,
4240 server_id: LanguageServerId,
4241 cx: &mut ModelContext<Self>,
4242 ) -> Option<Task<()>> {
4243 log::info!("beginning to reinstall server");
4244
4245 let existing_server = match self.language_servers.remove(&server_id) {
4246 Some(LanguageServerState::Running { server, .. }) => Some(server),
4247 _ => None,
4248 };
4249
4250 self.worktree_store.update(cx, |store, cx| {
4251 for worktree in store.worktrees() {
4252 let key = (worktree.read(cx).id(), adapter.name.clone());
4253 self.language_server_ids.remove(&key);
4254 }
4255 });
4256
4257 Some(cx.spawn(move |this, mut cx| async move {
4258 if let Some(task) = existing_server.and_then(|server| server.shutdown()) {
4259 log::info!("shutting down existing server");
4260 task.await;
4261 }
4262
4263 // TODO: This is race-safe with regards to preventing new instances from
4264 // starting while deleting, but existing instances in other projects are going
4265 // to be very confused and messed up
4266 let Some(task) = this
4267 .update(&mut cx, |this, cx| {
4268 this.languages.delete_server_container(adapter.clone(), cx)
4269 })
4270 .log_err()
4271 else {
4272 return;
4273 };
4274 task.await;
4275
4276 this.update(&mut cx, |this, cx| {
4277 for worktree in this.worktree_store.read(cx).worktrees().collect::<Vec<_>>() {
4278 this.start_language_server(&worktree, adapter.clone(), language.clone(), cx);
4279 }
4280 })
4281 .ok();
4282 }))
4283 }
4284
4285 async fn shutdown_language_server(
4286 server_state: Option<LanguageServerState>,
4287 name: Arc<str>,
4288 cx: AsyncAppContext,
4289 ) {
4290 let server = match server_state {
4291 Some(LanguageServerState::Starting(task)) => {
4292 let mut timer = cx
4293 .background_executor()
4294 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
4295 .fuse();
4296
4297 select! {
4298 server = task.fuse() => server,
4299 _ = timer => {
4300 log::info!(
4301 "timeout waiting for language server {} to finish launching before stopping",
4302 name
4303 );
4304 None
4305 },
4306 }
4307 }
4308
4309 Some(LanguageServerState::Running { server, .. }) => Some(server),
4310
4311 None => None,
4312 };
4313
4314 if let Some(server) = server {
4315 if let Some(shutdown) = server.shutdown() {
4316 shutdown.await;
4317 }
4318 }
4319 }
4320
4321 // Returns a list of all of the worktrees which no longer have a language server and the root path
4322 // for the stopped server
4323 pub fn stop_language_server(
4324 &mut self,
4325 worktree_id: WorktreeId,
4326 adapter_name: LanguageServerName,
4327 cx: &mut ModelContext<Self>,
4328 ) -> Task<Vec<WorktreeId>> {
4329 let key = (worktree_id, adapter_name);
4330 if let Some(server_id) = self.language_server_ids.remove(&key) {
4331 let name = key.1 .0;
4332 log::info!("stopping language server {name}");
4333
4334 // Remove other entries for this language server as well
4335 let mut orphaned_worktrees = vec![worktree_id];
4336 let other_keys = self.language_server_ids.keys().cloned().collect::<Vec<_>>();
4337 for other_key in other_keys {
4338 if self.language_server_ids.get(&other_key) == Some(&server_id) {
4339 self.language_server_ids.remove(&other_key);
4340 orphaned_worktrees.push(other_key.0);
4341 }
4342 }
4343
4344 self.buffer_store.update(cx, |buffer_store, cx| {
4345 for buffer in buffer_store.buffers() {
4346 buffer.update(cx, |buffer, cx| {
4347 buffer.update_diagnostics(server_id, Default::default(), cx);
4348 });
4349 }
4350 });
4351
4352 let project_id = self.project_id;
4353 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
4354 summaries.retain(|path, summaries_by_server_id| {
4355 if summaries_by_server_id.remove(&server_id).is_some() {
4356 if let Some(downstream_client) = self.downstream_client.clone() {
4357 downstream_client
4358 .send(proto::UpdateDiagnosticSummary {
4359 project_id,
4360 worktree_id: worktree_id.to_proto(),
4361 summary: Some(proto::DiagnosticSummary {
4362 path: path.to_string_lossy().to_string(),
4363 language_server_id: server_id.0 as u64,
4364 error_count: 0,
4365 warning_count: 0,
4366 }),
4367 })
4368 .log_err();
4369 }
4370 !summaries_by_server_id.is_empty()
4371 } else {
4372 true
4373 }
4374 });
4375 }
4376
4377 for diagnostics in self.diagnostics.values_mut() {
4378 diagnostics.retain(|_, diagnostics_by_server_id| {
4379 if let Ok(ix) =
4380 diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0)
4381 {
4382 diagnostics_by_server_id.remove(ix);
4383 !diagnostics_by_server_id.is_empty()
4384 } else {
4385 true
4386 }
4387 });
4388 }
4389
4390 self.language_server_watched_paths.remove(&server_id);
4391 self.language_server_statuses.remove(&server_id);
4392 cx.notify();
4393
4394 let server_state = self.language_servers.remove(&server_id);
4395 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
4396 cx.spawn(move |_, cx| async move {
4397 Self::shutdown_language_server(server_state, name, cx).await;
4398 orphaned_worktrees
4399 })
4400 } else {
4401 Task::ready(Vec::new())
4402 }
4403 }
4404
4405 pub fn restart_language_servers_for_buffers(
4406 &mut self,
4407 buffers: impl IntoIterator<Item = Model<Buffer>>,
4408 cx: &mut ModelContext<Self>,
4409 ) {
4410 if let Some(client) = self.upstream_client.clone() {
4411 let request = client.request(proto::RestartLanguageServers {
4412 project_id: self.project_id,
4413 buffer_ids: buffers
4414 .into_iter()
4415 .map(|b| b.read(cx).remote_id().to_proto())
4416 .collect(),
4417 });
4418 cx.background_executor()
4419 .spawn(request)
4420 .detach_and_log_err(cx);
4421 } else {
4422 #[allow(clippy::mutable_key_type)]
4423 let language_server_lookup_info: HashSet<(Model<Worktree>, Arc<Language>)> = buffers
4424 .into_iter()
4425 .filter_map(|buffer| {
4426 let buffer = buffer.read(cx);
4427 let file = buffer.file()?;
4428 let worktree = File::from_dyn(Some(file))?.worktree.clone();
4429 let language = self
4430 .languages
4431 .language_for_file(file, Some(buffer.as_rope()), cx)
4432 .now_or_never()?
4433 .ok()?;
4434 Some((worktree, language))
4435 })
4436 .collect();
4437
4438 for (worktree, language) in language_server_lookup_info {
4439 self.restart_language_servers(worktree, language, cx);
4440 }
4441 }
4442 }
4443
4444 pub fn restart_language_servers(
4445 &mut self,
4446 worktree: Model<Worktree>,
4447 language: Arc<Language>,
4448 cx: &mut ModelContext<Self>,
4449 ) {
4450 let worktree_id = worktree.read(cx).id();
4451
4452 let stop_tasks = self
4453 .languages
4454 .clone()
4455 .lsp_adapters(&language)
4456 .iter()
4457 .map(|adapter| {
4458 let stop_task = self.stop_language_server(worktree_id, adapter.name.clone(), cx);
4459 (stop_task, adapter.name.clone())
4460 })
4461 .collect::<Vec<_>>();
4462 if stop_tasks.is_empty() {
4463 return;
4464 }
4465
4466 cx.spawn(move |this, mut cx| async move {
4467 // For each stopped language server, record all of the worktrees with which
4468 // it was associated.
4469 let mut affected_worktrees = Vec::new();
4470 for (stop_task, language_server_name) in stop_tasks {
4471 for affected_worktree_id in stop_task.await {
4472 affected_worktrees.push((affected_worktree_id, language_server_name.clone()));
4473 }
4474 }
4475
4476 this.update(&mut cx, |this, cx| {
4477 // Restart the language server for the given worktree.
4478 this.start_language_servers(&worktree, language.clone(), cx);
4479
4480 // Lookup new server ids and set them for each of the orphaned worktrees
4481 for (affected_worktree_id, language_server_name) in affected_worktrees {
4482 if let Some(new_server_id) = this
4483 .language_server_ids
4484 .get(&(worktree_id, language_server_name.clone()))
4485 .cloned()
4486 {
4487 this.language_server_ids
4488 .insert((affected_worktree_id, language_server_name), new_server_id);
4489 }
4490 }
4491 })
4492 .ok();
4493 })
4494 .detach();
4495 }
4496
4497 fn check_errored_server(
4498 language: Arc<Language>,
4499 adapter: Arc<CachedLspAdapter>,
4500 server_id: LanguageServerId,
4501 installation_test_binary: Option<LanguageServerBinary>,
4502 cx: &mut ModelContext<Self>,
4503 ) {
4504 if !adapter.can_be_reinstalled() {
4505 log::info!(
4506 "Validation check requested for {:?} but it cannot be reinstalled",
4507 adapter.name.0
4508 );
4509 return;
4510 }
4511
4512 cx.spawn(move |this, mut cx| async move {
4513 log::info!("About to spawn test binary");
4514
4515 // A lack of test binary counts as a failure
4516 let process = installation_test_binary.and_then(|binary| {
4517 smol::process::Command::new(&binary.path)
4518 .current_dir(&binary.path)
4519 .args(binary.arguments)
4520 .stdin(Stdio::piped())
4521 .stdout(Stdio::piped())
4522 .stderr(Stdio::inherit())
4523 .kill_on_drop(true)
4524 .spawn()
4525 .ok()
4526 });
4527
4528 const PROCESS_TIMEOUT: Duration = Duration::from_secs(5);
4529 let mut timeout = cx.background_executor().timer(PROCESS_TIMEOUT).fuse();
4530
4531 let mut errored = false;
4532 if let Some(mut process) = process {
4533 futures::select! {
4534 status = process.status().fuse() => match status {
4535 Ok(status) => errored = !status.success(),
4536 Err(_) => errored = true,
4537 },
4538
4539 _ = timeout => {
4540 log::info!("test binary time-ed out, this counts as a success");
4541 _ = process.kill();
4542 }
4543 }
4544 } else {
4545 log::warn!("test binary failed to launch");
4546 errored = true;
4547 }
4548
4549 if errored {
4550 log::warn!("test binary check failed");
4551 let task = this
4552 .update(&mut cx, move |this, cx| {
4553 this.reinstall_language_server(language, adapter, server_id, cx)
4554 })
4555 .ok()
4556 .flatten();
4557
4558 if let Some(task) = task {
4559 task.await;
4560 }
4561 }
4562 })
4563 .detach();
4564 }
4565
4566 async fn setup_pending_language_server(
4567 this: WeakModel<Self>,
4568 override_options: Option<serde_json::Value>,
4569 pending_server: PendingLanguageServer,
4570 delegate: Arc<dyn LspAdapterDelegate>,
4571 adapter: Arc<CachedLspAdapter>,
4572 server_id: LanguageServerId,
4573 cx: &mut AsyncAppContext,
4574 ) -> Result<Arc<LanguageServer>> {
4575 let workspace_config = adapter
4576 .adapter
4577 .clone()
4578 .workspace_configuration(&delegate, cx)
4579 .await?;
4580 let (language_server, mut initialization_options) = pending_server.task.await?;
4581
4582 let name = language_server.name();
4583 language_server
4584 .on_notification::<lsp::notification::PublishDiagnostics, _>({
4585 let adapter = adapter.clone();
4586 let this = this.clone();
4587 move |mut params, mut cx| {
4588 let adapter = adapter.clone();
4589 if let Some(this) = this.upgrade() {
4590 adapter.process_diagnostics(&mut params);
4591 this.update(&mut cx, |this, cx| {
4592 this.update_diagnostics(
4593 server_id,
4594 params,
4595 &adapter.disk_based_diagnostic_sources,
4596 cx,
4597 )
4598 .log_err();
4599 })
4600 .ok();
4601 }
4602 }
4603 })
4604 .detach();
4605
4606 language_server
4607 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
4608 let adapter = adapter.adapter.clone();
4609 let delegate = delegate.clone();
4610 move |params, mut cx| {
4611 let adapter = adapter.clone();
4612 let delegate = delegate.clone();
4613 async move {
4614 let workspace_config =
4615 adapter.workspace_configuration(&delegate, &mut cx).await?;
4616 Ok(params
4617 .items
4618 .into_iter()
4619 .map(|item| {
4620 if let Some(section) = &item.section {
4621 workspace_config
4622 .get(section)
4623 .cloned()
4624 .unwrap_or(serde_json::Value::Null)
4625 } else {
4626 workspace_config.clone()
4627 }
4628 })
4629 .collect())
4630 }
4631 }
4632 })
4633 .detach();
4634
4635 // Even though we don't have handling for these requests, respond to them to
4636 // avoid stalling any language server like `gopls` which waits for a response
4637 // to these requests when initializing.
4638 language_server
4639 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
4640 let this = this.clone();
4641 move |params, mut cx| {
4642 let this = this.clone();
4643 async move {
4644 this.update(&mut cx, |this, _| {
4645 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
4646 {
4647 if let lsp::NumberOrString::String(token) = params.token {
4648 status.progress_tokens.insert(token);
4649 }
4650 }
4651 })?;
4652
4653 Ok(())
4654 }
4655 }
4656 })
4657 .detach();
4658
4659 language_server
4660 .on_request::<lsp::request::RegisterCapability, _, _>({
4661 let this = this.clone();
4662 move |params, mut cx| {
4663 let this = this.clone();
4664 async move {
4665 for reg in params.registrations {
4666 match reg.method.as_str() {
4667 "workspace/didChangeWatchedFiles" => {
4668 if let Some(options) = reg.register_options {
4669 let options = serde_json::from_value(options)?;
4670 this.update(&mut cx, |this, cx| {
4671 this.on_lsp_did_change_watched_files(
4672 server_id, ®.id, options, cx,
4673 );
4674 })?;
4675 }
4676 }
4677 "textDocument/rangeFormatting" => {
4678 this.update(&mut cx, |this, _| {
4679 if let Some(server) = this.language_server_for_id(server_id)
4680 {
4681 let options = reg
4682 .register_options
4683 .map(|options| {
4684 serde_json::from_value::<
4685 lsp::DocumentRangeFormattingOptions,
4686 >(
4687 options
4688 )
4689 })
4690 .transpose()?;
4691 let provider = match options {
4692 None => OneOf::Left(true),
4693 Some(options) => OneOf::Right(options),
4694 };
4695 server.update_capabilities(|capabilities| {
4696 capabilities.document_range_formatting_provider =
4697 Some(provider);
4698 })
4699 }
4700 anyhow::Ok(())
4701 })??;
4702 }
4703 "textDocument/onTypeFormatting" => {
4704 this.update(&mut cx, |this, _| {
4705 if let Some(server) = this.language_server_for_id(server_id)
4706 {
4707 let options = reg
4708 .register_options
4709 .map(|options| {
4710 serde_json::from_value::<
4711 lsp::DocumentOnTypeFormattingOptions,
4712 >(
4713 options
4714 )
4715 })
4716 .transpose()?;
4717 if let Some(options) = options {
4718 server.update_capabilities(|capabilities| {
4719 capabilities
4720 .document_on_type_formatting_provider =
4721 Some(options);
4722 })
4723 }
4724 }
4725 anyhow::Ok(())
4726 })??;
4727 }
4728 "textDocument/formatting" => {
4729 this.update(&mut cx, |this, _| {
4730 if let Some(server) = this.language_server_for_id(server_id)
4731 {
4732 let options = reg
4733 .register_options
4734 .map(|options| {
4735 serde_json::from_value::<
4736 lsp::DocumentFormattingOptions,
4737 >(
4738 options
4739 )
4740 })
4741 .transpose()?;
4742 let provider = match options {
4743 None => OneOf::Left(true),
4744 Some(options) => OneOf::Right(options),
4745 };
4746 server.update_capabilities(|capabilities| {
4747 capabilities.document_formatting_provider =
4748 Some(provider);
4749 })
4750 }
4751 anyhow::Ok(())
4752 })??;
4753 }
4754 _ => log::warn!("unhandled capability registration: {reg:?}"),
4755 }
4756 }
4757 Ok(())
4758 }
4759 }
4760 })
4761 .detach();
4762
4763 language_server
4764 .on_request::<lsp::request::UnregisterCapability, _, _>({
4765 let this = this.clone();
4766 move |params, mut cx| {
4767 let this = this.clone();
4768 async move {
4769 for unreg in params.unregisterations.iter() {
4770 match unreg.method.as_str() {
4771 "workspace/didChangeWatchedFiles" => {
4772 this.update(&mut cx, |this, cx| {
4773 this.on_lsp_unregister_did_change_watched_files(
4774 server_id, &unreg.id, cx,
4775 );
4776 })?;
4777 }
4778 "textDocument/rangeFormatting" => {
4779 this.update(&mut cx, |this, _| {
4780 if let Some(server) = this.language_server_for_id(server_id)
4781 {
4782 server.update_capabilities(|capabilities| {
4783 capabilities.document_range_formatting_provider =
4784 None
4785 })
4786 }
4787 })?;
4788 }
4789 "textDocument/onTypeFormatting" => {
4790 this.update(&mut cx, |this, _| {
4791 if let Some(server) = this.language_server_for_id(server_id)
4792 {
4793 server.update_capabilities(|capabilities| {
4794 capabilities.document_on_type_formatting_provider =
4795 None;
4796 })
4797 }
4798 })?;
4799 }
4800 "textDocument/formatting" => {
4801 this.update(&mut cx, |this, _| {
4802 if let Some(server) = this.language_server_for_id(server_id)
4803 {
4804 server.update_capabilities(|capabilities| {
4805 capabilities.document_formatting_provider = None;
4806 })
4807 }
4808 })?;
4809 }
4810 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
4811 }
4812 }
4813 Ok(())
4814 }
4815 }
4816 })
4817 .detach();
4818
4819 language_server
4820 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
4821 let adapter = adapter.clone();
4822 let this = this.clone();
4823 move |params, cx| {
4824 Self::on_lsp_workspace_edit(
4825 this.clone(),
4826 params,
4827 server_id,
4828 adapter.clone(),
4829 cx,
4830 )
4831 }
4832 })
4833 .detach();
4834
4835 language_server
4836 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
4837 let this = this.clone();
4838 move |(), mut cx| {
4839 let this = this.clone();
4840 async move {
4841 this.update(&mut cx, |this, cx| {
4842 cx.emit(LspStoreEvent::RefreshInlayHints);
4843 this.downstream_client.as_ref().map(|client| {
4844 client.send(proto::RefreshInlayHints {
4845 project_id: this.project_id,
4846 })
4847 })
4848 })?
4849 .transpose()?;
4850 Ok(())
4851 }
4852 }
4853 })
4854 .detach();
4855
4856 language_server
4857 .on_request::<lsp::request::ShowMessageRequest, _, _>({
4858 let this = this.clone();
4859 let name = name.to_string();
4860 move |params, mut cx| {
4861 let this = this.clone();
4862 let name = name.to_string();
4863 async move {
4864 let actions = params.actions.unwrap_or_default();
4865 let (tx, mut rx) = smol::channel::bounded(1);
4866 let request = LanguageServerPromptRequest {
4867 level: match params.typ {
4868 lsp::MessageType::ERROR => PromptLevel::Critical,
4869 lsp::MessageType::WARNING => PromptLevel::Warning,
4870 _ => PromptLevel::Info,
4871 },
4872 message: params.message,
4873 actions,
4874 response_channel: tx,
4875 lsp_name: name.clone(),
4876 };
4877
4878 if let Ok(_) = this.update(&mut cx, |_, cx| {
4879 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
4880 }) {
4881 let response = rx.next().await;
4882
4883 Ok(response)
4884 } else {
4885 Ok(None)
4886 }
4887 }
4888 }
4889 })
4890 .detach();
4891
4892 let disk_based_diagnostics_progress_token =
4893 adapter.disk_based_diagnostics_progress_token.clone();
4894
4895 language_server
4896 .on_notification::<ServerStatus, _>({
4897 let this = this.clone();
4898 let name = name.to_string();
4899 move |params, mut cx| {
4900 let this = this.clone();
4901 let name = name.to_string();
4902 if let Some(ref message) = params.message {
4903 let message = message.trim();
4904 if !message.is_empty() {
4905 let formatted_message = format!(
4906 "Language server {name} (id {server_id}) status update: {message}"
4907 );
4908 match params.health {
4909 ServerHealthStatus::Ok => log::info!("{}", formatted_message),
4910 ServerHealthStatus::Warning => log::warn!("{}", formatted_message),
4911 ServerHealthStatus::Error => {
4912 log::error!("{}", formatted_message);
4913 let (tx, _rx) = smol::channel::bounded(1);
4914 let request = LanguageServerPromptRequest {
4915 level: PromptLevel::Critical,
4916 message: params.message.unwrap_or_default(),
4917 actions: Vec::new(),
4918 response_channel: tx,
4919 lsp_name: name.clone(),
4920 };
4921 let _ = this
4922 .update(&mut cx, |_, cx| {
4923 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
4924 })
4925 .ok();
4926 }
4927 ServerHealthStatus::Other(status) => {
4928 log::info!(
4929 "Unknown server health: {status}\n{formatted_message}"
4930 )
4931 }
4932 }
4933 }
4934 }
4935 }
4936 })
4937 .detach();
4938 language_server
4939 .on_notification::<lsp::notification::ShowMessage, _>({
4940 let this = this.clone();
4941 let name = name.to_string();
4942 move |params, mut cx| {
4943 let this = this.clone();
4944 let name = name.to_string();
4945
4946 let (tx, _) = smol::channel::bounded(1);
4947 let request = LanguageServerPromptRequest {
4948 level: match params.typ {
4949 lsp::MessageType::ERROR => PromptLevel::Critical,
4950 lsp::MessageType::WARNING => PromptLevel::Warning,
4951 _ => PromptLevel::Info,
4952 },
4953 message: params.message,
4954 actions: vec![],
4955 response_channel: tx,
4956 lsp_name: name.clone(),
4957 };
4958
4959 let _ = this.update(&mut cx, |_, cx| {
4960 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
4961 });
4962 }
4963 })
4964 .detach();
4965 language_server
4966 .on_notification::<lsp::notification::Progress, _>({
4967 let this = this.clone();
4968 move |params, mut cx| {
4969 if let Some(this) = this.upgrade() {
4970 this.update(&mut cx, |this, cx| {
4971 this.on_lsp_progress(
4972 params,
4973 server_id,
4974 disk_based_diagnostics_progress_token.clone(),
4975 cx,
4976 );
4977 })
4978 .ok();
4979 }
4980 }
4981 })
4982 .detach();
4983
4984 language_server
4985 .on_notification::<lsp::notification::LogMessage, _>({
4986 let this = this.clone();
4987 move |params, mut cx| {
4988 if let Some(this) = this.upgrade() {
4989 this.update(&mut cx, |_, cx| {
4990 cx.emit(LspStoreEvent::LanguageServerLog(
4991 server_id,
4992 LanguageServerLogType::Log(params.typ),
4993 params.message,
4994 ));
4995 })
4996 .ok();
4997 }
4998 }
4999 })
5000 .detach();
5001
5002 language_server
5003 .on_notification::<lsp::notification::LogTrace, _>({
5004 let this = this.clone();
5005 move |params, mut cx| {
5006 if let Some(this) = this.upgrade() {
5007 this.update(&mut cx, |_, cx| {
5008 cx.emit(LspStoreEvent::LanguageServerLog(
5009 server_id,
5010 LanguageServerLogType::Trace(params.verbose),
5011 params.message,
5012 ));
5013 })
5014 .ok();
5015 }
5016 }
5017 })
5018 .detach();
5019
5020 match (&mut initialization_options, override_options) {
5021 (Some(initialization_options), Some(override_options)) => {
5022 merge_json_value_into(override_options, initialization_options);
5023 }
5024 (None, override_options) => initialization_options = override_options,
5025 _ => {}
5026 }
5027
5028 let language_server = cx
5029 .update(|cx| language_server.initialize(initialization_options, cx))?
5030 .await
5031 .inspect_err(|_| {
5032 if let Some(this) = this.upgrade() {
5033 this.update(cx, |_, cx| {
5034 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
5035 })
5036 .ok();
5037 }
5038 })?;
5039
5040 language_server
5041 .notify::<lsp::notification::DidChangeConfiguration>(
5042 lsp::DidChangeConfigurationParams {
5043 settings: workspace_config,
5044 },
5045 )
5046 .ok();
5047
5048 Ok(language_server)
5049 }
5050
5051 pub fn update_diagnostics(
5052 &mut self,
5053 language_server_id: LanguageServerId,
5054 mut params: lsp::PublishDiagnosticsParams,
5055 disk_based_sources: &[String],
5056 cx: &mut ModelContext<Self>,
5057 ) -> Result<()> {
5058 let abs_path = params
5059 .uri
5060 .to_file_path()
5061 .map_err(|_| anyhow!("URI is not a file"))?;
5062 let mut diagnostics = Vec::default();
5063 let mut primary_diagnostic_group_ids = HashMap::default();
5064 let mut sources_by_group_id = HashMap::default();
5065 let mut supporting_diagnostics = HashMap::default();
5066
5067 // Ensure that primary diagnostics are always the most severe
5068 params.diagnostics.sort_by_key(|item| item.severity);
5069
5070 for diagnostic in ¶ms.diagnostics {
5071 let source = diagnostic.source.as_ref();
5072 let code = diagnostic.code.as_ref().map(|code| match code {
5073 lsp::NumberOrString::Number(code) => code.to_string(),
5074 lsp::NumberOrString::String(code) => code.clone(),
5075 });
5076 let range = range_from_lsp(diagnostic.range);
5077 let is_supporting = diagnostic
5078 .related_information
5079 .as_ref()
5080 .map_or(false, |infos| {
5081 infos.iter().any(|info| {
5082 primary_diagnostic_group_ids.contains_key(&(
5083 source,
5084 code.clone(),
5085 range_from_lsp(info.location.range),
5086 ))
5087 })
5088 });
5089
5090 let is_unnecessary = diagnostic.tags.as_ref().map_or(false, |tags| {
5091 tags.iter().any(|tag| *tag == DiagnosticTag::UNNECESSARY)
5092 });
5093
5094 if is_supporting {
5095 supporting_diagnostics.insert(
5096 (source, code.clone(), range),
5097 (diagnostic.severity, is_unnecessary),
5098 );
5099 } else {
5100 let group_id = post_inc(&mut self.next_diagnostic_group_id);
5101 let is_disk_based =
5102 source.map_or(false, |source| disk_based_sources.contains(source));
5103
5104 sources_by_group_id.insert(group_id, source);
5105 primary_diagnostic_group_ids
5106 .insert((source, code.clone(), range.clone()), group_id);
5107
5108 diagnostics.push(DiagnosticEntry {
5109 range,
5110 diagnostic: Diagnostic {
5111 source: diagnostic.source.clone(),
5112 code: code.clone(),
5113 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
5114 message: diagnostic.message.trim().to_string(),
5115 group_id,
5116 is_primary: true,
5117 is_disk_based,
5118 is_unnecessary,
5119 data: diagnostic.data.clone(),
5120 },
5121 });
5122 if let Some(infos) = &diagnostic.related_information {
5123 for info in infos {
5124 if info.location.uri == params.uri && !info.message.is_empty() {
5125 let range = range_from_lsp(info.location.range);
5126 diagnostics.push(DiagnosticEntry {
5127 range,
5128 diagnostic: Diagnostic {
5129 source: diagnostic.source.clone(),
5130 code: code.clone(),
5131 severity: DiagnosticSeverity::INFORMATION,
5132 message: info.message.trim().to_string(),
5133 group_id,
5134 is_primary: false,
5135 is_disk_based,
5136 is_unnecessary: false,
5137 data: diagnostic.data.clone(),
5138 },
5139 });
5140 }
5141 }
5142 }
5143 }
5144 }
5145
5146 for entry in &mut diagnostics {
5147 let diagnostic = &mut entry.diagnostic;
5148 if !diagnostic.is_primary {
5149 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
5150 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
5151 source,
5152 diagnostic.code.clone(),
5153 entry.range.clone(),
5154 )) {
5155 if let Some(severity) = severity {
5156 diagnostic.severity = severity;
5157 }
5158 diagnostic.is_unnecessary = is_unnecessary;
5159 }
5160 }
5161 }
5162
5163 self.update_diagnostic_entries(
5164 language_server_id,
5165 abs_path,
5166 params.version,
5167 diagnostics,
5168 cx,
5169 )?;
5170 Ok(())
5171 }
5172
5173 fn insert_newly_running_language_server(
5174 &mut self,
5175 language: Arc<Language>,
5176 adapter: Arc<CachedLspAdapter>,
5177 language_server: Arc<LanguageServer>,
5178 server_id: LanguageServerId,
5179 key: (WorktreeId, LanguageServerName),
5180 cx: &mut ModelContext<Self>,
5181 ) -> Result<()> {
5182 // If the language server for this key doesn't match the server id, don't store the
5183 // server. Which will cause it to be dropped, killing the process
5184 if self
5185 .language_server_ids
5186 .get(&key)
5187 .map(|id| id != &server_id)
5188 .unwrap_or(false)
5189 {
5190 return Ok(());
5191 }
5192
5193 // Update language_servers collection with Running variant of LanguageServerState
5194 // indicating that the server is up and running and ready
5195 self.language_servers.insert(
5196 server_id,
5197 LanguageServerState::Running {
5198 adapter: adapter.clone(),
5199 language: language.clone(),
5200 server: language_server.clone(),
5201 simulate_disk_based_diagnostics_completion: None,
5202 },
5203 );
5204
5205 self.language_server_statuses.insert(
5206 server_id,
5207 LanguageServerStatus {
5208 name: language_server.name().to_string(),
5209 pending_work: Default::default(),
5210 has_pending_diagnostic_updates: false,
5211 progress_tokens: Default::default(),
5212 },
5213 );
5214
5215 cx.emit(LspStoreEvent::LanguageServerAdded(server_id));
5216
5217 if let Some(downstream_client) = self.downstream_client.as_ref() {
5218 downstream_client.send(proto::StartLanguageServer {
5219 project_id: self.project_id,
5220 server: Some(proto::LanguageServer {
5221 id: server_id.0 as u64,
5222 name: language_server.name().to_string(),
5223 }),
5224 })?;
5225 }
5226
5227 // Tell the language server about every open buffer in the worktree that matches the language.
5228 self.buffer_store.update(cx, |buffer_store, cx| {
5229 for buffer_handle in buffer_store.buffers() {
5230 let buffer = buffer_handle.read(cx);
5231 let file = match File::from_dyn(buffer.file()) {
5232 Some(file) => file,
5233 None => continue,
5234 };
5235 let language = match buffer.language() {
5236 Some(language) => language,
5237 None => continue,
5238 };
5239
5240 if file.worktree.read(cx).id() != key.0
5241 || !self
5242 .languages
5243 .lsp_adapters(&language)
5244 .iter()
5245 .any(|a| a.name == key.1)
5246 {
5247 continue;
5248 }
5249
5250 let file = match file.as_local() {
5251 Some(file) => file,
5252 None => continue,
5253 };
5254
5255 let versions = self
5256 .buffer_snapshots
5257 .entry(buffer.remote_id())
5258 .or_default()
5259 .entry(server_id)
5260 .or_insert_with(|| {
5261 vec![LspBufferSnapshot {
5262 version: 0,
5263 snapshot: buffer.text_snapshot(),
5264 }]
5265 });
5266
5267 let snapshot = versions.last().unwrap();
5268 let version = snapshot.version;
5269 let initial_snapshot = &snapshot.snapshot;
5270 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
5271 language_server.notify::<lsp::notification::DidOpenTextDocument>(
5272 lsp::DidOpenTextDocumentParams {
5273 text_document: lsp::TextDocumentItem::new(
5274 uri,
5275 adapter.language_id(&language),
5276 version,
5277 initial_snapshot.text(),
5278 ),
5279 },
5280 )?;
5281
5282 buffer_handle.update(cx, |buffer, cx| {
5283 buffer.set_completion_triggers(
5284 language_server
5285 .capabilities()
5286 .completion_provider
5287 .as_ref()
5288 .and_then(|provider| provider.trigger_characters.clone())
5289 .unwrap_or_default(),
5290 cx,
5291 )
5292 });
5293 }
5294 anyhow::Ok(())
5295 })?;
5296
5297 cx.notify();
5298 Ok(())
5299 }
5300
5301 fn buffer_snapshot_for_lsp_version(
5302 &mut self,
5303 buffer: &Model<Buffer>,
5304 server_id: LanguageServerId,
5305 version: Option<i32>,
5306 cx: &AppContext,
5307 ) -> Result<TextBufferSnapshot> {
5308 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
5309
5310 if let Some(version) = version {
5311 let buffer_id = buffer.read(cx).remote_id();
5312 let snapshots = self
5313 .buffer_snapshots
5314 .get_mut(&buffer_id)
5315 .and_then(|m| m.get_mut(&server_id))
5316 .ok_or_else(|| {
5317 anyhow!("no snapshots found for buffer {buffer_id} and server {server_id}")
5318 })?;
5319
5320 let found_snapshot = snapshots
5321 .binary_search_by_key(&version, |e| e.version)
5322 .map(|ix| snapshots[ix].snapshot.clone())
5323 .map_err(|_| {
5324 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
5325 })?;
5326
5327 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
5328 Ok(found_snapshot)
5329 } else {
5330 Ok((buffer.read(cx)).text_snapshot())
5331 }
5332 }
5333
5334 pub fn language_servers_running_disk_based_diagnostics(
5335 &self,
5336 ) -> impl Iterator<Item = LanguageServerId> + '_ {
5337 self.language_server_statuses
5338 .iter()
5339 .filter_map(|(id, status)| {
5340 if status.has_pending_diagnostic_updates {
5341 Some(*id)
5342 } else {
5343 None
5344 }
5345 })
5346 }
5347
5348 pub(crate) fn language_servers_for_buffer<'a>(
5349 &'a self,
5350 buffer: &'a Buffer,
5351 cx: &'a AppContext,
5352 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
5353 self.language_server_ids_for_buffer(buffer, cx)
5354 .into_iter()
5355 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
5356 LanguageServerState::Running {
5357 adapter, server, ..
5358 } => Some((adapter, server)),
5359 _ => None,
5360 })
5361 }
5362
5363 pub(crate) fn cancel_language_server_work_for_buffers(
5364 &mut self,
5365 buffers: impl IntoIterator<Item = Model<Buffer>>,
5366 cx: &mut ModelContext<Self>,
5367 ) {
5368 let servers = buffers
5369 .into_iter()
5370 .flat_map(|buffer| {
5371 self.language_server_ids_for_buffer(buffer.read(cx), cx)
5372 .into_iter()
5373 })
5374 .collect::<HashSet<_>>();
5375
5376 for server_id in servers {
5377 self.cancel_language_server_work(server_id, None, cx);
5378 }
5379 }
5380
5381 pub fn language_servers(
5382 &self,
5383 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName, WorktreeId)> {
5384 self.language_server_ids
5385 .iter()
5386 .map(|((worktree_id, server_name), server_id)| {
5387 (*server_id, server_name.clone(), *worktree_id)
5388 })
5389 }
5390
5391 pub fn register_supplementary_language_server(
5392 &mut self,
5393 id: LanguageServerId,
5394 name: LanguageServerName,
5395 server: Arc<LanguageServer>,
5396 cx: &mut ModelContext<Self>,
5397 ) {
5398 self.supplementary_language_servers
5399 .insert(id, (name, server));
5400 cx.emit(LspStoreEvent::LanguageServerAdded(id));
5401 }
5402
5403 pub fn unregister_supplementary_language_server(
5404 &mut self,
5405 id: LanguageServerId,
5406 cx: &mut ModelContext<Self>,
5407 ) {
5408 self.supplementary_language_servers.remove(&id);
5409 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
5410 }
5411
5412 pub fn supplementary_language_servers(
5413 &self,
5414 ) -> impl '_ + Iterator<Item = (&LanguageServerId, &LanguageServerName)> {
5415 self.supplementary_language_servers
5416 .iter()
5417 .map(|(id, (name, _))| (id, name))
5418 }
5419
5420 pub fn language_server_adapter_for_id(
5421 &self,
5422 id: LanguageServerId,
5423 ) -> Option<Arc<CachedLspAdapter>> {
5424 if let Some(LanguageServerState::Running { adapter, .. }) = self.language_servers.get(&id) {
5425 Some(adapter.clone())
5426 } else {
5427 None
5428 }
5429 }
5430
5431 pub fn update_local_worktree_language_servers(
5432 &mut self,
5433 worktree_handle: &Model<Worktree>,
5434 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
5435 cx: &mut ModelContext<Self>,
5436 ) {
5437 if changes.is_empty() {
5438 return;
5439 }
5440
5441 let worktree_id = worktree_handle.read(cx).id();
5442 let mut language_server_ids = self
5443 .language_server_ids
5444 .iter()
5445 .filter_map(|((server_worktree_id, _), server_id)| {
5446 (*server_worktree_id == worktree_id).then_some(*server_id)
5447 })
5448 .collect::<Vec<_>>();
5449 language_server_ids.sort();
5450 language_server_ids.dedup();
5451
5452 let abs_path = worktree_handle.read(cx).abs_path();
5453 for server_id in &language_server_ids {
5454 if let Some(LanguageServerState::Running { server, .. }) =
5455 self.language_servers.get(server_id)
5456 {
5457 if let Some(watched_paths) = self
5458 .language_server_watched_paths
5459 .get(&server_id)
5460 .and_then(|paths| paths.get(&worktree_id))
5461 {
5462 let params = lsp::DidChangeWatchedFilesParams {
5463 changes: changes
5464 .iter()
5465 .filter_map(|(path, _, change)| {
5466 if !watched_paths.is_match(&path) {
5467 return None;
5468 }
5469 let typ = match change {
5470 PathChange::Loaded => return None,
5471 PathChange::Added => lsp::FileChangeType::CREATED,
5472 PathChange::Removed => lsp::FileChangeType::DELETED,
5473 PathChange::Updated => lsp::FileChangeType::CHANGED,
5474 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
5475 };
5476 Some(lsp::FileEvent {
5477 uri: lsp::Url::from_file_path(abs_path.join(path)).unwrap(),
5478 typ,
5479 })
5480 })
5481 .collect(),
5482 };
5483 if !params.changes.is_empty() {
5484 server
5485 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
5486 .log_err();
5487 }
5488 }
5489 }
5490 }
5491 }
5492
5493 pub(crate) fn cancel_language_server_work(
5494 &mut self,
5495 server_id: LanguageServerId,
5496 token_to_cancel: Option<String>,
5497 _cx: &mut ModelContext<Self>,
5498 ) {
5499 let status = self.language_server_statuses.get(&server_id);
5500 let server = self.language_servers.get(&server_id);
5501 if let Some((server, status)) = server.zip(status) {
5502 if let LanguageServerState::Running { server, .. } = server {
5503 for (token, progress) in &status.pending_work {
5504 if let Some(token_to_cancel) = token_to_cancel.as_ref() {
5505 if token != token_to_cancel {
5506 continue;
5507 }
5508 }
5509 if progress.is_cancellable {
5510 server
5511 .notify::<lsp::notification::WorkDoneProgressCancel>(
5512 WorkDoneProgressCancelParams {
5513 token: lsp::NumberOrString::String(token.clone()),
5514 },
5515 )
5516 .ok();
5517 }
5518 }
5519 }
5520 }
5521 }
5522
5523 pub fn wait_for_remote_buffer(
5524 &mut self,
5525 id: BufferId,
5526 cx: &mut ModelContext<Self>,
5527 ) -> Task<Result<Model<Buffer>>> {
5528 self.buffer_store.update(cx, |buffer_store, cx| {
5529 buffer_store.wait_for_remote_buffer(id, cx)
5530 })
5531 }
5532
5533 pub(crate) fn language_server_ids_for_buffer(
5534 &self,
5535 buffer: &Buffer,
5536 cx: &AppContext,
5537 ) -> Vec<LanguageServerId> {
5538 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
5539 let worktree_id = file.worktree_id(cx);
5540 self.languages
5541 .lsp_adapters(&language)
5542 .iter()
5543 .flat_map(|adapter| {
5544 let key = (worktree_id, adapter.name.clone());
5545 self.language_server_ids.get(&key).copied()
5546 })
5547 .collect()
5548 } else {
5549 Vec::new()
5550 }
5551 }
5552
5553 pub async fn deserialize_text_edits(
5554 this: Model<Self>,
5555 buffer_to_edit: Model<Buffer>,
5556 edits: Vec<lsp::TextEdit>,
5557 push_to_history: bool,
5558 _: Arc<CachedLspAdapter>,
5559 language_server: Arc<LanguageServer>,
5560 cx: &mut AsyncAppContext,
5561 ) -> Result<Option<Transaction>> {
5562 let edits = this
5563 .update(cx, |this, cx| {
5564 this.edits_from_lsp(
5565 &buffer_to_edit,
5566 edits,
5567 language_server.server_id(),
5568 None,
5569 cx,
5570 )
5571 })?
5572 .await?;
5573
5574 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
5575 buffer.finalize_last_transaction();
5576 buffer.start_transaction();
5577 for (range, text) in edits {
5578 buffer.edit([(range, text)], None, cx);
5579 }
5580
5581 if buffer.end_transaction(cx).is_some() {
5582 let transaction = buffer.finalize_last_transaction().unwrap().clone();
5583 if !push_to_history {
5584 buffer.forget_transaction(transaction.id);
5585 }
5586 Some(transaction)
5587 } else {
5588 None
5589 }
5590 })?;
5591
5592 Ok(transaction)
5593 }
5594
5595 pub async fn deserialize_workspace_edit(
5596 this: Model<Self>,
5597 edit: lsp::WorkspaceEdit,
5598 push_to_history: bool,
5599 lsp_adapter: Arc<CachedLspAdapter>,
5600 language_server: Arc<LanguageServer>,
5601 cx: &mut AsyncAppContext,
5602 ) -> Result<ProjectTransaction> {
5603 let fs = this.update(cx, |this, _| this.fs.clone())?;
5604 let mut operations = Vec::new();
5605 if let Some(document_changes) = edit.document_changes {
5606 match document_changes {
5607 lsp::DocumentChanges::Edits(edits) => {
5608 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
5609 }
5610 lsp::DocumentChanges::Operations(ops) => operations = ops,
5611 }
5612 } else if let Some(changes) = edit.changes {
5613 operations.extend(changes.into_iter().map(|(uri, edits)| {
5614 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
5615 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
5616 uri,
5617 version: None,
5618 },
5619 edits: edits.into_iter().map(Edit::Plain).collect(),
5620 })
5621 }));
5622 }
5623
5624 let mut project_transaction = ProjectTransaction::default();
5625 for operation in operations {
5626 match operation {
5627 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
5628 let abs_path = op
5629 .uri
5630 .to_file_path()
5631 .map_err(|_| anyhow!("can't convert URI to path"))?;
5632
5633 if let Some(parent_path) = abs_path.parent() {
5634 fs.create_dir(parent_path).await?;
5635 }
5636 if abs_path.ends_with("/") {
5637 fs.create_dir(&abs_path).await?;
5638 } else {
5639 fs.create_file(
5640 &abs_path,
5641 op.options
5642 .map(|options| fs::CreateOptions {
5643 overwrite: options.overwrite.unwrap_or(false),
5644 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
5645 })
5646 .unwrap_or_default(),
5647 )
5648 .await?;
5649 }
5650 }
5651
5652 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
5653 let source_abs_path = op
5654 .old_uri
5655 .to_file_path()
5656 .map_err(|_| anyhow!("can't convert URI to path"))?;
5657 let target_abs_path = op
5658 .new_uri
5659 .to_file_path()
5660 .map_err(|_| anyhow!("can't convert URI to path"))?;
5661 fs.rename(
5662 &source_abs_path,
5663 &target_abs_path,
5664 op.options
5665 .map(|options| fs::RenameOptions {
5666 overwrite: options.overwrite.unwrap_or(false),
5667 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
5668 })
5669 .unwrap_or_default(),
5670 )
5671 .await?;
5672 }
5673
5674 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
5675 let abs_path = op
5676 .uri
5677 .to_file_path()
5678 .map_err(|_| anyhow!("can't convert URI to path"))?;
5679 let options = op
5680 .options
5681 .map(|options| fs::RemoveOptions {
5682 recursive: options.recursive.unwrap_or(false),
5683 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
5684 })
5685 .unwrap_or_default();
5686 if abs_path.ends_with("/") {
5687 fs.remove_dir(&abs_path, options).await?;
5688 } else {
5689 fs.remove_file(&abs_path, options).await?;
5690 }
5691 }
5692
5693 lsp::DocumentChangeOperation::Edit(op) => {
5694 let buffer_to_edit = this
5695 .update(cx, |this, cx| {
5696 this.open_local_buffer_via_lsp(
5697 op.text_document.uri.clone(),
5698 language_server.server_id(),
5699 lsp_adapter.name.clone(),
5700 cx,
5701 )
5702 })?
5703 .await?;
5704
5705 let edits = this
5706 .update(cx, |this, cx| {
5707 let path = buffer_to_edit.read(cx).project_path(cx);
5708 let active_entry = this.active_entry;
5709 let is_active_entry = path.clone().map_or(false, |project_path| {
5710 this.worktree_store
5711 .read(cx)
5712 .entry_for_path(&project_path, cx)
5713 .map_or(false, |entry| Some(entry.id) == active_entry)
5714 });
5715
5716 let (mut edits, mut snippet_edits) = (vec![], vec![]);
5717 for edit in op.edits {
5718 match edit {
5719 Edit::Plain(edit) => edits.push(edit),
5720 Edit::Annotated(edit) => edits.push(edit.text_edit),
5721 Edit::Snippet(edit) => {
5722 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
5723 else {
5724 continue;
5725 };
5726
5727 if is_active_entry {
5728 snippet_edits.push((edit.range, snippet));
5729 } else {
5730 // Since this buffer is not focused, apply a normal edit.
5731 edits.push(TextEdit {
5732 range: edit.range,
5733 new_text: snippet.text,
5734 });
5735 }
5736 }
5737 }
5738 }
5739 if !snippet_edits.is_empty() {
5740 let buffer_id = buffer_to_edit.read(cx).remote_id();
5741 let version = if let Some(buffer_version) = op.text_document.version
5742 {
5743 this.buffer_snapshots
5744 .get(&buffer_id)
5745 .and_then(|server_to_snapshots| {
5746 let all_snapshots = server_to_snapshots
5747 .get(&language_server.server_id())?;
5748 all_snapshots
5749 .binary_search_by_key(&buffer_version, |snapshot| {
5750 snapshot.version
5751 })
5752 .ok()
5753 .and_then(|index| all_snapshots.get(index))
5754 })
5755 .map(|lsp_snapshot| lsp_snapshot.snapshot.version())
5756 } else {
5757 Some(buffer_to_edit.read(cx).saved_version())
5758 };
5759
5760 let most_recent_edit = version.and_then(|version| {
5761 version.iter().max_by_key(|timestamp| timestamp.value)
5762 });
5763 // Check if the edit that triggered that edit has been made by this participant.
5764
5765 if let Some(most_recent_edit) = most_recent_edit {
5766 cx.emit(LspStoreEvent::SnippetEdit {
5767 buffer_id,
5768 edits: snippet_edits,
5769 most_recent_edit,
5770 });
5771 }
5772 }
5773
5774 this.edits_from_lsp(
5775 &buffer_to_edit,
5776 edits,
5777 language_server.server_id(),
5778 op.text_document.version,
5779 cx,
5780 )
5781 })?
5782 .await?;
5783
5784 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
5785 buffer.finalize_last_transaction();
5786 buffer.start_transaction();
5787 for (range, text) in edits {
5788 buffer.edit([(range, text)], None, cx);
5789 }
5790 let transaction = if buffer.end_transaction(cx).is_some() {
5791 let transaction = buffer.finalize_last_transaction().unwrap().clone();
5792 if !push_to_history {
5793 buffer.forget_transaction(transaction.id);
5794 }
5795 Some(transaction)
5796 } else {
5797 None
5798 };
5799
5800 transaction
5801 })?;
5802 if let Some(transaction) = transaction {
5803 project_transaction.0.insert(buffer_to_edit, transaction);
5804 }
5805 }
5806 }
5807 }
5808
5809 Ok(project_transaction)
5810 }
5811
5812 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
5813 proto::Symbol {
5814 language_server_name: symbol.language_server_name.0.to_string(),
5815 source_worktree_id: symbol.source_worktree_id.to_proto(),
5816 worktree_id: symbol.path.worktree_id.to_proto(),
5817 path: symbol.path.path.to_string_lossy().to_string(),
5818 name: symbol.name.clone(),
5819 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
5820 start: Some(proto::PointUtf16 {
5821 row: symbol.range.start.0.row,
5822 column: symbol.range.start.0.column,
5823 }),
5824 end: Some(proto::PointUtf16 {
5825 row: symbol.range.end.0.row,
5826 column: symbol.range.end.0.column,
5827 }),
5828 signature: symbol.signature.to_vec(),
5829 }
5830 }
5831
5832 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
5833 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
5834 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
5835 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
5836 let path = ProjectPath {
5837 worktree_id,
5838 path: PathBuf::from(serialized_symbol.path).into(),
5839 };
5840
5841 let start = serialized_symbol
5842 .start
5843 .ok_or_else(|| anyhow!("invalid start"))?;
5844 let end = serialized_symbol
5845 .end
5846 .ok_or_else(|| anyhow!("invalid end"))?;
5847 Ok(CoreSymbol {
5848 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
5849 source_worktree_id,
5850 path,
5851 name: serialized_symbol.name,
5852 range: Unclipped(PointUtf16::new(start.row, start.column))
5853 ..Unclipped(PointUtf16::new(end.row, end.column)),
5854 kind,
5855 signature: serialized_symbol
5856 .signature
5857 .try_into()
5858 .map_err(|_| anyhow!("invalid signature"))?,
5859 })
5860 }
5861
5862 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
5863 proto::Completion {
5864 old_start: Some(serialize_anchor(&completion.old_range.start)),
5865 old_end: Some(serialize_anchor(&completion.old_range.end)),
5866 new_text: completion.new_text.clone(),
5867 server_id: completion.server_id.0 as u64,
5868 lsp_completion: serde_json::to_vec(&completion.lsp_completion).unwrap(),
5869 }
5870 }
5871
5872 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
5873 let old_start = completion
5874 .old_start
5875 .and_then(deserialize_anchor)
5876 .ok_or_else(|| anyhow!("invalid old start"))?;
5877 let old_end = completion
5878 .old_end
5879 .and_then(deserialize_anchor)
5880 .ok_or_else(|| anyhow!("invalid old end"))?;
5881 let lsp_completion = serde_json::from_slice(&completion.lsp_completion)?;
5882
5883 Ok(CoreCompletion {
5884 old_range: old_start..old_end,
5885 new_text: completion.new_text,
5886 server_id: LanguageServerId(completion.server_id as usize),
5887 lsp_completion,
5888 })
5889 }
5890
5891 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
5892 proto::CodeAction {
5893 server_id: action.server_id.0 as u64,
5894 start: Some(serialize_anchor(&action.range.start)),
5895 end: Some(serialize_anchor(&action.range.end)),
5896 lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(),
5897 }
5898 }
5899
5900 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
5901 let start = action
5902 .start
5903 .and_then(deserialize_anchor)
5904 .ok_or_else(|| anyhow!("invalid start"))?;
5905 let end = action
5906 .end
5907 .and_then(deserialize_anchor)
5908 .ok_or_else(|| anyhow!("invalid end"))?;
5909 let lsp_action = serde_json::from_slice(&action.lsp_action)?;
5910 Ok(CodeAction {
5911 server_id: LanguageServerId(action.server_id as usize),
5912 range: start..end,
5913 lsp_action,
5914 })
5915 }
5916}
5917
5918impl EventEmitter<LspStoreEvent> for LspStore {}
5919
5920fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
5921 hover
5922 .contents
5923 .retain(|hover_block| !hover_block.text.trim().is_empty());
5924 if hover.contents.is_empty() {
5925 None
5926 } else {
5927 Some(hover)
5928 }
5929}
5930
5931async fn populate_labels_for_completions(
5932 mut new_completions: Vec<CoreCompletion>,
5933 language_registry: &Arc<LanguageRegistry>,
5934 language: Option<Arc<Language>>,
5935 lsp_adapter: Option<Arc<CachedLspAdapter>>,
5936 completions: &mut Vec<Completion>,
5937) {
5938 let lsp_completions = new_completions
5939 .iter_mut()
5940 .map(|completion| mem::take(&mut completion.lsp_completion))
5941 .collect::<Vec<_>>();
5942
5943 let labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
5944 lsp_adapter
5945 .labels_for_completions(&lsp_completions, language)
5946 .await
5947 .log_err()
5948 .unwrap_or_default()
5949 } else {
5950 Vec::new()
5951 };
5952
5953 for ((completion, lsp_completion), label) in new_completions
5954 .into_iter()
5955 .zip(lsp_completions)
5956 .zip(labels.into_iter().chain(iter::repeat(None)))
5957 {
5958 let documentation = if let Some(docs) = &lsp_completion.documentation {
5959 Some(prepare_completion_documentation(docs, &language_registry, language.clone()).await)
5960 } else {
5961 None
5962 };
5963
5964 completions.push(Completion {
5965 old_range: completion.old_range,
5966 new_text: completion.new_text,
5967 label: label.unwrap_or_else(|| {
5968 CodeLabel::plain(
5969 lsp_completion.label.clone(),
5970 lsp_completion.filter_text.as_deref(),
5971 )
5972 }),
5973 server_id: completion.server_id,
5974 documentation,
5975 lsp_completion,
5976 confirm: None,
5977 })
5978 }
5979}
5980
5981#[derive(Debug)]
5982pub enum LanguageServerToQuery {
5983 Primary,
5984 Other(LanguageServerId),
5985}
5986
5987struct LspBufferSnapshot {
5988 version: i32,
5989 snapshot: TextBufferSnapshot,
5990}
5991
5992/// A prompt requested by LSP server.
5993#[derive(Clone, Debug)]
5994pub struct LanguageServerPromptRequest {
5995 pub level: PromptLevel,
5996 pub message: String,
5997 pub actions: Vec<MessageActionItem>,
5998 pub lsp_name: String,
5999 pub(crate) response_channel: Sender<MessageActionItem>,
6000}
6001
6002impl LanguageServerPromptRequest {
6003 pub async fn respond(self, index: usize) -> Option<()> {
6004 if let Some(response) = self.actions.into_iter().nth(index) {
6005 self.response_channel.send(response).await.ok()
6006 } else {
6007 None
6008 }
6009 }
6010}
6011impl PartialEq for LanguageServerPromptRequest {
6012 fn eq(&self, other: &Self) -> bool {
6013 self.message == other.message && self.actions == other.actions
6014 }
6015}
6016
6017#[derive(Clone, Debug, PartialEq)]
6018pub enum LanguageServerLogType {
6019 Log(MessageType),
6020 Trace(Option<String>),
6021}
6022
6023pub enum LanguageServerState {
6024 Starting(Task<Option<Arc<LanguageServer>>>),
6025
6026 Running {
6027 language: Arc<Language>,
6028 adapter: Arc<CachedLspAdapter>,
6029 server: Arc<LanguageServer>,
6030 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
6031 },
6032}
6033
6034#[derive(Clone, Debug, Serialize)]
6035pub struct LanguageServerProgress {
6036 pub is_disk_based_diagnostics_progress: bool,
6037 pub is_cancellable: bool,
6038 pub title: Option<String>,
6039 pub message: Option<String>,
6040 pub percentage: Option<usize>,
6041 #[serde(skip_serializing)]
6042 pub last_update_at: Instant,
6043}
6044
6045#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
6046pub struct DiagnosticSummary {
6047 pub error_count: usize,
6048 pub warning_count: usize,
6049}
6050
6051impl DiagnosticSummary {
6052 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
6053 let mut this = Self {
6054 error_count: 0,
6055 warning_count: 0,
6056 };
6057
6058 for entry in diagnostics {
6059 if entry.diagnostic.is_primary {
6060 match entry.diagnostic.severity {
6061 DiagnosticSeverity::ERROR => this.error_count += 1,
6062 DiagnosticSeverity::WARNING => this.warning_count += 1,
6063 _ => {}
6064 }
6065 }
6066 }
6067
6068 this
6069 }
6070
6071 pub fn is_empty(&self) -> bool {
6072 self.error_count == 0 && self.warning_count == 0
6073 }
6074
6075 pub fn to_proto(
6076 &self,
6077 language_server_id: LanguageServerId,
6078 path: &Path,
6079 ) -> proto::DiagnosticSummary {
6080 proto::DiagnosticSummary {
6081 path: path.to_string_lossy().to_string(),
6082 language_server_id: language_server_id.0 as u64,
6083 error_count: self.error_count as u32,
6084 warning_count: self.warning_count as u32,
6085 }
6086 }
6087}
6088
6089fn glob_literal_prefix(glob: &str) -> &str {
6090 let mut literal_end = 0;
6091 for (i, part) in glob.split(path::MAIN_SEPARATOR).enumerate() {
6092 if part.contains(&['*', '?', '{', '}']) {
6093 break;
6094 } else {
6095 if i > 0 {
6096 // Account for separator prior to this part
6097 literal_end += path::MAIN_SEPARATOR.len_utf8();
6098 }
6099 literal_end += part.len();
6100 }
6101 }
6102 &glob[..literal_end]
6103}
6104
6105pub struct ProjectLspAdapterDelegate {
6106 lsp_store: WeakModel<LspStore>,
6107 worktree: worktree::Snapshot,
6108 fs: Arc<dyn Fs>,
6109 http_client: Arc<dyn HttpClient>,
6110 language_registry: Arc<LanguageRegistry>,
6111 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
6112}
6113
6114impl ProjectLspAdapterDelegate {
6115 pub fn new(
6116 lsp_store: &LspStore,
6117 worktree: &Model<Worktree>,
6118 cx: &mut ModelContext<LspStore>,
6119 ) -> Arc<Self> {
6120 let worktree_id = worktree.read(cx).id();
6121 let worktree_abs_path = worktree.read(cx).abs_path();
6122 let load_shell_env_task = if let Some(environment) = &lsp_store.environment {
6123 environment.update(cx, |env, cx| {
6124 env.get_environment(Some(worktree_id), Some(worktree_abs_path), cx)
6125 })
6126 } else {
6127 Task::ready(None).shared()
6128 };
6129
6130 let Some(http_client) = lsp_store.http_client.clone() else {
6131 panic!("ProjectLspAdapterDelegate cannot be constructedd on an ssh-remote yet")
6132 };
6133
6134 Arc::new(Self {
6135 lsp_store: cx.weak_model(),
6136 worktree: worktree.read(cx).snapshot(),
6137 fs: lsp_store.fs.clone(),
6138 http_client,
6139 language_registry: lsp_store.languages.clone(),
6140 load_shell_env_task,
6141 })
6142 }
6143}
6144
6145#[async_trait]
6146impl LspAdapterDelegate for ProjectLspAdapterDelegate {
6147 fn show_notification(&self, message: &str, cx: &mut AppContext) {
6148 self.lsp_store
6149 .update(cx, |_, cx| {
6150 cx.emit(LspStoreEvent::Notification(message.to_owned()))
6151 })
6152 .ok();
6153 }
6154
6155 fn http_client(&self) -> Arc<dyn HttpClient> {
6156 self.http_client.clone()
6157 }
6158
6159 fn worktree_id(&self) -> u64 {
6160 self.worktree.id().to_proto()
6161 }
6162
6163 fn worktree_root_path(&self) -> &Path {
6164 self.worktree.abs_path().as_ref()
6165 }
6166
6167 async fn shell_env(&self) -> HashMap<String, String> {
6168 let task = self.load_shell_env_task.clone();
6169 task.await.unwrap_or_default()
6170 }
6171
6172 #[cfg(not(target_os = "windows"))]
6173 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
6174 let worktree_abs_path = self.worktree.abs_path();
6175 let shell_path = self.shell_env().await.get("PATH").cloned();
6176 which::which_in(command, shell_path.as_ref(), &worktree_abs_path).ok()
6177 }
6178
6179 #[cfg(target_os = "windows")]
6180 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
6181 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
6182 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
6183 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
6184 which::which(command).ok()
6185 }
6186
6187 fn update_status(
6188 &self,
6189 server_name: LanguageServerName,
6190 status: language::LanguageServerBinaryStatus,
6191 ) {
6192 self.language_registry
6193 .update_lsp_status(server_name, status);
6194 }
6195
6196 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
6197 if self.worktree.entry_for_path(&path).is_none() {
6198 return Err(anyhow!("no such path {path:?}"));
6199 }
6200 let path = self.worktree.absolutize(path.as_ref())?;
6201 let content = self.fs.load(&path).await?;
6202 Ok(content)
6203 }
6204}
6205
6206async fn populate_labels_for_symbols(
6207 symbols: Vec<CoreSymbol>,
6208 language_registry: &Arc<LanguageRegistry>,
6209 default_language: Option<Arc<Language>>,
6210 lsp_adapter: Option<Arc<CachedLspAdapter>>,
6211 output: &mut Vec<Symbol>,
6212) {
6213 #[allow(clippy::mutable_key_type)]
6214 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
6215
6216 let mut unknown_path = None;
6217 for symbol in symbols {
6218 let language = language_registry
6219 .language_for_file_path(&symbol.path.path)
6220 .await
6221 .ok()
6222 .or_else(|| {
6223 unknown_path.get_or_insert(symbol.path.path.clone());
6224 default_language.clone()
6225 });
6226 symbols_by_language
6227 .entry(language)
6228 .or_default()
6229 .push(symbol);
6230 }
6231
6232 if let Some(unknown_path) = unknown_path {
6233 log::info!(
6234 "no language found for symbol path {}",
6235 unknown_path.display()
6236 );
6237 }
6238
6239 let mut label_params = Vec::new();
6240 for (language, mut symbols) in symbols_by_language {
6241 label_params.clear();
6242 label_params.extend(
6243 symbols
6244 .iter_mut()
6245 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
6246 );
6247
6248 let mut labels = Vec::new();
6249 if let Some(language) = language {
6250 let lsp_adapter = lsp_adapter
6251 .clone()
6252 .or_else(|| language_registry.lsp_adapters(&language).first().cloned());
6253 if let Some(lsp_adapter) = lsp_adapter {
6254 labels = lsp_adapter
6255 .labels_for_symbols(&label_params, &language)
6256 .await
6257 .log_err()
6258 .unwrap_or_default();
6259 }
6260 }
6261
6262 for ((symbol, (name, _)), label) in symbols
6263 .into_iter()
6264 .zip(label_params.drain(..))
6265 .zip(labels.into_iter().chain(iter::repeat(None)))
6266 {
6267 output.push(Symbol {
6268 language_server_name: symbol.language_server_name,
6269 source_worktree_id: symbol.source_worktree_id,
6270 path: symbol.path,
6271 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
6272 name,
6273 kind: symbol.kind,
6274 range: symbol.range,
6275 signature: symbol.signature,
6276 });
6277 }
6278 }
6279}
6280
6281fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
6282 match server.capabilities().text_document_sync.as_ref()? {
6283 lsp::TextDocumentSyncCapability::Kind(kind) => match kind {
6284 &lsp::TextDocumentSyncKind::NONE => None,
6285 &lsp::TextDocumentSyncKind::FULL => Some(true),
6286 &lsp::TextDocumentSyncKind::INCREMENTAL => Some(false),
6287 _ => None,
6288 },
6289 lsp::TextDocumentSyncCapability::Options(options) => match options.save.as_ref()? {
6290 lsp::TextDocumentSyncSaveOptions::Supported(supported) => {
6291 if *supported {
6292 Some(true)
6293 } else {
6294 None
6295 }
6296 }
6297 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
6298 Some(save_options.include_text.unwrap_or(false))
6299 }
6300 },
6301 }
6302}
6303
6304#[cfg(test)]
6305#[test]
6306fn test_glob_literal_prefix() {
6307 assert_eq!(glob_literal_prefix("**/*.js"), "");
6308 assert_eq!(glob_literal_prefix("node_modules/**/*.js"), "node_modules");
6309 assert_eq!(glob_literal_prefix("foo/{bar,baz}.js"), "foo");
6310 assert_eq!(glob_literal_prefix("foo/bar/baz.js"), "foo/bar/baz.js");
6311}