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