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