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::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::BufferEvent,
505 cx: &mut ModelContext<Self>,
506 ) {
507 match event {
508 language::BufferEvent::Edited { .. } => {
509 self.on_buffer_edited(buffer, cx);
510 }
511
512 language::BufferEvent::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
2934 let mut response_results = server_ids
2935 .into_iter()
2936 .map(|server_id| {
2937 self.request_lsp(
2938 buffer.clone(),
2939 LanguageServerToQuery::Other(server_id),
2940 request.clone(),
2941 cx,
2942 )
2943 })
2944 .collect::<FuturesUnordered<_>>();
2945
2946 cx.spawn(|_, _| async move {
2947 let mut responses = Vec::with_capacity(response_results.len());
2948 while let Some(response_result) = response_results.next().await {
2949 if let Some(response) = response_result.log_err() {
2950 responses.push(response);
2951 }
2952 }
2953 responses
2954 })
2955 }
2956
2957 async fn handle_lsp_command<T: LspCommand>(
2958 this: Model<Self>,
2959 envelope: TypedEnvelope<T::ProtoRequest>,
2960 mut cx: AsyncAppContext,
2961 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
2962 where
2963 <T::LspRequest as lsp::request::Request>::Params: Send,
2964 <T::LspRequest as lsp::request::Request>::Result: Send,
2965 {
2966 let sender_id = envelope.original_sender_id().unwrap_or_default();
2967 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
2968 let buffer_handle = this.update(&mut cx, |this, cx| {
2969 this.buffer_store.read(cx).get_existing(buffer_id)
2970 })??;
2971 let request = T::from_proto(
2972 envelope.payload,
2973 this.clone(),
2974 buffer_handle.clone(),
2975 cx.clone(),
2976 )
2977 .await?;
2978 let response = this
2979 .update(&mut cx, |this, cx| {
2980 this.request_lsp(
2981 buffer_handle.clone(),
2982 LanguageServerToQuery::Primary,
2983 request,
2984 cx,
2985 )
2986 })?
2987 .await?;
2988 this.update(&mut cx, |this, cx| {
2989 Ok(T::response_to_proto(
2990 response,
2991 this,
2992 sender_id,
2993 &buffer_handle.read(cx).version(),
2994 cx,
2995 ))
2996 })?
2997 }
2998
2999 async fn handle_multi_lsp_query(
3000 this: Model<Self>,
3001 envelope: TypedEnvelope<proto::MultiLspQuery>,
3002 mut cx: AsyncAppContext,
3003 ) -> Result<proto::MultiLspQueryResponse> {
3004 let sender_id = envelope.original_sender_id().unwrap_or_default();
3005 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
3006 let version = deserialize_version(&envelope.payload.version);
3007 let buffer = this.update(&mut cx, |this, cx| {
3008 this.buffer_store.read(cx).get_existing(buffer_id)
3009 })??;
3010 buffer
3011 .update(&mut cx, |buffer, _| {
3012 buffer.wait_for_version(version.clone())
3013 })?
3014 .await?;
3015 let buffer_version = buffer.update(&mut cx, |buffer, _| buffer.version())?;
3016 match envelope
3017 .payload
3018 .strategy
3019 .context("invalid request without the strategy")?
3020 {
3021 proto::multi_lsp_query::Strategy::All(_) => {
3022 // currently, there's only one multiple language servers query strategy,
3023 // so just ensure it's specified correctly
3024 }
3025 }
3026 match envelope.payload.request {
3027 Some(proto::multi_lsp_query::Request::GetHover(get_hover)) => {
3028 let get_hover =
3029 GetHover::from_proto(get_hover, this.clone(), buffer.clone(), cx.clone())
3030 .await?;
3031 let all_hovers = this
3032 .update(&mut cx, |this, cx| {
3033 this.request_multiple_lsp_locally(
3034 &buffer,
3035 Some(get_hover.position),
3036 get_hover,
3037 cx,
3038 )
3039 })?
3040 .await
3041 .into_iter()
3042 .filter_map(|hover| remove_empty_hover_blocks(hover?));
3043 this.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
3044 responses: all_hovers
3045 .map(|hover| proto::LspResponse {
3046 response: Some(proto::lsp_response::Response::GetHoverResponse(
3047 GetHover::response_to_proto(
3048 Some(hover),
3049 project,
3050 sender_id,
3051 &buffer_version,
3052 cx,
3053 ),
3054 )),
3055 })
3056 .collect(),
3057 })
3058 }
3059 Some(proto::multi_lsp_query::Request::GetCodeActions(get_code_actions)) => {
3060 let get_code_actions = GetCodeActions::from_proto(
3061 get_code_actions,
3062 this.clone(),
3063 buffer.clone(),
3064 cx.clone(),
3065 )
3066 .await?;
3067
3068 let all_actions = this
3069 .update(&mut cx, |project, cx| {
3070 project.request_multiple_lsp_locally(
3071 &buffer,
3072 Some(get_code_actions.range.start),
3073 get_code_actions,
3074 cx,
3075 )
3076 })?
3077 .await
3078 .into_iter();
3079
3080 this.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
3081 responses: all_actions
3082 .map(|code_actions| proto::LspResponse {
3083 response: Some(proto::lsp_response::Response::GetCodeActionsResponse(
3084 GetCodeActions::response_to_proto(
3085 code_actions,
3086 project,
3087 sender_id,
3088 &buffer_version,
3089 cx,
3090 ),
3091 )),
3092 })
3093 .collect(),
3094 })
3095 }
3096 Some(proto::multi_lsp_query::Request::GetSignatureHelp(get_signature_help)) => {
3097 let get_signature_help = GetSignatureHelp::from_proto(
3098 get_signature_help,
3099 this.clone(),
3100 buffer.clone(),
3101 cx.clone(),
3102 )
3103 .await?;
3104
3105 let all_signatures = this
3106 .update(&mut cx, |project, cx| {
3107 project.request_multiple_lsp_locally(
3108 &buffer,
3109 Some(get_signature_help.position),
3110 get_signature_help,
3111 cx,
3112 )
3113 })?
3114 .await
3115 .into_iter();
3116
3117 this.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
3118 responses: all_signatures
3119 .map(|signature_help| proto::LspResponse {
3120 response: Some(
3121 proto::lsp_response::Response::GetSignatureHelpResponse(
3122 GetSignatureHelp::response_to_proto(
3123 signature_help,
3124 project,
3125 sender_id,
3126 &buffer_version,
3127 cx,
3128 ),
3129 ),
3130 ),
3131 })
3132 .collect(),
3133 })
3134 }
3135 None => anyhow::bail!("empty multi lsp query request"),
3136 }
3137 }
3138
3139 async fn handle_apply_code_action(
3140 this: Model<Self>,
3141 envelope: TypedEnvelope<proto::ApplyCodeAction>,
3142 mut cx: AsyncAppContext,
3143 ) -> Result<proto::ApplyCodeActionResponse> {
3144 let sender_id = envelope.original_sender_id().unwrap_or_default();
3145 let action = Self::deserialize_code_action(
3146 envelope
3147 .payload
3148 .action
3149 .ok_or_else(|| anyhow!("invalid action"))?,
3150 )?;
3151 let apply_code_action = this.update(&mut cx, |this, cx| {
3152 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
3153 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
3154 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
3155 })??;
3156
3157 let project_transaction = apply_code_action.await?;
3158 let project_transaction = this.update(&mut cx, |this, cx| {
3159 this.buffer_store.update(cx, |buffer_store, cx| {
3160 buffer_store.serialize_project_transaction_for_peer(
3161 project_transaction,
3162 sender_id,
3163 cx,
3164 )
3165 })
3166 })?;
3167 Ok(proto::ApplyCodeActionResponse {
3168 transaction: Some(project_transaction),
3169 })
3170 }
3171
3172 async fn handle_update_diagnostic_summary(
3173 this: Model<Self>,
3174 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
3175 mut cx: AsyncAppContext,
3176 ) -> Result<()> {
3177 this.update(&mut cx, |this, cx| {
3178 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
3179 if let Some(message) = envelope.payload.summary {
3180 let project_path = ProjectPath {
3181 worktree_id,
3182 path: Path::new(&message.path).into(),
3183 };
3184 let path = project_path.path.clone();
3185 let server_id = LanguageServerId(message.language_server_id as usize);
3186 let summary = DiagnosticSummary {
3187 error_count: message.error_count as usize,
3188 warning_count: message.warning_count as usize,
3189 };
3190
3191 if summary.is_empty() {
3192 if let Some(worktree_summaries) =
3193 this.diagnostic_summaries.get_mut(&worktree_id)
3194 {
3195 if let Some(summaries) = worktree_summaries.get_mut(&path) {
3196 summaries.remove(&server_id);
3197 if summaries.is_empty() {
3198 worktree_summaries.remove(&path);
3199 }
3200 }
3201 }
3202 } else {
3203 this.diagnostic_summaries
3204 .entry(worktree_id)
3205 .or_default()
3206 .entry(path)
3207 .or_default()
3208 .insert(server_id, summary);
3209 }
3210 cx.emit(LspStoreEvent::DiagnosticsUpdated {
3211 language_server_id: LanguageServerId(message.language_server_id as usize),
3212 path: project_path,
3213 });
3214 }
3215 Ok(())
3216 })?
3217 }
3218
3219 async fn handle_start_language_server(
3220 this: Model<Self>,
3221 envelope: TypedEnvelope<proto::StartLanguageServer>,
3222 mut cx: AsyncAppContext,
3223 ) -> Result<()> {
3224 let server = envelope
3225 .payload
3226 .server
3227 .ok_or_else(|| anyhow!("invalid server"))?;
3228 this.update(&mut cx, |this, cx| {
3229 this.language_server_statuses.insert(
3230 LanguageServerId(server.id as usize),
3231 LanguageServerStatus {
3232 name: server.name,
3233 pending_work: Default::default(),
3234 has_pending_diagnostic_updates: false,
3235 progress_tokens: Default::default(),
3236 },
3237 );
3238 cx.notify();
3239 })?;
3240 Ok(())
3241 }
3242
3243 async fn handle_update_language_server(
3244 this: Model<Self>,
3245 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
3246 mut cx: AsyncAppContext,
3247 ) -> Result<()> {
3248 this.update(&mut cx, |this, cx| {
3249 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
3250
3251 match envelope
3252 .payload
3253 .variant
3254 .ok_or_else(|| anyhow!("invalid variant"))?
3255 {
3256 proto::update_language_server::Variant::WorkStart(payload) => {
3257 this.on_lsp_work_start(
3258 language_server_id,
3259 payload.token,
3260 LanguageServerProgress {
3261 title: payload.title,
3262 is_disk_based_diagnostics_progress: false,
3263 is_cancellable: false,
3264 message: payload.message,
3265 percentage: payload.percentage.map(|p| p as usize),
3266 last_update_at: cx.background_executor().now(),
3267 },
3268 cx,
3269 );
3270 }
3271
3272 proto::update_language_server::Variant::WorkProgress(payload) => {
3273 this.on_lsp_work_progress(
3274 language_server_id,
3275 payload.token,
3276 LanguageServerProgress {
3277 title: None,
3278 is_disk_based_diagnostics_progress: false,
3279 is_cancellable: false,
3280 message: payload.message,
3281 percentage: payload.percentage.map(|p| p as usize),
3282 last_update_at: cx.background_executor().now(),
3283 },
3284 cx,
3285 );
3286 }
3287
3288 proto::update_language_server::Variant::WorkEnd(payload) => {
3289 this.on_lsp_work_end(language_server_id, payload.token, cx);
3290 }
3291
3292 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
3293 this.disk_based_diagnostics_started(language_server_id, cx);
3294 }
3295
3296 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
3297 this.disk_based_diagnostics_finished(language_server_id, cx)
3298 }
3299 }
3300
3301 Ok(())
3302 })?
3303 }
3304
3305 pub fn disk_based_diagnostics_started(
3306 &mut self,
3307 language_server_id: LanguageServerId,
3308 cx: &mut ModelContext<Self>,
3309 ) {
3310 if let Some(language_server_status) =
3311 self.language_server_statuses.get_mut(&language_server_id)
3312 {
3313 language_server_status.has_pending_diagnostic_updates = true;
3314 }
3315
3316 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
3317 cx.emit(LspStoreEvent::LanguageServerUpdate {
3318 language_server_id,
3319 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
3320 Default::default(),
3321 ),
3322 })
3323 }
3324
3325 pub fn disk_based_diagnostics_finished(
3326 &mut self,
3327 language_server_id: LanguageServerId,
3328 cx: &mut ModelContext<Self>,
3329 ) {
3330 if let Some(language_server_status) =
3331 self.language_server_statuses.get_mut(&language_server_id)
3332 {
3333 language_server_status.has_pending_diagnostic_updates = false;
3334 }
3335
3336 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
3337 cx.emit(LspStoreEvent::LanguageServerUpdate {
3338 language_server_id,
3339 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
3340 Default::default(),
3341 ),
3342 })
3343 }
3344
3345 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
3346 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
3347 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
3348 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
3349 // the language server might take some time to publish diagnostics.
3350 fn simulate_disk_based_diagnostics_events_if_needed(
3351 &mut self,
3352 language_server_id: LanguageServerId,
3353 cx: &mut ModelContext<Self>,
3354 ) {
3355 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
3356
3357 let Some(LanguageServerState::Running {
3358 simulate_disk_based_diagnostics_completion,
3359 adapter,
3360 ..
3361 }) = self
3362 .as_local_mut()
3363 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
3364 else {
3365 return;
3366 };
3367
3368 if adapter.disk_based_diagnostics_progress_token.is_some() {
3369 return;
3370 }
3371
3372 let prev_task = simulate_disk_based_diagnostics_completion.replace(cx.spawn(
3373 move |this, mut cx| async move {
3374 cx.background_executor()
3375 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
3376 .await;
3377
3378 this.update(&mut cx, |this, cx| {
3379 this.disk_based_diagnostics_finished(language_server_id, cx);
3380
3381 if let Some(LanguageServerState::Running {
3382 simulate_disk_based_diagnostics_completion,
3383 ..
3384 }) = this.as_local_mut().and_then(|local_store| {
3385 local_store.language_servers.get_mut(&language_server_id)
3386 }) {
3387 *simulate_disk_based_diagnostics_completion = None;
3388 }
3389 })
3390 .ok();
3391 },
3392 ));
3393
3394 if prev_task.is_none() {
3395 self.disk_based_diagnostics_started(language_server_id, cx);
3396 }
3397 }
3398
3399 pub fn language_server_statuses(
3400 &self,
3401 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
3402 self.language_server_statuses
3403 .iter()
3404 .map(|(key, value)| (*key, value))
3405 }
3406
3407 fn lsp_notify_abs_paths_changed(
3408 &mut self,
3409 server_id: LanguageServerId,
3410 changes: Vec<PathEvent>,
3411 ) {
3412 maybe!({
3413 let server = self.language_server_for_id(server_id)?;
3414 let changes = changes
3415 .into_iter()
3416 .filter_map(|event| {
3417 let typ = match event.kind? {
3418 PathEventKind::Created => lsp::FileChangeType::CREATED,
3419 PathEventKind::Removed => lsp::FileChangeType::DELETED,
3420 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
3421 };
3422 Some(lsp::FileEvent {
3423 uri: lsp::Url::from_file_path(&event.path).ok()?,
3424 typ,
3425 })
3426 })
3427 .collect::<Vec<_>>();
3428 if !changes.is_empty() {
3429 server
3430 .notify::<lsp::notification::DidChangeWatchedFiles>(
3431 lsp::DidChangeWatchedFilesParams { changes },
3432 )
3433 .log_err();
3434 }
3435 Some(())
3436 });
3437 }
3438
3439 fn rebuild_watched_paths(
3440 &mut self,
3441 language_server_id: LanguageServerId,
3442 cx: &mut ModelContext<Self>,
3443 ) {
3444 let worktrees = self
3445 .worktree_store
3446 .read(cx)
3447 .worktrees()
3448 .filter_map(|worktree| {
3449 self.language_servers_for_worktree(worktree.read(cx).id())
3450 .find(|server| server.server_id() == language_server_id)
3451 .map(|_| worktree)
3452 })
3453 .collect::<Vec<_>>();
3454
3455 let local_lsp_store = self.as_local_mut().unwrap();
3456
3457 let Some(watchers) = local_lsp_store
3458 .language_server_watcher_registrations
3459 .get(&language_server_id)
3460 else {
3461 return;
3462 };
3463
3464 let mut worktree_globs = HashMap::default();
3465 let mut abs_globs = HashMap::default();
3466 log::trace!(
3467 "Processing new watcher paths for language server with id {}",
3468 language_server_id
3469 );
3470
3471 enum PathToWatch {
3472 Worktree {
3473 literal_prefix: Arc<Path>,
3474 pattern: String,
3475 },
3476 Absolute {
3477 path: Arc<Path>,
3478 pattern: String,
3479 },
3480 }
3481 for watcher in watchers.values().flatten() {
3482 let mut found_host = false;
3483 for worktree in &worktrees {
3484 let glob_is_inside_worktree = worktree.update(cx, |tree, _| {
3485 if let Some(worktree_root_path) = tree.abs_path().to_str() {
3486 let path_to_watch = match &watcher.glob_pattern {
3487 lsp::GlobPattern::String(s) => {
3488 match s.strip_prefix(worktree_root_path) {
3489 Some(relative) => {
3490 let pattern = relative
3491 .strip_prefix(std::path::MAIN_SEPARATOR)
3492 .unwrap_or(relative)
3493 .to_owned();
3494 let literal_prefix = glob_literal_prefix(&pattern);
3495
3496 let literal_prefix = Arc::from(PathBuf::from(
3497 literal_prefix
3498 .strip_prefix(std::path::MAIN_SEPARATOR)
3499 .unwrap_or(literal_prefix),
3500 ));
3501 PathToWatch::Worktree {
3502 literal_prefix,
3503 pattern,
3504 }
3505 }
3506 None => {
3507 let path = glob_literal_prefix(s);
3508 let glob = &s[path.len()..];
3509 let pattern = glob
3510 .strip_prefix(std::path::MAIN_SEPARATOR)
3511 .unwrap_or(glob)
3512 .to_owned();
3513 let path = if Path::new(path).components().next().is_none()
3514 {
3515 Arc::from(Path::new(worktree_root_path))
3516 } else {
3517 PathBuf::from(path).into()
3518 };
3519
3520 PathToWatch::Absolute { path, pattern }
3521 }
3522 }
3523 }
3524 lsp::GlobPattern::Relative(rp) => {
3525 let Ok(mut base_uri) = match &rp.base_uri {
3526 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3527 lsp::OneOf::Right(base_uri) => base_uri,
3528 }
3529 .to_file_path() else {
3530 return false;
3531 };
3532
3533 match base_uri.strip_prefix(worktree_root_path) {
3534 Ok(relative) => {
3535 let mut literal_prefix = relative.to_owned();
3536 literal_prefix.push(glob_literal_prefix(&rp.pattern));
3537
3538 PathToWatch::Worktree {
3539 literal_prefix: literal_prefix.into(),
3540 pattern: rp.pattern.clone(),
3541 }
3542 }
3543 Err(_) => {
3544 let path = glob_literal_prefix(&rp.pattern);
3545 let glob = &rp.pattern[path.len()..];
3546 let pattern = glob
3547 .strip_prefix(std::path::MAIN_SEPARATOR)
3548 .unwrap_or(glob)
3549 .to_owned();
3550 base_uri.push(path);
3551
3552 let path = if base_uri.components().next().is_none() {
3553 Arc::from(Path::new("/"))
3554 } else {
3555 base_uri.into()
3556 };
3557 PathToWatch::Absolute { path, pattern }
3558 }
3559 }
3560 }
3561 };
3562 match path_to_watch {
3563 PathToWatch::Worktree {
3564 literal_prefix,
3565 pattern,
3566 } => {
3567 if let Some((tree, glob)) =
3568 tree.as_local_mut().zip(Glob::new(&pattern).log_err())
3569 {
3570 tree.add_path_prefix_to_scan(literal_prefix);
3571 worktree_globs
3572 .entry(tree.id())
3573 .or_insert_with(GlobSetBuilder::new)
3574 .add(glob);
3575 } else {
3576 return false;
3577 }
3578 }
3579 PathToWatch::Absolute { path, pattern } => {
3580 if let Some(glob) = Glob::new(&pattern).log_err() {
3581 abs_globs
3582 .entry(path)
3583 .or_insert_with(GlobSetBuilder::new)
3584 .add(glob);
3585 }
3586 }
3587 }
3588 return true;
3589 }
3590 false
3591 });
3592 if glob_is_inside_worktree {
3593 log::trace!(
3594 "Watcher pattern `{}` has been attached to the worktree at `{}`",
3595 serde_json::to_string(&watcher.glob_pattern).unwrap(),
3596 worktree.read(cx).abs_path().display()
3597 );
3598 found_host = true;
3599 }
3600 }
3601 if !found_host {
3602 log::error!(
3603 "Watcher pattern `{}` has not been attached to any worktree or absolute path",
3604 serde_json::to_string(&watcher.glob_pattern).unwrap()
3605 )
3606 }
3607 }
3608
3609 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3610 for (worktree_id, builder) in worktree_globs {
3611 if let Ok(globset) = builder.build() {
3612 watch_builder.watch_worktree(worktree_id, globset);
3613 }
3614 }
3615 for (abs_path, builder) in abs_globs {
3616 if let Ok(globset) = builder.build() {
3617 watch_builder.watch_abs_path(abs_path, globset);
3618 }
3619 }
3620 let watcher = watch_builder.build(local_lsp_store.fs.clone(), language_server_id, cx);
3621 local_lsp_store
3622 .language_server_watched_paths
3623 .insert(language_server_id, watcher);
3624
3625 cx.notify();
3626 }
3627
3628 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3629 if let Some(local_lsp_store) = self.as_local() {
3630 if let Some(LanguageServerState::Running { server, .. }) =
3631 local_lsp_store.language_servers.get(&id)
3632 {
3633 Some(server.clone())
3634 } else if let Some((_, server)) =
3635 local_lsp_store.supplementary_language_servers.get(&id)
3636 {
3637 Some(Arc::clone(server))
3638 } else {
3639 None
3640 }
3641 } else {
3642 None
3643 }
3644 }
3645
3646 async fn on_lsp_workspace_edit(
3647 this: WeakModel<Self>,
3648 params: lsp::ApplyWorkspaceEditParams,
3649 server_id: LanguageServerId,
3650 adapter: Arc<CachedLspAdapter>,
3651 mut cx: AsyncAppContext,
3652 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3653 let this = this
3654 .upgrade()
3655 .ok_or_else(|| anyhow!("project project closed"))?;
3656 let language_server = this
3657 .update(&mut cx, |this, _| this.language_server_for_id(server_id))?
3658 .ok_or_else(|| anyhow!("language server not found"))?;
3659 let transaction = Self::deserialize_workspace_edit(
3660 this.clone(),
3661 params.edit,
3662 true,
3663 adapter.clone(),
3664 language_server.clone(),
3665 &mut cx,
3666 )
3667 .await
3668 .log_err();
3669 this.update(&mut cx, |this, _| {
3670 if let Some(transaction) = transaction {
3671 this.as_local_mut()
3672 .unwrap()
3673 .last_workspace_edits_by_language_server
3674 .insert(server_id, transaction);
3675 }
3676 })?;
3677 Ok(lsp::ApplyWorkspaceEditResponse {
3678 applied: true,
3679 failed_change: None,
3680 failure_reason: None,
3681 })
3682 }
3683
3684 fn on_lsp_progress(
3685 &mut self,
3686 progress: lsp::ProgressParams,
3687 language_server_id: LanguageServerId,
3688 disk_based_diagnostics_progress_token: Option<String>,
3689 cx: &mut ModelContext<Self>,
3690 ) {
3691 let token = match progress.token {
3692 lsp::NumberOrString::String(token) => token,
3693 lsp::NumberOrString::Number(token) => {
3694 log::info!("skipping numeric progress token {}", token);
3695 return;
3696 }
3697 };
3698
3699 let lsp::ProgressParamsValue::WorkDone(progress) = progress.value;
3700 let language_server_status =
3701 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3702 status
3703 } else {
3704 return;
3705 };
3706
3707 if !language_server_status.progress_tokens.contains(&token) {
3708 return;
3709 }
3710
3711 let is_disk_based_diagnostics_progress = disk_based_diagnostics_progress_token
3712 .as_ref()
3713 .map_or(false, |disk_based_token| {
3714 token.starts_with(disk_based_token)
3715 });
3716
3717 match progress {
3718 lsp::WorkDoneProgress::Begin(report) => {
3719 if is_disk_based_diagnostics_progress {
3720 self.disk_based_diagnostics_started(language_server_id, cx);
3721 }
3722 self.on_lsp_work_start(
3723 language_server_id,
3724 token.clone(),
3725 LanguageServerProgress {
3726 title: Some(report.title),
3727 is_disk_based_diagnostics_progress,
3728 is_cancellable: report.cancellable.unwrap_or(false),
3729 message: report.message.clone(),
3730 percentage: report.percentage.map(|p| p as usize),
3731 last_update_at: cx.background_executor().now(),
3732 },
3733 cx,
3734 );
3735 }
3736 lsp::WorkDoneProgress::Report(report) => {
3737 if self.on_lsp_work_progress(
3738 language_server_id,
3739 token.clone(),
3740 LanguageServerProgress {
3741 title: None,
3742 is_disk_based_diagnostics_progress,
3743 is_cancellable: report.cancellable.unwrap_or(false),
3744 message: report.message.clone(),
3745 percentage: report.percentage.map(|p| p as usize),
3746 last_update_at: cx.background_executor().now(),
3747 },
3748 cx,
3749 ) {
3750 cx.emit(LspStoreEvent::LanguageServerUpdate {
3751 language_server_id,
3752 message: proto::update_language_server::Variant::WorkProgress(
3753 proto::LspWorkProgress {
3754 token,
3755 message: report.message,
3756 percentage: report.percentage,
3757 },
3758 ),
3759 })
3760 }
3761 }
3762 lsp::WorkDoneProgress::End(_) => {
3763 language_server_status.progress_tokens.remove(&token);
3764 self.on_lsp_work_end(language_server_id, token.clone(), cx);
3765 if is_disk_based_diagnostics_progress {
3766 self.disk_based_diagnostics_finished(language_server_id, cx);
3767 }
3768 }
3769 }
3770 }
3771
3772 fn on_lsp_work_start(
3773 &mut self,
3774 language_server_id: LanguageServerId,
3775 token: String,
3776 progress: LanguageServerProgress,
3777 cx: &mut ModelContext<Self>,
3778 ) {
3779 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3780 status.pending_work.insert(token.clone(), progress.clone());
3781 cx.notify();
3782 }
3783 cx.emit(LspStoreEvent::LanguageServerUpdate {
3784 language_server_id,
3785 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
3786 token,
3787 title: progress.title,
3788 message: progress.message,
3789 percentage: progress.percentage.map(|p| p as u32),
3790 }),
3791 })
3792 }
3793
3794 fn on_lsp_work_progress(
3795 &mut self,
3796 language_server_id: LanguageServerId,
3797 token: String,
3798 progress: LanguageServerProgress,
3799 cx: &mut ModelContext<Self>,
3800 ) -> bool {
3801 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3802 match status.pending_work.entry(token) {
3803 btree_map::Entry::Vacant(entry) => {
3804 entry.insert(progress);
3805 cx.notify();
3806 return true;
3807 }
3808 btree_map::Entry::Occupied(mut entry) => {
3809 let entry = entry.get_mut();
3810 if (progress.last_update_at - entry.last_update_at)
3811 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
3812 {
3813 entry.last_update_at = progress.last_update_at;
3814 if progress.message.is_some() {
3815 entry.message = progress.message;
3816 }
3817 if progress.percentage.is_some() {
3818 entry.percentage = progress.percentage;
3819 }
3820 cx.notify();
3821 return true;
3822 }
3823 }
3824 }
3825 }
3826
3827 false
3828 }
3829
3830 fn on_lsp_work_end(
3831 &mut self,
3832 language_server_id: LanguageServerId,
3833 token: String,
3834 cx: &mut ModelContext<Self>,
3835 ) {
3836 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
3837 if let Some(work) = status.pending_work.remove(&token) {
3838 if !work.is_disk_based_diagnostics_progress {
3839 cx.emit(LspStoreEvent::RefreshInlayHints);
3840 }
3841 }
3842 cx.notify();
3843 }
3844
3845 cx.emit(LspStoreEvent::LanguageServerUpdate {
3846 language_server_id,
3847 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd { token }),
3848 })
3849 }
3850
3851 fn on_lsp_did_change_watched_files(
3852 &mut self,
3853 language_server_id: LanguageServerId,
3854 registration_id: &str,
3855 params: DidChangeWatchedFilesRegistrationOptions,
3856 cx: &mut ModelContext<Self>,
3857 ) {
3858 if let Some(local) = self.as_local_mut() {
3859 let registrations = local
3860 .language_server_watcher_registrations
3861 .entry(language_server_id)
3862 .or_default();
3863
3864 registrations.insert(registration_id.to_string(), params.watchers);
3865
3866 self.rebuild_watched_paths(language_server_id, cx);
3867 }
3868 }
3869
3870 fn on_lsp_unregister_did_change_watched_files(
3871 &mut self,
3872 language_server_id: LanguageServerId,
3873 registration_id: &str,
3874 cx: &mut ModelContext<Self>,
3875 ) {
3876 if let Some(local) = self.as_local_mut() {
3877 let registrations = local
3878 .language_server_watcher_registrations
3879 .entry(language_server_id)
3880 .or_default();
3881
3882 if registrations.remove(registration_id).is_some() {
3883 log::info!(
3884 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3885 language_server_id,
3886 registration_id
3887 );
3888 } else {
3889 log::warn!(
3890 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3891 language_server_id,
3892 registration_id
3893 );
3894 }
3895
3896 self.rebuild_watched_paths(language_server_id, cx);
3897 }
3898 }
3899
3900 #[allow(clippy::type_complexity)]
3901 pub(crate) fn edits_from_lsp(
3902 &mut self,
3903 buffer: &Model<Buffer>,
3904 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3905 server_id: LanguageServerId,
3906 version: Option<i32>,
3907 cx: &mut ModelContext<Self>,
3908 ) -> Task<Result<Vec<(Range<Anchor>, String)>>> {
3909 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3910 cx.background_executor().spawn(async move {
3911 let snapshot = snapshot?;
3912 let mut lsp_edits = lsp_edits
3913 .into_iter()
3914 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3915 .collect::<Vec<_>>();
3916 lsp_edits.sort_by_key(|(range, _)| range.start);
3917
3918 let mut lsp_edits = lsp_edits.into_iter().peekable();
3919 let mut edits = Vec::new();
3920 while let Some((range, mut new_text)) = lsp_edits.next() {
3921 // Clip invalid ranges provided by the language server.
3922 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3923 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3924
3925 // Combine any LSP edits that are adjacent.
3926 //
3927 // Also, combine LSP edits that are separated from each other by only
3928 // a newline. This is important because for some code actions,
3929 // Rust-analyzer rewrites the entire buffer via a series of edits that
3930 // are separated by unchanged newline characters.
3931 //
3932 // In order for the diffing logic below to work properly, any edits that
3933 // cancel each other out must be combined into one.
3934 while let Some((next_range, next_text)) = lsp_edits.peek() {
3935 if next_range.start.0 > range.end {
3936 if next_range.start.0.row > range.end.row + 1
3937 || next_range.start.0.column > 0
3938 || snapshot.clip_point_utf16(
3939 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3940 Bias::Left,
3941 ) > range.end
3942 {
3943 break;
3944 }
3945 new_text.push('\n');
3946 }
3947 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3948 new_text.push_str(next_text);
3949 lsp_edits.next();
3950 }
3951
3952 // For multiline edits, perform a diff of the old and new text so that
3953 // we can identify the changes more precisely, preserving the locations
3954 // of any anchors positioned in the unchanged regions.
3955 if range.end.row > range.start.row {
3956 let mut offset = range.start.to_offset(&snapshot);
3957 let old_text = snapshot.text_for_range(range).collect::<String>();
3958
3959 let diff = TextDiff::from_lines(old_text.as_str(), &new_text);
3960 let mut moved_since_edit = true;
3961 for change in diff.iter_all_changes() {
3962 let tag = change.tag();
3963 let value = change.value();
3964 match tag {
3965 ChangeTag::Equal => {
3966 offset += value.len();
3967 moved_since_edit = true;
3968 }
3969 ChangeTag::Delete => {
3970 let start = snapshot.anchor_after(offset);
3971 let end = snapshot.anchor_before(offset + value.len());
3972 if moved_since_edit {
3973 edits.push((start..end, String::new()));
3974 } else {
3975 edits.last_mut().unwrap().0.end = end;
3976 }
3977 offset += value.len();
3978 moved_since_edit = false;
3979 }
3980 ChangeTag::Insert => {
3981 if moved_since_edit {
3982 let anchor = snapshot.anchor_after(offset);
3983 edits.push((anchor..anchor, value.to_string()));
3984 } else {
3985 edits.last_mut().unwrap().1.push_str(value);
3986 }
3987 moved_since_edit = false;
3988 }
3989 }
3990 }
3991 } else if range.end == range.start {
3992 let anchor = snapshot.anchor_after(range.start);
3993 edits.push((anchor..anchor, new_text));
3994 } else {
3995 let edit_start = snapshot.anchor_after(range.start);
3996 let edit_end = snapshot.anchor_before(range.end);
3997 edits.push((edit_start..edit_end, new_text));
3998 }
3999 }
4000
4001 Ok(edits)
4002 })
4003 }
4004
4005 pub async fn handle_resolve_completion_documentation(
4006 this: Model<Self>,
4007 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
4008 mut cx: AsyncAppContext,
4009 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
4010 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
4011
4012 let completion = this
4013 .read_with(&cx, |this, _| {
4014 let id = LanguageServerId(envelope.payload.language_server_id as usize);
4015 let Some(server) = this.language_server_for_id(id) else {
4016 return Err(anyhow!("No language server {id}"));
4017 };
4018
4019 Ok(server.request::<lsp::request::ResolveCompletionItem>(lsp_completion))
4020 })??
4021 .await?;
4022
4023 let mut documentation_is_markdown = false;
4024 let documentation = match completion.documentation {
4025 Some(lsp::Documentation::String(text)) => text,
4026
4027 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
4028 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
4029 value
4030 }
4031
4032 _ => String::new(),
4033 };
4034
4035 // If we have a new buffer_id, that means we're talking to a new client
4036 // and want to check for new text_edits in the completion too.
4037 let mut old_start = None;
4038 let mut old_end = None;
4039 let mut new_text = String::default();
4040 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
4041 let buffer_snapshot = this.update(&mut cx, |this, cx| {
4042 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
4043 anyhow::Ok(buffer.read(cx).snapshot())
4044 })??;
4045
4046 if let Some(text_edit) = completion.text_edit.as_ref() {
4047 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
4048
4049 if let Some((old_range, mut text_edit_new_text)) = edit {
4050 LineEnding::normalize(&mut text_edit_new_text);
4051
4052 new_text = text_edit_new_text;
4053 old_start = Some(serialize_anchor(&old_range.start));
4054 old_end = Some(serialize_anchor(&old_range.end));
4055 }
4056 }
4057 }
4058
4059 Ok(proto::ResolveCompletionDocumentationResponse {
4060 documentation,
4061 documentation_is_markdown,
4062 old_start,
4063 old_end,
4064 new_text,
4065 })
4066 }
4067
4068 async fn handle_on_type_formatting(
4069 this: Model<Self>,
4070 envelope: TypedEnvelope<proto::OnTypeFormatting>,
4071 mut cx: AsyncAppContext,
4072 ) -> Result<proto::OnTypeFormattingResponse> {
4073 let on_type_formatting = this.update(&mut cx, |this, cx| {
4074 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
4075 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
4076 let position = envelope
4077 .payload
4078 .position
4079 .and_then(deserialize_anchor)
4080 .ok_or_else(|| anyhow!("invalid position"))?;
4081 Ok::<_, anyhow::Error>(this.apply_on_type_formatting(
4082 buffer,
4083 position,
4084 envelope.payload.trigger.clone(),
4085 cx,
4086 ))
4087 })??;
4088
4089 let transaction = on_type_formatting
4090 .await?
4091 .as_ref()
4092 .map(language::proto::serialize_transaction);
4093 Ok(proto::OnTypeFormattingResponse { transaction })
4094 }
4095
4096 async fn handle_refresh_inlay_hints(
4097 this: Model<Self>,
4098 _: TypedEnvelope<proto::RefreshInlayHints>,
4099 mut cx: AsyncAppContext,
4100 ) -> Result<proto::Ack> {
4101 this.update(&mut cx, |_, cx| {
4102 cx.emit(LspStoreEvent::RefreshInlayHints);
4103 })?;
4104 Ok(proto::Ack {})
4105 }
4106
4107 async fn handle_inlay_hints(
4108 this: Model<Self>,
4109 envelope: TypedEnvelope<proto::InlayHints>,
4110 mut cx: AsyncAppContext,
4111 ) -> Result<proto::InlayHintsResponse> {
4112 let sender_id = envelope.original_sender_id().unwrap_or_default();
4113 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
4114 let buffer = this.update(&mut cx, |this, cx| {
4115 this.buffer_store.read(cx).get_existing(buffer_id)
4116 })??;
4117 buffer
4118 .update(&mut cx, |buffer, _| {
4119 buffer.wait_for_version(deserialize_version(&envelope.payload.version))
4120 })?
4121 .await
4122 .with_context(|| format!("waiting for version for buffer {}", buffer.entity_id()))?;
4123
4124 let start = envelope
4125 .payload
4126 .start
4127 .and_then(deserialize_anchor)
4128 .context("missing range start")?;
4129 let end = envelope
4130 .payload
4131 .end
4132 .and_then(deserialize_anchor)
4133 .context("missing range end")?;
4134 let buffer_hints = this
4135 .update(&mut cx, |lsp_store, cx| {
4136 lsp_store.inlay_hints(buffer.clone(), start..end, cx)
4137 })?
4138 .await
4139 .context("inlay hints fetch")?;
4140
4141 this.update(&mut cx, |project, cx| {
4142 InlayHints::response_to_proto(
4143 buffer_hints,
4144 project,
4145 sender_id,
4146 &buffer.read(cx).version(),
4147 cx,
4148 )
4149 })
4150 }
4151
4152 async fn handle_resolve_inlay_hint(
4153 this: Model<Self>,
4154 envelope: TypedEnvelope<proto::ResolveInlayHint>,
4155 mut cx: AsyncAppContext,
4156 ) -> Result<proto::ResolveInlayHintResponse> {
4157 let proto_hint = envelope
4158 .payload
4159 .hint
4160 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
4161 let hint = InlayHints::proto_to_project_hint(proto_hint)
4162 .context("resolved proto inlay hint conversion")?;
4163 let buffer = this.update(&mut cx, |this, cx| {
4164 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
4165 this.buffer_store.read(cx).get_existing(buffer_id)
4166 })??;
4167 let response_hint = this
4168 .update(&mut cx, |this, cx| {
4169 this.resolve_inlay_hint(
4170 hint,
4171 buffer,
4172 LanguageServerId(envelope.payload.language_server_id as usize),
4173 cx,
4174 )
4175 })?
4176 .await
4177 .context("inlay hints fetch")?;
4178 Ok(proto::ResolveInlayHintResponse {
4179 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
4180 })
4181 }
4182
4183 async fn handle_open_buffer_for_symbol(
4184 this: Model<Self>,
4185 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
4186 mut cx: AsyncAppContext,
4187 ) -> Result<proto::OpenBufferForSymbolResponse> {
4188 let peer_id = envelope.original_sender_id().unwrap_or_default();
4189 let symbol = envelope
4190 .payload
4191 .symbol
4192 .ok_or_else(|| anyhow!("invalid symbol"))?;
4193 let symbol = Self::deserialize_symbol(symbol)?;
4194 let symbol = this.update(&mut cx, |this, _| {
4195 let signature = this.symbol_signature(&symbol.path);
4196 if signature == symbol.signature {
4197 Ok(symbol)
4198 } else {
4199 Err(anyhow!("invalid symbol signature"))
4200 }
4201 })??;
4202 let buffer = this
4203 .update(&mut cx, |this, cx| {
4204 this.open_buffer_for_symbol(
4205 &Symbol {
4206 language_server_name: symbol.language_server_name,
4207 source_worktree_id: symbol.source_worktree_id,
4208 path: symbol.path,
4209 name: symbol.name,
4210 kind: symbol.kind,
4211 range: symbol.range,
4212 signature: symbol.signature,
4213 label: CodeLabel {
4214 text: Default::default(),
4215 runs: Default::default(),
4216 filter_range: Default::default(),
4217 },
4218 },
4219 cx,
4220 )
4221 })?
4222 .await?;
4223
4224 this.update(&mut cx, |this, cx| {
4225 let is_private = buffer
4226 .read(cx)
4227 .file()
4228 .map(|f| f.is_private())
4229 .unwrap_or_default();
4230 if is_private {
4231 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
4232 } else {
4233 this.buffer_store
4234 .update(cx, |buffer_store, cx| {
4235 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
4236 })
4237 .detach_and_log_err(cx);
4238 let buffer_id = buffer.read(cx).remote_id().to_proto();
4239 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
4240 }
4241 })?
4242 }
4243
4244 fn symbol_signature(&self, project_path: &ProjectPath) -> [u8; 32] {
4245 let mut hasher = Sha256::new();
4246 hasher.update(project_path.worktree_id.to_proto().to_be_bytes());
4247 hasher.update(project_path.path.to_string_lossy().as_bytes());
4248 hasher.update(self.nonce.to_be_bytes());
4249 hasher.finalize().as_slice().try_into().unwrap()
4250 }
4251
4252 pub async fn handle_get_project_symbols(
4253 this: Model<Self>,
4254 envelope: TypedEnvelope<proto::GetProjectSymbols>,
4255 mut cx: AsyncAppContext,
4256 ) -> Result<proto::GetProjectSymbolsResponse> {
4257 let symbols = this
4258 .update(&mut cx, |this, cx| {
4259 this.symbols(&envelope.payload.query, cx)
4260 })?
4261 .await?;
4262
4263 Ok(proto::GetProjectSymbolsResponse {
4264 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
4265 })
4266 }
4267
4268 pub async fn handle_restart_language_servers(
4269 this: Model<Self>,
4270 envelope: TypedEnvelope<proto::RestartLanguageServers>,
4271 mut cx: AsyncAppContext,
4272 ) -> Result<proto::Ack> {
4273 this.update(&mut cx, |this, cx| {
4274 let buffers: Vec<_> = envelope
4275 .payload
4276 .buffer_ids
4277 .into_iter()
4278 .flat_map(|buffer_id| {
4279 this.buffer_store
4280 .read(cx)
4281 .get(BufferId::new(buffer_id).log_err()?)
4282 })
4283 .collect();
4284 this.restart_language_servers_for_buffers(buffers, cx)
4285 })?;
4286
4287 Ok(proto::Ack {})
4288 }
4289
4290 pub async fn handle_create_language_server(
4291 this: Model<Self>,
4292 envelope: TypedEnvelope<proto::CreateLanguageServer>,
4293 mut cx: AsyncAppContext,
4294 ) -> Result<proto::Ack> {
4295 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4296 let name = LanguageServerName::from_proto(envelope.payload.name);
4297
4298 let binary = envelope
4299 .payload
4300 .binary
4301 .ok_or_else(|| anyhow!("missing binary"))?;
4302 let binary = LanguageServerBinary {
4303 path: PathBuf::from(binary.path),
4304 env: None,
4305 arguments: binary.arguments.into_iter().map(Into::into).collect(),
4306 };
4307 let language = envelope
4308 .payload
4309 .language
4310 .ok_or_else(|| anyhow!("missing language"))?;
4311 let language_name = LanguageName::from_proto(language.name);
4312 let matcher: LanguageMatcher = serde_json::from_str(&language.matcher)?;
4313
4314 this.update(&mut cx, |this, cx| {
4315 this.languages
4316 .register_language(language_name.clone(), None, matcher.clone(), {
4317 let language_name = language_name.clone();
4318 move || {
4319 Ok((
4320 LanguageConfig {
4321 name: language_name.clone(),
4322 matcher: matcher.clone(),
4323 ..Default::default()
4324 },
4325 Default::default(),
4326 Default::default(),
4327 ))
4328 }
4329 });
4330 cx.background_executor()
4331 .spawn(this.languages.language_for_name(language_name.0.as_ref()))
4332 .detach();
4333
4334 let adapter = Arc::new(SshLspAdapter::new(
4335 name,
4336 binary,
4337 envelope.payload.initialization_options,
4338 envelope.payload.code_action_kinds,
4339 ));
4340
4341 this.languages
4342 .register_lsp_adapter(language_name.clone(), adapter.clone());
4343 let Some(worktree) = this
4344 .worktree_store
4345 .read(cx)
4346 .worktree_for_id(worktree_id, cx)
4347 else {
4348 return Err(anyhow!("worktree not found"));
4349 };
4350 this.start_language_server(
4351 &worktree,
4352 CachedLspAdapter::new(adapter),
4353 language_name,
4354 cx,
4355 );
4356 Ok(())
4357 })??;
4358 Ok(proto::Ack {})
4359 }
4360
4361 pub async fn handle_which_command(
4362 this: Model<Self>,
4363 envelope: TypedEnvelope<proto::WhichCommand>,
4364 mut cx: AsyncAppContext,
4365 ) -> Result<proto::WhichCommandResponse> {
4366 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4367 let command = PathBuf::from(envelope.payload.command);
4368 let response = this
4369 .update(&mut cx, |this, cx| {
4370 let worktree = this.worktree_for_id(worktree_id, cx)?;
4371 let delegate = ProjectLspAdapterDelegate::for_local(this, &worktree, cx);
4372 anyhow::Ok(
4373 cx.spawn(|_, _| async move { delegate.which(command.as_os_str()).await }),
4374 )
4375 })??
4376 .await;
4377
4378 Ok(proto::WhichCommandResponse {
4379 path: response.map(|path| path.to_string_lossy().to_string()),
4380 })
4381 }
4382
4383 pub async fn handle_shell_env(
4384 this: Model<Self>,
4385 envelope: TypedEnvelope<proto::ShellEnv>,
4386 mut cx: AsyncAppContext,
4387 ) -> Result<proto::ShellEnvResponse> {
4388 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4389 let response = this
4390 .update(&mut cx, |this, cx| {
4391 let worktree = this.worktree_for_id(worktree_id, cx)?;
4392 let delegate = ProjectLspAdapterDelegate::for_local(this, &worktree, cx);
4393 anyhow::Ok(cx.spawn(|_, _| async move { delegate.shell_env().await }))
4394 })??
4395 .await;
4396
4397 Ok(proto::ShellEnvResponse {
4398 env: response.into_iter().collect(),
4399 })
4400 }
4401
4402 async fn handle_apply_additional_edits_for_completion(
4403 this: Model<Self>,
4404 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
4405 mut cx: AsyncAppContext,
4406 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
4407 let (buffer, completion) = this.update(&mut cx, |this, cx| {
4408 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
4409 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
4410 let completion = Self::deserialize_completion(
4411 envelope
4412 .payload
4413 .completion
4414 .ok_or_else(|| anyhow!("invalid completion"))?,
4415 )?;
4416 anyhow::Ok((buffer, completion))
4417 })??;
4418
4419 let apply_additional_edits = this.update(&mut cx, |this, cx| {
4420 this.apply_additional_edits_for_completion(
4421 buffer,
4422 Completion {
4423 old_range: completion.old_range,
4424 new_text: completion.new_text,
4425 lsp_completion: completion.lsp_completion,
4426 server_id: completion.server_id,
4427 documentation: None,
4428 label: CodeLabel {
4429 text: Default::default(),
4430 runs: Default::default(),
4431 filter_range: Default::default(),
4432 },
4433 confirm: None,
4434 },
4435 false,
4436 cx,
4437 )
4438 })?;
4439
4440 Ok(proto::ApplyCompletionAdditionalEditsResponse {
4441 transaction: apply_additional_edits
4442 .await?
4443 .as_ref()
4444 .map(language::proto::serialize_transaction),
4445 })
4446 }
4447
4448 fn language_settings<'a>(
4449 &'a self,
4450 worktree: &'a Model<Worktree>,
4451 language: &LanguageName,
4452 cx: &'a mut ModelContext<Self>,
4453 ) -> &'a LanguageSettings {
4454 let root_file = worktree.update(cx, |tree, cx| tree.root_file(cx));
4455 all_language_settings(root_file.map(|f| f as _).as_ref(), cx).language(Some(language))
4456 }
4457
4458 pub fn start_language_servers(
4459 &mut self,
4460 worktree: &Model<Worktree>,
4461 language: LanguageName,
4462 cx: &mut ModelContext<Self>,
4463 ) {
4464 let settings = self.language_settings(worktree, &language, cx);
4465 if !settings.enable_language_server || self.mode.is_remote() {
4466 return;
4467 }
4468
4469 let available_lsp_adapters = self.languages.clone().lsp_adapters(&language);
4470 let available_language_servers = available_lsp_adapters
4471 .iter()
4472 .map(|lsp_adapter| lsp_adapter.name.clone())
4473 .collect::<Vec<_>>();
4474
4475 let desired_language_servers =
4476 settings.customized_language_servers(&available_language_servers);
4477
4478 let mut enabled_lsp_adapters: Vec<Arc<CachedLspAdapter>> = Vec::new();
4479 for desired_language_server in desired_language_servers {
4480 if let Some(adapter) = available_lsp_adapters
4481 .iter()
4482 .find(|adapter| adapter.name == desired_language_server)
4483 {
4484 enabled_lsp_adapters.push(adapter.clone());
4485 continue;
4486 }
4487
4488 if let Some(adapter) = self
4489 .languages
4490 .load_available_lsp_adapter(&desired_language_server)
4491 {
4492 self.languages
4493 .register_lsp_adapter(language.clone(), adapter.adapter.clone());
4494 enabled_lsp_adapters.push(adapter);
4495 continue;
4496 }
4497
4498 log::warn!(
4499 "no language server found matching '{}'",
4500 desired_language_server.0
4501 );
4502 }
4503
4504 for adapter in &enabled_lsp_adapters {
4505 self.start_language_server(worktree, adapter.clone(), language.clone(), cx);
4506 }
4507
4508 // After starting all the language servers, reorder them to reflect the desired order
4509 // based on the settings.
4510 //
4511 // This is done, in part, to ensure that language servers loaded at different points
4512 // (e.g., native vs extension) still end up in the right order at the end, rather than
4513 // it being based on which language server happened to be loaded in first.
4514 self.languages
4515 .reorder_language_servers(&language, enabled_lsp_adapters);
4516 }
4517
4518 /*
4519 ssh client owns the lifecycle of the language servers
4520 ssh host actually runs the binaries
4521
4522 in the future: ssh client will use the local extensions to get the downloads etc.
4523 and send them up over the ssh connection (but today) we'll just the static config
4524
4525 languages::() <-- registers lsp adapters
4526 on the ssh host we won't have adapters for the LSPs
4527 */
4528
4529 fn start_language_server_on_ssh_host(
4530 &mut self,
4531 worktree: &Model<Worktree>,
4532 adapter: Arc<CachedLspAdapter>,
4533 language: LanguageName,
4534 cx: &mut ModelContext<Self>,
4535 ) {
4536 let ssh = self.as_ssh().unwrap();
4537
4538 let delegate =
4539 ProjectLspAdapterDelegate::for_ssh(self, worktree, ssh.upstream_client.clone(), cx)
4540 as Arc<dyn LspAdapterDelegate>;
4541
4542 // TODO: We should use `adapter` here instead of reaching through the `CachedLspAdapter`.
4543 let lsp_adapter = adapter.adapter.clone();
4544
4545 let project_id = self.project_id;
4546 let worktree_id = worktree.read(cx).id().to_proto();
4547 let upstream_client = ssh.upstream_client.clone();
4548 let name = adapter.name().to_string();
4549
4550 let Some(available_language) = self.languages.available_language_for_name(&language) else {
4551 log::error!("failed to find available language {language}");
4552 return;
4553 };
4554
4555 let task = cx.spawn(|_, cx| async move {
4556 let user_binary_task = lsp_adapter.check_if_user_installed(delegate.as_ref(), &cx);
4557 let binary = match user_binary_task.await {
4558 Some(binary) => binary,
4559 None => {
4560 return Err(anyhow!(
4561 "Downloading language server for ssh host is not supported yet"
4562 ))
4563 }
4564 };
4565
4566 let name = adapter.name().to_string();
4567 let code_action_kinds = adapter
4568 .adapter
4569 .code_action_kinds()
4570 .map(|kinds| serde_json::to_string(&kinds))
4571 .transpose()?;
4572 let get_options = adapter.adapter.clone().initialization_options(&delegate);
4573 let initialization_options = get_options
4574 .await?
4575 .map(|options| serde_json::to_string(&options))
4576 .transpose()?;
4577
4578 let language_server_command = proto::LanguageServerCommand {
4579 path: binary.path.to_string_lossy().to_string(),
4580 arguments: binary
4581 .arguments
4582 .iter()
4583 .map(|args| args.to_string_lossy().to_string())
4584 .collect(),
4585 env: binary.env.unwrap_or_default().into_iter().collect(),
4586 };
4587
4588 upstream_client
4589 .request(proto::CreateLanguageServer {
4590 project_id,
4591 worktree_id,
4592 name,
4593 binary: Some(language_server_command),
4594 initialization_options,
4595 code_action_kinds,
4596 language: Some(proto::AvailableLanguage {
4597 name: language.to_proto(),
4598 matcher: serde_json::to_string(&available_language.matcher())?,
4599 }),
4600 })
4601 .await
4602 });
4603 cx.spawn(|this, mut cx| async move {
4604 if let Err(e) = task.await {
4605 this.update(&mut cx, |_this, cx| {
4606 cx.emit(LspStoreEvent::Notification(format!(
4607 "failed to start {}: {}",
4608 name, e
4609 )))
4610 })
4611 .ok();
4612 }
4613 })
4614 .detach();
4615 }
4616
4617 fn start_language_server(
4618 &mut self,
4619 worktree_handle: &Model<Worktree>,
4620 adapter: Arc<CachedLspAdapter>,
4621 language: LanguageName,
4622 cx: &mut ModelContext<Self>,
4623 ) {
4624 if self.mode.is_remote() {
4625 return;
4626 }
4627
4628 let worktree = worktree_handle.read(cx);
4629 let worktree_id = worktree.id();
4630 let worktree_path = worktree.abs_path();
4631 let key = (worktree_id, adapter.name.clone());
4632 if self.language_server_ids.contains_key(&key) {
4633 return;
4634 }
4635
4636 if self.mode.is_ssh() {
4637 self.start_language_server_on_ssh_host(worktree_handle, adapter, language, cx);
4638 return;
4639 }
4640
4641 if adapter.reinstall_attempt_count.load(SeqCst) > MAX_SERVER_REINSTALL_ATTEMPT_COUNT {
4642 return;
4643 }
4644
4645 let local = self.as_local().unwrap();
4646
4647 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
4648 let lsp_adapter_delegate = ProjectLspAdapterDelegate::for_local(self, worktree_handle, cx);
4649 let cli_environment = local.environment.update(cx, |environment, cx| {
4650 environment.get_environment(Some(worktree_id), Some(worktree_path.clone()), cx)
4651 });
4652
4653 let pending_server = match self.languages.create_pending_language_server(
4654 stderr_capture.clone(),
4655 language.clone(),
4656 adapter.clone(),
4657 Arc::clone(&worktree_path),
4658 lsp_adapter_delegate.clone(),
4659 cli_environment,
4660 cx,
4661 ) {
4662 Some(pending_server) => pending_server,
4663 None => return,
4664 };
4665
4666 let project_settings = ProjectSettings::get(
4667 Some(SettingsLocation {
4668 worktree_id,
4669 path: Path::new(""),
4670 }),
4671 cx,
4672 );
4673
4674 // We need some on the SSH client, and some on SSH host
4675 let lsp = project_settings.lsp.get(&adapter.name.0);
4676 let override_options = lsp.and_then(|s| s.initialization_options.clone());
4677
4678 let server_id = pending_server.server_id;
4679 let container_dir = pending_server.container_dir.clone();
4680 let state = LanguageServerState::Starting({
4681 let adapter = adapter.clone();
4682 let server_name = adapter.name.0.clone();
4683 let language = language.clone();
4684 let key = key.clone();
4685
4686 cx.spawn(move |this, mut cx| async move {
4687 let result = Self::setup_and_insert_language_server(
4688 this.clone(),
4689 lsp_adapter_delegate,
4690 override_options,
4691 pending_server,
4692 adapter.clone(),
4693 language.clone(),
4694 server_id,
4695 key,
4696 &mut cx,
4697 )
4698 .await;
4699
4700 match result {
4701 Ok(server) => {
4702 stderr_capture.lock().take();
4703 server
4704 }
4705
4706 Err(err) => {
4707 log::error!("failed to start language server {server_name:?}: {err}");
4708 log::error!("server stderr: {:?}", stderr_capture.lock().take());
4709
4710 let this = this.upgrade()?;
4711 let container_dir = container_dir?;
4712
4713 let attempt_count = adapter.reinstall_attempt_count.fetch_add(1, SeqCst);
4714 if attempt_count >= MAX_SERVER_REINSTALL_ATTEMPT_COUNT {
4715 let max = MAX_SERVER_REINSTALL_ATTEMPT_COUNT;
4716 log::error!("Hit {max} reinstallation attempts for {server_name:?}");
4717 return None;
4718 }
4719
4720 log::info!(
4721 "retrying installation of language server {server_name:?} in {}s",
4722 SERVER_REINSTALL_DEBOUNCE_TIMEOUT.as_secs()
4723 );
4724 cx.background_executor()
4725 .timer(SERVER_REINSTALL_DEBOUNCE_TIMEOUT)
4726 .await;
4727
4728 let installation_test_binary = adapter
4729 .installation_test_binary(container_dir.to_path_buf())
4730 .await;
4731
4732 this.update(&mut cx, |_, cx| {
4733 Self::check_errored_server(
4734 language,
4735 adapter,
4736 server_id,
4737 installation_test_binary,
4738 cx,
4739 )
4740 })
4741 .ok();
4742
4743 None
4744 }
4745 }
4746 })
4747 });
4748
4749 self.as_local_mut()
4750 .unwrap()
4751 .language_servers
4752 .insert(server_id, state);
4753 self.language_server_ids.insert(key, server_id);
4754 }
4755
4756 #[allow(clippy::too_many_arguments)]
4757 async fn setup_and_insert_language_server(
4758 this: WeakModel<Self>,
4759 delegate: Arc<dyn LspAdapterDelegate>,
4760 override_initialization_options: Option<serde_json::Value>,
4761 pending_server: PendingLanguageServer,
4762 adapter: Arc<CachedLspAdapter>,
4763 language: LanguageName,
4764 server_id: LanguageServerId,
4765 key: (WorktreeId, LanguageServerName),
4766 cx: &mut AsyncAppContext,
4767 ) -> Result<Option<Arc<LanguageServer>>> {
4768 let language_server = Self::setup_pending_language_server(
4769 this.clone(),
4770 override_initialization_options,
4771 pending_server,
4772 delegate,
4773 adapter.clone(),
4774 server_id,
4775 cx,
4776 )
4777 .await?;
4778
4779 let this = match this.upgrade() {
4780 Some(this) => this,
4781 None => return Err(anyhow!("failed to upgrade project handle")),
4782 };
4783
4784 this.update(cx, |this, cx| {
4785 this.insert_newly_running_language_server(
4786 language,
4787 adapter,
4788 language_server.clone(),
4789 server_id,
4790 key,
4791 cx,
4792 )
4793 })??;
4794
4795 Ok(Some(language_server))
4796 }
4797
4798 fn reinstall_language_server(
4799 &mut self,
4800 language: LanguageName,
4801 adapter: Arc<CachedLspAdapter>,
4802 server_id: LanguageServerId,
4803 cx: &mut ModelContext<Self>,
4804 ) -> Option<Task<()>> {
4805 log::info!("beginning to reinstall server");
4806
4807 if let Some(local) = self.as_local_mut() {
4808 let existing_server = match local.language_servers.remove(&server_id) {
4809 Some(LanguageServerState::Running { server, .. }) => Some(server),
4810 _ => None,
4811 };
4812
4813 self.worktree_store.update(cx, |store, cx| {
4814 for worktree in store.worktrees() {
4815 let key = (worktree.read(cx).id(), adapter.name.clone());
4816 self.language_server_ids.remove(&key);
4817 }
4818 });
4819
4820 Some(cx.spawn(move |this, mut cx| async move {
4821 if let Some(task) = existing_server.and_then(|server| server.shutdown()) {
4822 log::info!("shutting down existing server");
4823 task.await;
4824 }
4825
4826 // TODO: This is race-safe with regards to preventing new instances from
4827 // starting while deleting, but existing instances in other projects are going
4828 // to be very confused and messed up
4829 let Some(task) = this
4830 .update(&mut cx, |this, cx| {
4831 this.languages.delete_server_container(adapter.clone(), cx)
4832 })
4833 .log_err()
4834 else {
4835 return;
4836 };
4837 task.await;
4838
4839 this.update(&mut cx, |this, cx| {
4840 for worktree in this.worktree_store.read(cx).worktrees().collect::<Vec<_>>() {
4841 this.start_language_server(
4842 &worktree,
4843 adapter.clone(),
4844 language.clone(),
4845 cx,
4846 );
4847 }
4848 })
4849 .ok();
4850 }))
4851 } else if let Some(_ssh_store) = self.as_ssh() {
4852 // TODO
4853 None
4854 } else {
4855 None
4856 }
4857 }
4858
4859 async fn shutdown_language_server(
4860 server_state: Option<LanguageServerState>,
4861 name: Arc<str>,
4862 cx: AsyncAppContext,
4863 ) {
4864 let server = match server_state {
4865 Some(LanguageServerState::Starting(task)) => {
4866 let mut timer = cx
4867 .background_executor()
4868 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
4869 .fuse();
4870
4871 select! {
4872 server = task.fuse() => server,
4873 _ = timer => {
4874 log::info!(
4875 "timeout waiting for language server {} to finish launching before stopping",
4876 name
4877 );
4878 None
4879 },
4880 }
4881 }
4882
4883 Some(LanguageServerState::Running { server, .. }) => Some(server),
4884
4885 None => None,
4886 };
4887
4888 if let Some(server) = server {
4889 if let Some(shutdown) = server.shutdown() {
4890 shutdown.await;
4891 }
4892 }
4893 }
4894
4895 // Returns a list of all of the worktrees which no longer have a language server and the root path
4896 // for the stopped server
4897 pub fn stop_language_server(
4898 &mut self,
4899 worktree_id: WorktreeId,
4900 adapter_name: LanguageServerName,
4901 cx: &mut ModelContext<Self>,
4902 ) -> Task<Vec<WorktreeId>> {
4903 let key = (worktree_id, adapter_name);
4904 if self.mode.is_local() {
4905 if let Some(server_id) = self.language_server_ids.remove(&key) {
4906 let name = key.1 .0;
4907 log::info!("stopping language server {name}");
4908
4909 // Remove other entries for this language server as well
4910 let mut orphaned_worktrees = vec![worktree_id];
4911 let other_keys = self.language_server_ids.keys().cloned().collect::<Vec<_>>();
4912 for other_key in other_keys {
4913 if self.language_server_ids.get(&other_key) == Some(&server_id) {
4914 self.language_server_ids.remove(&other_key);
4915 orphaned_worktrees.push(other_key.0);
4916 }
4917 }
4918
4919 self.buffer_store.update(cx, |buffer_store, cx| {
4920 for buffer in buffer_store.buffers() {
4921 buffer.update(cx, |buffer, cx| {
4922 buffer.update_diagnostics(server_id, Default::default(), cx);
4923 });
4924 }
4925 });
4926
4927 let project_id = self.project_id;
4928 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
4929 summaries.retain(|path, summaries_by_server_id| {
4930 if summaries_by_server_id.remove(&server_id).is_some() {
4931 if let Some(downstream_client) = self.downstream_client.clone() {
4932 downstream_client
4933 .send(proto::UpdateDiagnosticSummary {
4934 project_id,
4935 worktree_id: worktree_id.to_proto(),
4936 summary: Some(proto::DiagnosticSummary {
4937 path: path.to_string_lossy().to_string(),
4938 language_server_id: server_id.0 as u64,
4939 error_count: 0,
4940 warning_count: 0,
4941 }),
4942 })
4943 .log_err();
4944 }
4945 !summaries_by_server_id.is_empty()
4946 } else {
4947 true
4948 }
4949 });
4950 }
4951
4952 for diagnostics in self.diagnostics.values_mut() {
4953 diagnostics.retain(|_, diagnostics_by_server_id| {
4954 if let Ok(ix) =
4955 diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0)
4956 {
4957 diagnostics_by_server_id.remove(ix);
4958 !diagnostics_by_server_id.is_empty()
4959 } else {
4960 true
4961 }
4962 });
4963 }
4964
4965 self.as_local_mut()
4966 .unwrap()
4967 .language_server_watched_paths
4968 .remove(&server_id);
4969 self.language_server_statuses.remove(&server_id);
4970 cx.notify();
4971
4972 let server_state = self
4973 .as_local_mut()
4974 .unwrap()
4975 .language_servers
4976 .remove(&server_id);
4977 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
4978 cx.spawn(move |_, cx| async move {
4979 Self::shutdown_language_server(server_state, name, cx).await;
4980 orphaned_worktrees
4981 })
4982 } else {
4983 Task::ready(Vec::new())
4984 }
4985 } else if self.mode.is_ssh() {
4986 // TODO ssh
4987 Task::ready(Vec::new())
4988 } else {
4989 Task::ready(Vec::new())
4990 }
4991 }
4992
4993 pub fn restart_language_servers_for_buffers(
4994 &mut self,
4995 buffers: impl IntoIterator<Item = Model<Buffer>>,
4996 cx: &mut ModelContext<Self>,
4997 ) {
4998 if let Some(client) = self.upstream_client() {
4999 let request = client.request(proto::RestartLanguageServers {
5000 project_id: self.project_id,
5001 buffer_ids: buffers
5002 .into_iter()
5003 .map(|b| b.read(cx).remote_id().to_proto())
5004 .collect(),
5005 });
5006 cx.background_executor()
5007 .spawn(request)
5008 .detach_and_log_err(cx);
5009 } else {
5010 #[allow(clippy::mutable_key_type)]
5011 let language_server_lookup_info: HashSet<(Model<Worktree>, LanguageName)> = buffers
5012 .into_iter()
5013 .filter_map(|buffer| {
5014 let buffer = buffer.read(cx);
5015 let file = buffer.file()?;
5016 let worktree = File::from_dyn(Some(file))?.worktree.clone();
5017 let language =
5018 self.languages
5019 .language_for_file(file, Some(buffer.as_rope()), cx)?;
5020
5021 Some((worktree, language.name()))
5022 })
5023 .collect();
5024
5025 for (worktree, language) in language_server_lookup_info {
5026 self.restart_language_servers(worktree, language, cx);
5027 }
5028 }
5029 }
5030
5031 pub fn restart_language_servers(
5032 &mut self,
5033 worktree: Model<Worktree>,
5034 language: LanguageName,
5035 cx: &mut ModelContext<Self>,
5036 ) {
5037 let worktree_id = worktree.read(cx).id();
5038
5039 let stop_tasks = self
5040 .languages
5041 .clone()
5042 .lsp_adapters(&language)
5043 .iter()
5044 .map(|adapter| {
5045 let stop_task = self.stop_language_server(worktree_id, adapter.name.clone(), cx);
5046 (stop_task, adapter.name.clone())
5047 })
5048 .collect::<Vec<_>>();
5049 if stop_tasks.is_empty() {
5050 return;
5051 }
5052
5053 cx.spawn(move |this, mut cx| async move {
5054 // For each stopped language server, record all of the worktrees with which
5055 // it was associated.
5056 let mut affected_worktrees = Vec::new();
5057 for (stop_task, language_server_name) in stop_tasks {
5058 for affected_worktree_id in stop_task.await {
5059 affected_worktrees.push((affected_worktree_id, language_server_name.clone()));
5060 }
5061 }
5062
5063 this.update(&mut cx, |this, cx| {
5064 // Restart the language server for the given worktree.
5065 this.start_language_servers(&worktree, language.clone(), cx);
5066
5067 // Lookup new server ids and set them for each of the orphaned worktrees
5068 for (affected_worktree_id, language_server_name) in affected_worktrees {
5069 if let Some(new_server_id) = this
5070 .language_server_ids
5071 .get(&(worktree_id, language_server_name.clone()))
5072 .cloned()
5073 {
5074 this.language_server_ids
5075 .insert((affected_worktree_id, language_server_name), new_server_id);
5076 }
5077 }
5078 })
5079 .ok();
5080 })
5081 .detach();
5082 }
5083
5084 fn check_errored_server(
5085 language: LanguageName,
5086 adapter: Arc<CachedLspAdapter>,
5087 server_id: LanguageServerId,
5088 installation_test_binary: Option<LanguageServerBinary>,
5089 cx: &mut ModelContext<Self>,
5090 ) {
5091 if !adapter.can_be_reinstalled() {
5092 log::info!(
5093 "Validation check requested for {:?} but it cannot be reinstalled",
5094 adapter.name.0
5095 );
5096 return;
5097 }
5098
5099 cx.spawn(move |this, mut cx| async move {
5100 log::info!("About to spawn test binary");
5101
5102 // A lack of test binary counts as a failure
5103 let process = installation_test_binary.and_then(|binary| {
5104 smol::process::Command::new(&binary.path)
5105 .current_dir(&binary.path)
5106 .args(binary.arguments)
5107 .stdin(Stdio::piped())
5108 .stdout(Stdio::piped())
5109 .stderr(Stdio::inherit())
5110 .kill_on_drop(true)
5111 .spawn()
5112 .ok()
5113 });
5114
5115 const PROCESS_TIMEOUT: Duration = Duration::from_secs(5);
5116 let mut timeout = cx.background_executor().timer(PROCESS_TIMEOUT).fuse();
5117
5118 let mut errored = false;
5119 if let Some(mut process) = process {
5120 futures::select! {
5121 status = process.status().fuse() => match status {
5122 Ok(status) => errored = !status.success(),
5123 Err(_) => errored = true,
5124 },
5125
5126 _ = timeout => {
5127 log::info!("test binary time-ed out, this counts as a success");
5128 _ = process.kill();
5129 }
5130 }
5131 } else {
5132 log::warn!("test binary failed to launch");
5133 errored = true;
5134 }
5135
5136 if errored {
5137 log::warn!("test binary check failed");
5138 let task = this
5139 .update(&mut cx, move |this, cx| {
5140 this.reinstall_language_server(language, adapter, server_id, cx)
5141 })
5142 .ok()
5143 .flatten();
5144
5145 if let Some(task) = task {
5146 task.await;
5147 }
5148 }
5149 })
5150 .detach();
5151 }
5152
5153 async fn setup_pending_language_server(
5154 this: WeakModel<Self>,
5155 override_options: Option<serde_json::Value>,
5156 pending_server: PendingLanguageServer,
5157 delegate: Arc<dyn LspAdapterDelegate>,
5158 adapter: Arc<CachedLspAdapter>,
5159 server_id: LanguageServerId,
5160 cx: &mut AsyncAppContext,
5161 ) -> Result<Arc<LanguageServer>> {
5162 let workspace_config = adapter
5163 .adapter
5164 .clone()
5165 .workspace_configuration(&delegate, cx)
5166 .await?;
5167 // This has to come from the server
5168 let (language_server, mut initialization_options) = pending_server.task.await?;
5169
5170 let name = language_server.name();
5171 language_server
5172 .on_notification::<lsp::notification::PublishDiagnostics, _>({
5173 let adapter = adapter.clone();
5174 let this = this.clone();
5175 move |mut params, mut cx| {
5176 let adapter = adapter.clone();
5177 if let Some(this) = this.upgrade() {
5178 adapter.process_diagnostics(&mut params);
5179 // Everything else has to be on the server, Can we make it on the client?
5180 this.update(&mut cx, |this, cx| {
5181 this.update_diagnostics(
5182 server_id,
5183 params,
5184 &adapter.disk_based_diagnostic_sources,
5185 cx,
5186 )
5187 .log_err();
5188 })
5189 .ok();
5190 }
5191 }
5192 })
5193 .detach();
5194
5195 language_server
5196 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
5197 let adapter = adapter.adapter.clone();
5198 let delegate = delegate.clone();
5199 move |params, mut cx| {
5200 let adapter = adapter.clone();
5201 let delegate = delegate.clone();
5202 async move {
5203 let workspace_config =
5204 adapter.workspace_configuration(&delegate, &mut cx).await?;
5205 Ok(params
5206 .items
5207 .into_iter()
5208 .map(|item| {
5209 if let Some(section) = &item.section {
5210 workspace_config
5211 .get(section)
5212 .cloned()
5213 .unwrap_or(serde_json::Value::Null)
5214 } else {
5215 workspace_config.clone()
5216 }
5217 })
5218 .collect())
5219 }
5220 }
5221 })
5222 .detach();
5223
5224 let id = language_server.server_id();
5225 language_server
5226 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
5227 let this = this.clone();
5228 move |_, mut cx| {
5229 let this = this.clone();
5230 async move {
5231 let Some(server) =
5232 this.update(&mut cx, |this, _| this.language_server_for_id(id))?
5233 else {
5234 return Ok(None);
5235 };
5236 let root = server.root_path();
5237 let Ok(uri) = Url::from_file_path(&root) else {
5238 return Ok(None);
5239 };
5240 Ok(Some(vec![WorkspaceFolder {
5241 uri,
5242 name: Default::default(),
5243 }]))
5244 }
5245 }
5246 })
5247 .detach();
5248 // Even though we don't have handling for these requests, respond to them to
5249 // avoid stalling any language server like `gopls` which waits for a response
5250 // to these requests when initializing.
5251 language_server
5252 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
5253 let this = this.clone();
5254 move |params, mut cx| {
5255 let this = this.clone();
5256 async move {
5257 this.update(&mut cx, |this, _| {
5258 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
5259 {
5260 if let lsp::NumberOrString::String(token) = params.token {
5261 status.progress_tokens.insert(token);
5262 }
5263 }
5264 })?;
5265
5266 Ok(())
5267 }
5268 }
5269 })
5270 .detach();
5271
5272 language_server
5273 .on_request::<lsp::request::RegisterCapability, _, _>({
5274 let this = this.clone();
5275 move |params, mut cx| {
5276 let this = this.clone();
5277 async move {
5278 for reg in params.registrations {
5279 match reg.method.as_str() {
5280 "workspace/didChangeWatchedFiles" => {
5281 if let Some(options) = reg.register_options {
5282 let options = serde_json::from_value(options)?;
5283 this.update(&mut cx, |this, cx| {
5284 this.on_lsp_did_change_watched_files(
5285 server_id, ®.id, options, cx,
5286 );
5287 })?;
5288 }
5289 }
5290 "textDocument/rangeFormatting" => {
5291 this.update(&mut cx, |this, _| {
5292 if let Some(server) = this.language_server_for_id(server_id)
5293 {
5294 let options = reg
5295 .register_options
5296 .map(|options| {
5297 serde_json::from_value::<
5298 lsp::DocumentRangeFormattingOptions,
5299 >(
5300 options
5301 )
5302 })
5303 .transpose()?;
5304 let provider = match options {
5305 None => OneOf::Left(true),
5306 Some(options) => OneOf::Right(options),
5307 };
5308 server.update_capabilities(|capabilities| {
5309 capabilities.document_range_formatting_provider =
5310 Some(provider);
5311 })
5312 }
5313 anyhow::Ok(())
5314 })??;
5315 }
5316 "textDocument/onTypeFormatting" => {
5317 this.update(&mut cx, |this, _| {
5318 if let Some(server) = this.language_server_for_id(server_id)
5319 {
5320 let options = reg
5321 .register_options
5322 .map(|options| {
5323 serde_json::from_value::<
5324 lsp::DocumentOnTypeFormattingOptions,
5325 >(
5326 options
5327 )
5328 })
5329 .transpose()?;
5330 if let Some(options) = options {
5331 server.update_capabilities(|capabilities| {
5332 capabilities
5333 .document_on_type_formatting_provider =
5334 Some(options);
5335 })
5336 }
5337 }
5338 anyhow::Ok(())
5339 })??;
5340 }
5341 "textDocument/formatting" => {
5342 this.update(&mut cx, |this, _| {
5343 if let Some(server) = this.language_server_for_id(server_id)
5344 {
5345 let options = reg
5346 .register_options
5347 .map(|options| {
5348 serde_json::from_value::<
5349 lsp::DocumentFormattingOptions,
5350 >(
5351 options
5352 )
5353 })
5354 .transpose()?;
5355 let provider = match options {
5356 None => OneOf::Left(true),
5357 Some(options) => OneOf::Right(options),
5358 };
5359 server.update_capabilities(|capabilities| {
5360 capabilities.document_formatting_provider =
5361 Some(provider);
5362 })
5363 }
5364 anyhow::Ok(())
5365 })??;
5366 }
5367 _ => log::warn!("unhandled capability registration: {reg:?}"),
5368 }
5369 }
5370 Ok(())
5371 }
5372 }
5373 })
5374 .detach();
5375
5376 language_server
5377 .on_request::<lsp::request::UnregisterCapability, _, _>({
5378 let this = this.clone();
5379 move |params, mut cx| {
5380 let this = this.clone();
5381 async move {
5382 for unreg in params.unregisterations.iter() {
5383 match unreg.method.as_str() {
5384 "workspace/didChangeWatchedFiles" => {
5385 this.update(&mut cx, |this, cx| {
5386 this.on_lsp_unregister_did_change_watched_files(
5387 server_id, &unreg.id, cx,
5388 );
5389 })?;
5390 }
5391 "textDocument/rangeFormatting" => {
5392 this.update(&mut cx, |this, _| {
5393 if let Some(server) = this.language_server_for_id(server_id)
5394 {
5395 server.update_capabilities(|capabilities| {
5396 capabilities.document_range_formatting_provider =
5397 None
5398 })
5399 }
5400 })?;
5401 }
5402 "textDocument/onTypeFormatting" => {
5403 this.update(&mut cx, |this, _| {
5404 if let Some(server) = this.language_server_for_id(server_id)
5405 {
5406 server.update_capabilities(|capabilities| {
5407 capabilities.document_on_type_formatting_provider =
5408 None;
5409 })
5410 }
5411 })?;
5412 }
5413 "textDocument/formatting" => {
5414 this.update(&mut cx, |this, _| {
5415 if let Some(server) = this.language_server_for_id(server_id)
5416 {
5417 server.update_capabilities(|capabilities| {
5418 capabilities.document_formatting_provider = None;
5419 })
5420 }
5421 })?;
5422 }
5423 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
5424 }
5425 }
5426 Ok(())
5427 }
5428 }
5429 })
5430 .detach();
5431
5432 language_server
5433 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
5434 let adapter = adapter.clone();
5435 let this = this.clone();
5436 move |params, cx| {
5437 Self::on_lsp_workspace_edit(
5438 this.clone(),
5439 params,
5440 server_id,
5441 adapter.clone(),
5442 cx,
5443 )
5444 }
5445 })
5446 .detach();
5447
5448 language_server
5449 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
5450 let this = this.clone();
5451 move |(), mut cx| {
5452 let this = this.clone();
5453 async move {
5454 this.update(&mut cx, |this, cx| {
5455 cx.emit(LspStoreEvent::RefreshInlayHints);
5456 this.downstream_client.as_ref().map(|client| {
5457 client.send(proto::RefreshInlayHints {
5458 project_id: this.project_id,
5459 })
5460 })
5461 })?
5462 .transpose()?;
5463 Ok(())
5464 }
5465 }
5466 })
5467 .detach();
5468
5469 language_server
5470 .on_request::<lsp::request::ShowMessageRequest, _, _>({
5471 let this = this.clone();
5472 let name = name.to_string();
5473 move |params, mut cx| {
5474 let this = this.clone();
5475 let name = name.to_string();
5476 async move {
5477 let actions = params.actions.unwrap_or_default();
5478 let (tx, mut rx) = smol::channel::bounded(1);
5479 let request = LanguageServerPromptRequest {
5480 level: match params.typ {
5481 lsp::MessageType::ERROR => PromptLevel::Critical,
5482 lsp::MessageType::WARNING => PromptLevel::Warning,
5483 _ => PromptLevel::Info,
5484 },
5485 message: params.message,
5486 actions,
5487 response_channel: tx,
5488 lsp_name: name.clone(),
5489 };
5490
5491 let did_update = this
5492 .update(&mut cx, |_, cx| {
5493 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
5494 })
5495 .is_ok();
5496 if did_update {
5497 let response = rx.next().await;
5498
5499 Ok(response)
5500 } else {
5501 Ok(None)
5502 }
5503 }
5504 }
5505 })
5506 .detach();
5507
5508 let disk_based_diagnostics_progress_token =
5509 adapter.disk_based_diagnostics_progress_token.clone();
5510
5511 language_server
5512 .on_notification::<ServerStatus, _>({
5513 let this = this.clone();
5514 let name = name.to_string();
5515 move |params, mut cx| {
5516 let this = this.clone();
5517 let name = name.to_string();
5518 if let Some(ref message) = params.message {
5519 let message = message.trim();
5520 if !message.is_empty() {
5521 let formatted_message = format!(
5522 "Language server {name} (id {server_id}) status update: {message}"
5523 );
5524 match params.health {
5525 ServerHealthStatus::Ok => log::info!("{}", formatted_message),
5526 ServerHealthStatus::Warning => log::warn!("{}", formatted_message),
5527 ServerHealthStatus::Error => {
5528 log::error!("{}", formatted_message);
5529 let (tx, _rx) = smol::channel::bounded(1);
5530 let request = LanguageServerPromptRequest {
5531 level: PromptLevel::Critical,
5532 message: params.message.unwrap_or_default(),
5533 actions: Vec::new(),
5534 response_channel: tx,
5535 lsp_name: name.clone(),
5536 };
5537 let _ = this
5538 .update(&mut cx, |_, cx| {
5539 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
5540 })
5541 .ok();
5542 }
5543 ServerHealthStatus::Other(status) => {
5544 log::info!(
5545 "Unknown server health: {status}\n{formatted_message}"
5546 )
5547 }
5548 }
5549 }
5550 }
5551 }
5552 })
5553 .detach();
5554 language_server
5555 .on_notification::<lsp::notification::ShowMessage, _>({
5556 let this = this.clone();
5557 let name = name.to_string();
5558 move |params, mut cx| {
5559 let this = this.clone();
5560 let name = name.to_string();
5561
5562 let (tx, _) = smol::channel::bounded(1);
5563 let request = LanguageServerPromptRequest {
5564 level: match params.typ {
5565 lsp::MessageType::ERROR => PromptLevel::Critical,
5566 lsp::MessageType::WARNING => PromptLevel::Warning,
5567 _ => PromptLevel::Info,
5568 },
5569 message: params.message,
5570 actions: vec![],
5571 response_channel: tx,
5572 lsp_name: name.clone(),
5573 };
5574
5575 let _ = this.update(&mut cx, |_, cx| {
5576 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
5577 });
5578 }
5579 })
5580 .detach();
5581 language_server
5582 .on_notification::<lsp::notification::Progress, _>({
5583 let this = this.clone();
5584 move |params, mut cx| {
5585 if let Some(this) = this.upgrade() {
5586 this.update(&mut cx, |this, cx| {
5587 this.on_lsp_progress(
5588 params,
5589 server_id,
5590 disk_based_diagnostics_progress_token.clone(),
5591 cx,
5592 );
5593 })
5594 .ok();
5595 }
5596 }
5597 })
5598 .detach();
5599
5600 language_server
5601 .on_notification::<lsp::notification::LogMessage, _>({
5602 let this = this.clone();
5603 move |params, mut cx| {
5604 if let Some(this) = this.upgrade() {
5605 this.update(&mut cx, |_, cx| {
5606 cx.emit(LspStoreEvent::LanguageServerLog(
5607 server_id,
5608 LanguageServerLogType::Log(params.typ),
5609 params.message,
5610 ));
5611 })
5612 .ok();
5613 }
5614 }
5615 })
5616 .detach();
5617
5618 language_server
5619 .on_notification::<lsp::notification::LogTrace, _>({
5620 let this = this.clone();
5621 move |params, mut cx| {
5622 if let Some(this) = this.upgrade() {
5623 this.update(&mut cx, |_, cx| {
5624 cx.emit(LspStoreEvent::LanguageServerLog(
5625 server_id,
5626 LanguageServerLogType::Trace(params.verbose),
5627 params.message,
5628 ));
5629 })
5630 .ok();
5631 }
5632 }
5633 })
5634 .detach();
5635
5636 match (&mut initialization_options, override_options) {
5637 (Some(initialization_options), Some(override_options)) => {
5638 merge_json_value_into(override_options, initialization_options);
5639 }
5640 (None, override_options) => initialization_options = override_options,
5641 _ => {}
5642 }
5643
5644 let language_server = cx
5645 .update(|cx| language_server.initialize(initialization_options, cx))?
5646 .await
5647 .inspect_err(|_| {
5648 if let Some(this) = this.upgrade() {
5649 this.update(cx, |_, cx| {
5650 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
5651 })
5652 .ok();
5653 }
5654 })?;
5655
5656 language_server
5657 .notify::<lsp::notification::DidChangeConfiguration>(
5658 lsp::DidChangeConfigurationParams {
5659 settings: workspace_config,
5660 },
5661 )
5662 .ok();
5663
5664 Ok(language_server)
5665 }
5666
5667 pub fn update_diagnostics(
5668 &mut self,
5669 language_server_id: LanguageServerId,
5670 mut params: lsp::PublishDiagnosticsParams,
5671 disk_based_sources: &[String],
5672 cx: &mut ModelContext<Self>,
5673 ) -> Result<()> {
5674 let abs_path = params
5675 .uri
5676 .to_file_path()
5677 .map_err(|_| anyhow!("URI is not a file"))?;
5678 let mut diagnostics = Vec::default();
5679 let mut primary_diagnostic_group_ids = HashMap::default();
5680 let mut sources_by_group_id = HashMap::default();
5681 let mut supporting_diagnostics = HashMap::default();
5682
5683 // Ensure that primary diagnostics are always the most severe
5684 params.diagnostics.sort_by_key(|item| item.severity);
5685
5686 for diagnostic in ¶ms.diagnostics {
5687 let source = diagnostic.source.as_ref();
5688 let code = diagnostic.code.as_ref().map(|code| match code {
5689 lsp::NumberOrString::Number(code) => code.to_string(),
5690 lsp::NumberOrString::String(code) => code.clone(),
5691 });
5692 let range = range_from_lsp(diagnostic.range);
5693 let is_supporting = diagnostic
5694 .related_information
5695 .as_ref()
5696 .map_or(false, |infos| {
5697 infos.iter().any(|info| {
5698 primary_diagnostic_group_ids.contains_key(&(
5699 source,
5700 code.clone(),
5701 range_from_lsp(info.location.range),
5702 ))
5703 })
5704 });
5705
5706 let is_unnecessary = diagnostic.tags.as_ref().map_or(false, |tags| {
5707 tags.iter().any(|tag| *tag == DiagnosticTag::UNNECESSARY)
5708 });
5709
5710 if is_supporting {
5711 supporting_diagnostics.insert(
5712 (source, code.clone(), range),
5713 (diagnostic.severity, is_unnecessary),
5714 );
5715 } else {
5716 let group_id = post_inc(&mut self.next_diagnostic_group_id);
5717 let is_disk_based =
5718 source.map_or(false, |source| disk_based_sources.contains(source));
5719
5720 sources_by_group_id.insert(group_id, source);
5721 primary_diagnostic_group_ids
5722 .insert((source, code.clone(), range.clone()), group_id);
5723
5724 diagnostics.push(DiagnosticEntry {
5725 range,
5726 diagnostic: Diagnostic {
5727 source: diagnostic.source.clone(),
5728 code: code.clone(),
5729 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
5730 message: diagnostic.message.trim().to_string(),
5731 group_id,
5732 is_primary: true,
5733 is_disk_based,
5734 is_unnecessary,
5735 data: diagnostic.data.clone(),
5736 },
5737 });
5738 if let Some(infos) = &diagnostic.related_information {
5739 for info in infos {
5740 if info.location.uri == params.uri && !info.message.is_empty() {
5741 let range = range_from_lsp(info.location.range);
5742 diagnostics.push(DiagnosticEntry {
5743 range,
5744 diagnostic: Diagnostic {
5745 source: diagnostic.source.clone(),
5746 code: code.clone(),
5747 severity: DiagnosticSeverity::INFORMATION,
5748 message: info.message.trim().to_string(),
5749 group_id,
5750 is_primary: false,
5751 is_disk_based,
5752 is_unnecessary: false,
5753 data: diagnostic.data.clone(),
5754 },
5755 });
5756 }
5757 }
5758 }
5759 }
5760 }
5761
5762 for entry in &mut diagnostics {
5763 let diagnostic = &mut entry.diagnostic;
5764 if !diagnostic.is_primary {
5765 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
5766 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
5767 source,
5768 diagnostic.code.clone(),
5769 entry.range.clone(),
5770 )) {
5771 if let Some(severity) = severity {
5772 diagnostic.severity = severity;
5773 }
5774 diagnostic.is_unnecessary = is_unnecessary;
5775 }
5776 }
5777 }
5778
5779 self.update_diagnostic_entries(
5780 language_server_id,
5781 abs_path,
5782 params.version,
5783 diagnostics,
5784 cx,
5785 )?;
5786 Ok(())
5787 }
5788
5789 fn insert_newly_running_language_server(
5790 &mut self,
5791 language: LanguageName,
5792 adapter: Arc<CachedLspAdapter>,
5793 language_server: Arc<LanguageServer>,
5794 server_id: LanguageServerId,
5795 key: (WorktreeId, LanguageServerName),
5796 cx: &mut ModelContext<Self>,
5797 ) -> Result<()> {
5798 // If the language server for this key doesn't match the server id, don't store the
5799 // server. Which will cause it to be dropped, killing the process
5800 if self
5801 .language_server_ids
5802 .get(&key)
5803 .map(|id| id != &server_id)
5804 .unwrap_or(false)
5805 {
5806 return Ok(());
5807 }
5808
5809 // Update language_servers collection with Running variant of LanguageServerState
5810 // indicating that the server is up and running and ready
5811 if let Some(local) = self.as_local_mut() {
5812 local.language_servers.insert(
5813 server_id,
5814 LanguageServerState::Running {
5815 adapter: adapter.clone(),
5816 language: language.clone(),
5817 server: language_server.clone(),
5818 simulate_disk_based_diagnostics_completion: None,
5819 },
5820 );
5821 }
5822
5823 self.language_server_statuses.insert(
5824 server_id,
5825 LanguageServerStatus {
5826 name: language_server.name().to_string(),
5827 pending_work: Default::default(),
5828 has_pending_diagnostic_updates: false,
5829 progress_tokens: Default::default(),
5830 },
5831 );
5832
5833 cx.emit(LspStoreEvent::LanguageServerAdded(server_id));
5834
5835 if let Some(downstream_client) = self.downstream_client.as_ref() {
5836 downstream_client.send(proto::StartLanguageServer {
5837 project_id: self.project_id,
5838 server: Some(proto::LanguageServer {
5839 id: server_id.0 as u64,
5840 name: language_server.name().to_string(),
5841 }),
5842 })?;
5843 }
5844
5845 // Tell the language server about every open buffer in the worktree that matches the language.
5846 self.buffer_store.update(cx, |buffer_store, cx| {
5847 for buffer_handle in buffer_store.buffers() {
5848 let buffer = buffer_handle.read(cx);
5849 let file = match File::from_dyn(buffer.file()) {
5850 Some(file) => file,
5851 None => continue,
5852 };
5853 let language = match buffer.language() {
5854 Some(language) => language,
5855 None => continue,
5856 };
5857
5858 if file.worktree.read(cx).id() != key.0
5859 || !self
5860 .languages
5861 .lsp_adapters(&language.name())
5862 .iter()
5863 .any(|a| a.name == key.1)
5864 {
5865 continue;
5866 }
5867
5868 let file = match file.as_local() {
5869 Some(file) => file,
5870 None => continue,
5871 };
5872
5873 let versions = self
5874 .buffer_snapshots
5875 .entry(buffer.remote_id())
5876 .or_default()
5877 .entry(server_id)
5878 .or_insert_with(|| {
5879 vec![LspBufferSnapshot {
5880 version: 0,
5881 snapshot: buffer.text_snapshot(),
5882 }]
5883 });
5884
5885 let snapshot = versions.last().unwrap();
5886 let version = snapshot.version;
5887 let initial_snapshot = &snapshot.snapshot;
5888 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
5889 language_server.notify::<lsp::notification::DidOpenTextDocument>(
5890 lsp::DidOpenTextDocumentParams {
5891 text_document: lsp::TextDocumentItem::new(
5892 uri,
5893 adapter.language_id(&language.name()),
5894 version,
5895 initial_snapshot.text(),
5896 ),
5897 },
5898 )?;
5899
5900 buffer_handle.update(cx, |buffer, cx| {
5901 buffer.set_completion_triggers(
5902 language_server
5903 .capabilities()
5904 .completion_provider
5905 .as_ref()
5906 .and_then(|provider| provider.trigger_characters.clone())
5907 .unwrap_or_default(),
5908 cx,
5909 )
5910 });
5911 }
5912 anyhow::Ok(())
5913 })?;
5914
5915 cx.notify();
5916 Ok(())
5917 }
5918
5919 fn buffer_snapshot_for_lsp_version(
5920 &mut self,
5921 buffer: &Model<Buffer>,
5922 server_id: LanguageServerId,
5923 version: Option<i32>,
5924 cx: &AppContext,
5925 ) -> Result<TextBufferSnapshot> {
5926 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
5927
5928 if let Some(version) = version {
5929 let buffer_id = buffer.read(cx).remote_id();
5930 let snapshots = self
5931 .buffer_snapshots
5932 .get_mut(&buffer_id)
5933 .and_then(|m| m.get_mut(&server_id))
5934 .ok_or_else(|| {
5935 anyhow!("no snapshots found for buffer {buffer_id} and server {server_id}")
5936 })?;
5937
5938 let found_snapshot = snapshots
5939 .binary_search_by_key(&version, |e| e.version)
5940 .map(|ix| snapshots[ix].snapshot.clone())
5941 .map_err(|_| {
5942 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
5943 })?;
5944
5945 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
5946 Ok(found_snapshot)
5947 } else {
5948 Ok((buffer.read(cx)).text_snapshot())
5949 }
5950 }
5951
5952 pub fn language_servers_running_disk_based_diagnostics(
5953 &self,
5954 ) -> impl Iterator<Item = LanguageServerId> + '_ {
5955 self.language_server_statuses
5956 .iter()
5957 .filter_map(|(id, status)| {
5958 if status.has_pending_diagnostic_updates {
5959 Some(*id)
5960 } else {
5961 None
5962 }
5963 })
5964 }
5965
5966 pub(crate) fn language_servers_for_buffer<'a>(
5967 &'a self,
5968 buffer: &'a Buffer,
5969 cx: &'a AppContext,
5970 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
5971 self.language_server_ids_for_buffer(buffer, cx)
5972 .into_iter()
5973 .filter_map(
5974 |server_id| match self.as_local()?.language_servers.get(&server_id)? {
5975 LanguageServerState::Running {
5976 adapter, server, ..
5977 } => Some((adapter, server)),
5978 _ => None,
5979 },
5980 )
5981 }
5982
5983 pub(crate) fn cancel_language_server_work_for_buffers(
5984 &mut self,
5985 buffers: impl IntoIterator<Item = Model<Buffer>>,
5986 cx: &mut ModelContext<Self>,
5987 ) {
5988 let servers = buffers
5989 .into_iter()
5990 .flat_map(|buffer| {
5991 self.language_server_ids_for_buffer(buffer.read(cx), cx)
5992 .into_iter()
5993 })
5994 .collect::<HashSet<_>>();
5995
5996 for server_id in servers {
5997 self.cancel_language_server_work(server_id, None, cx);
5998 }
5999 }
6000
6001 pub fn language_servers(
6002 &self,
6003 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName, WorktreeId)> {
6004 self.language_server_ids
6005 .iter()
6006 .map(|((worktree_id, server_name), server_id)| {
6007 (*server_id, server_name.clone(), *worktree_id)
6008 })
6009 }
6010
6011 pub fn register_supplementary_language_server(
6012 &mut self,
6013 id: LanguageServerId,
6014 name: LanguageServerName,
6015 server: Arc<LanguageServer>,
6016 cx: &mut ModelContext<Self>,
6017 ) {
6018 if let Some(local) = self.as_local_mut() {
6019 local
6020 .supplementary_language_servers
6021 .insert(id, (name, server));
6022 cx.emit(LspStoreEvent::LanguageServerAdded(id));
6023 }
6024 }
6025
6026 pub fn unregister_supplementary_language_server(
6027 &mut self,
6028 id: LanguageServerId,
6029 cx: &mut ModelContext<Self>,
6030 ) {
6031 if let Some(local) = self.as_local_mut() {
6032 local.supplementary_language_servers.remove(&id);
6033 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
6034 }
6035 }
6036
6037 pub fn supplementary_language_servers(
6038 &self,
6039 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
6040 self.as_local().into_iter().flat_map(|local| {
6041 local
6042 .supplementary_language_servers
6043 .iter()
6044 .map(|(id, (name, _))| (*id, name.clone()))
6045 })
6046 }
6047
6048 pub fn language_server_adapter_for_id(
6049 &self,
6050 id: LanguageServerId,
6051 ) -> Option<Arc<CachedLspAdapter>> {
6052 self.as_local()
6053 .and_then(|local| local.language_servers.get(&id))
6054 .and_then(|language_server_state| match language_server_state {
6055 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
6056 _ => None,
6057 })
6058 }
6059
6060 pub(super) fn update_local_worktree_language_servers(
6061 &mut self,
6062 worktree_handle: &Model<Worktree>,
6063 changes: &[(Arc<Path>, ProjectEntryId, PathChange)],
6064 cx: &mut ModelContext<Self>,
6065 ) {
6066 if changes.is_empty() {
6067 return;
6068 }
6069
6070 let Some(local) = self.as_local() else { return };
6071
6072 let worktree_id = worktree_handle.read(cx).id();
6073 let mut language_server_ids = self
6074 .language_server_ids
6075 .iter()
6076 .filter_map(|((server_worktree_id, _), server_id)| {
6077 (*server_worktree_id == worktree_id).then_some(*server_id)
6078 })
6079 .collect::<Vec<_>>();
6080 language_server_ids.sort();
6081 language_server_ids.dedup();
6082
6083 let abs_path = worktree_handle.read(cx).abs_path();
6084 for server_id in &language_server_ids {
6085 if let Some(LanguageServerState::Running { server, .. }) =
6086 local.language_servers.get(server_id)
6087 {
6088 if let Some(watched_paths) = local
6089 .language_server_watched_paths
6090 .get(server_id)
6091 .and_then(|paths| paths.read(cx).worktree_paths.get(&worktree_id))
6092 {
6093 let params = lsp::DidChangeWatchedFilesParams {
6094 changes: changes
6095 .iter()
6096 .filter_map(|(path, _, change)| {
6097 if !watched_paths.is_match(path) {
6098 return None;
6099 }
6100 let typ = match change {
6101 PathChange::Loaded => return None,
6102 PathChange::Added => lsp::FileChangeType::CREATED,
6103 PathChange::Removed => lsp::FileChangeType::DELETED,
6104 PathChange::Updated => lsp::FileChangeType::CHANGED,
6105 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
6106 };
6107 Some(lsp::FileEvent {
6108 uri: lsp::Url::from_file_path(abs_path.join(path)).unwrap(),
6109 typ,
6110 })
6111 })
6112 .collect(),
6113 };
6114 if !params.changes.is_empty() {
6115 server
6116 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
6117 .log_err();
6118 }
6119 }
6120 }
6121 }
6122 }
6123
6124 pub(crate) fn cancel_language_server_work(
6125 &mut self,
6126 server_id: LanguageServerId,
6127 token_to_cancel: Option<String>,
6128 _cx: &mut ModelContext<Self>,
6129 ) {
6130 let Some(local) = self.as_local() else {
6131 return;
6132 };
6133 let status = self.language_server_statuses.get(&server_id);
6134 let server = local.language_servers.get(&server_id);
6135 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status) {
6136 for (token, progress) in &status.pending_work {
6137 if let Some(token_to_cancel) = token_to_cancel.as_ref() {
6138 if token != token_to_cancel {
6139 continue;
6140 }
6141 }
6142 if progress.is_cancellable {
6143 server
6144 .notify::<lsp::notification::WorkDoneProgressCancel>(
6145 WorkDoneProgressCancelParams {
6146 token: lsp::NumberOrString::String(token.clone()),
6147 },
6148 )
6149 .ok();
6150 }
6151
6152 if progress.is_cancellable {
6153 server
6154 .notify::<lsp::notification::WorkDoneProgressCancel>(
6155 WorkDoneProgressCancelParams {
6156 token: lsp::NumberOrString::String(token.clone()),
6157 },
6158 )
6159 .ok();
6160 }
6161 }
6162 }
6163 }
6164
6165 pub fn wait_for_remote_buffer(
6166 &mut self,
6167 id: BufferId,
6168 cx: &mut ModelContext<Self>,
6169 ) -> Task<Result<Model<Buffer>>> {
6170 self.buffer_store.update(cx, |buffer_store, cx| {
6171 buffer_store.wait_for_remote_buffer(id, cx)
6172 })
6173 }
6174
6175 pub(crate) fn language_server_ids_for_buffer(
6176 &self,
6177 buffer: &Buffer,
6178 cx: &AppContext,
6179 ) -> Vec<LanguageServerId> {
6180 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
6181 let worktree_id = file.worktree_id(cx);
6182 self.languages
6183 .lsp_adapters(&language.name())
6184 .iter()
6185 .flat_map(|adapter| {
6186 let key = (worktree_id, adapter.name.clone());
6187 self.language_server_ids.get(&key).copied()
6188 })
6189 .collect()
6190 } else {
6191 Vec::new()
6192 }
6193 }
6194
6195 pub async fn deserialize_text_edits(
6196 this: Model<Self>,
6197 buffer_to_edit: Model<Buffer>,
6198 edits: Vec<lsp::TextEdit>,
6199 push_to_history: bool,
6200 _: Arc<CachedLspAdapter>,
6201 language_server: Arc<LanguageServer>,
6202 cx: &mut AsyncAppContext,
6203 ) -> Result<Option<Transaction>> {
6204 let edits = this
6205 .update(cx, |this, cx| {
6206 this.edits_from_lsp(
6207 &buffer_to_edit,
6208 edits,
6209 language_server.server_id(),
6210 None,
6211 cx,
6212 )
6213 })?
6214 .await?;
6215
6216 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
6217 buffer.finalize_last_transaction();
6218 buffer.start_transaction();
6219 for (range, text) in edits {
6220 buffer.edit([(range, text)], None, cx);
6221 }
6222
6223 if buffer.end_transaction(cx).is_some() {
6224 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6225 if !push_to_history {
6226 buffer.forget_transaction(transaction.id);
6227 }
6228 Some(transaction)
6229 } else {
6230 None
6231 }
6232 })?;
6233
6234 Ok(transaction)
6235 }
6236
6237 pub async fn deserialize_workspace_edit(
6238 this: Model<Self>,
6239 edit: lsp::WorkspaceEdit,
6240 push_to_history: bool,
6241 lsp_adapter: Arc<CachedLspAdapter>,
6242 language_server: Arc<LanguageServer>,
6243 cx: &mut AsyncAppContext,
6244 ) -> Result<ProjectTransaction> {
6245 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
6246
6247 let mut operations = Vec::new();
6248 if let Some(document_changes) = edit.document_changes {
6249 match document_changes {
6250 lsp::DocumentChanges::Edits(edits) => {
6251 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
6252 }
6253 lsp::DocumentChanges::Operations(ops) => operations = ops,
6254 }
6255 } else if let Some(changes) = edit.changes {
6256 operations.extend(changes.into_iter().map(|(uri, edits)| {
6257 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
6258 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
6259 uri,
6260 version: None,
6261 },
6262 edits: edits.into_iter().map(Edit::Plain).collect(),
6263 })
6264 }));
6265 }
6266
6267 let mut project_transaction = ProjectTransaction::default();
6268 for operation in operations {
6269 match operation {
6270 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
6271 let abs_path = op
6272 .uri
6273 .to_file_path()
6274 .map_err(|_| anyhow!("can't convert URI to path"))?;
6275
6276 if let Some(parent_path) = abs_path.parent() {
6277 fs.create_dir(parent_path).await?;
6278 }
6279 if abs_path.ends_with("/") {
6280 fs.create_dir(&abs_path).await?;
6281 } else {
6282 fs.create_file(
6283 &abs_path,
6284 op.options
6285 .map(|options| fs::CreateOptions {
6286 overwrite: options.overwrite.unwrap_or(false),
6287 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
6288 })
6289 .unwrap_or_default(),
6290 )
6291 .await?;
6292 }
6293 }
6294
6295 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
6296 let source_abs_path = op
6297 .old_uri
6298 .to_file_path()
6299 .map_err(|_| anyhow!("can't convert URI to path"))?;
6300 let target_abs_path = op
6301 .new_uri
6302 .to_file_path()
6303 .map_err(|_| anyhow!("can't convert URI to path"))?;
6304 fs.rename(
6305 &source_abs_path,
6306 &target_abs_path,
6307 op.options
6308 .map(|options| fs::RenameOptions {
6309 overwrite: options.overwrite.unwrap_or(false),
6310 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
6311 })
6312 .unwrap_or_default(),
6313 )
6314 .await?;
6315 }
6316
6317 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
6318 let abs_path = op
6319 .uri
6320 .to_file_path()
6321 .map_err(|_| anyhow!("can't convert URI to path"))?;
6322 let options = op
6323 .options
6324 .map(|options| fs::RemoveOptions {
6325 recursive: options.recursive.unwrap_or(false),
6326 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
6327 })
6328 .unwrap_or_default();
6329 if abs_path.ends_with("/") {
6330 fs.remove_dir(&abs_path, options).await?;
6331 } else {
6332 fs.remove_file(&abs_path, options).await?;
6333 }
6334 }
6335
6336 lsp::DocumentChangeOperation::Edit(op) => {
6337 let buffer_to_edit = this
6338 .update(cx, |this, cx| {
6339 this.open_local_buffer_via_lsp(
6340 op.text_document.uri.clone(),
6341 language_server.server_id(),
6342 lsp_adapter.name.clone(),
6343 cx,
6344 )
6345 })?
6346 .await?;
6347
6348 let edits = this
6349 .update(cx, |this, cx| {
6350 let path = buffer_to_edit.read(cx).project_path(cx);
6351 let active_entry = this.active_entry;
6352 let is_active_entry = path.clone().map_or(false, |project_path| {
6353 this.worktree_store
6354 .read(cx)
6355 .entry_for_path(&project_path, cx)
6356 .map_or(false, |entry| Some(entry.id) == active_entry)
6357 });
6358
6359 let (mut edits, mut snippet_edits) = (vec![], vec![]);
6360 for edit in op.edits {
6361 match edit {
6362 Edit::Plain(edit) => edits.push(edit),
6363 Edit::Annotated(edit) => edits.push(edit.text_edit),
6364 Edit::Snippet(edit) => {
6365 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
6366 else {
6367 continue;
6368 };
6369
6370 if is_active_entry {
6371 snippet_edits.push((edit.range, snippet));
6372 } else {
6373 // Since this buffer is not focused, apply a normal edit.
6374 edits.push(TextEdit {
6375 range: edit.range,
6376 new_text: snippet.text,
6377 });
6378 }
6379 }
6380 }
6381 }
6382 if !snippet_edits.is_empty() {
6383 let buffer_id = buffer_to_edit.read(cx).remote_id();
6384 let version = if let Some(buffer_version) = op.text_document.version
6385 {
6386 this.buffer_snapshots
6387 .get(&buffer_id)
6388 .and_then(|server_to_snapshots| {
6389 let all_snapshots = server_to_snapshots
6390 .get(&language_server.server_id())?;
6391 all_snapshots
6392 .binary_search_by_key(&buffer_version, |snapshot| {
6393 snapshot.version
6394 })
6395 .ok()
6396 .and_then(|index| all_snapshots.get(index))
6397 })
6398 .map(|lsp_snapshot| lsp_snapshot.snapshot.version())
6399 } else {
6400 Some(buffer_to_edit.read(cx).saved_version())
6401 };
6402
6403 let most_recent_edit = version.and_then(|version| {
6404 version.iter().max_by_key(|timestamp| timestamp.value)
6405 });
6406 // Check if the edit that triggered that edit has been made by this participant.
6407
6408 if let Some(most_recent_edit) = most_recent_edit {
6409 cx.emit(LspStoreEvent::SnippetEdit {
6410 buffer_id,
6411 edits: snippet_edits,
6412 most_recent_edit,
6413 });
6414 }
6415 }
6416
6417 this.edits_from_lsp(
6418 &buffer_to_edit,
6419 edits,
6420 language_server.server_id(),
6421 op.text_document.version,
6422 cx,
6423 )
6424 })?
6425 .await?;
6426
6427 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
6428 buffer.finalize_last_transaction();
6429 buffer.start_transaction();
6430 for (range, text) in edits {
6431 buffer.edit([(range, text)], None, cx);
6432 }
6433 let transaction = if buffer.end_transaction(cx).is_some() {
6434 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6435 if !push_to_history {
6436 buffer.forget_transaction(transaction.id);
6437 }
6438 Some(transaction)
6439 } else {
6440 None
6441 };
6442
6443 transaction
6444 })?;
6445 if let Some(transaction) = transaction {
6446 project_transaction.0.insert(buffer_to_edit, transaction);
6447 }
6448 }
6449 }
6450 }
6451
6452 Ok(project_transaction)
6453 }
6454
6455 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
6456 proto::Symbol {
6457 language_server_name: symbol.language_server_name.0.to_string(),
6458 source_worktree_id: symbol.source_worktree_id.to_proto(),
6459 worktree_id: symbol.path.worktree_id.to_proto(),
6460 path: symbol.path.path.to_string_lossy().to_string(),
6461 name: symbol.name.clone(),
6462 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
6463 start: Some(proto::PointUtf16 {
6464 row: symbol.range.start.0.row,
6465 column: symbol.range.start.0.column,
6466 }),
6467 end: Some(proto::PointUtf16 {
6468 row: symbol.range.end.0.row,
6469 column: symbol.range.end.0.column,
6470 }),
6471 signature: symbol.signature.to_vec(),
6472 }
6473 }
6474
6475 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
6476 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
6477 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
6478 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
6479 let path = ProjectPath {
6480 worktree_id,
6481 path: PathBuf::from(serialized_symbol.path).into(),
6482 };
6483
6484 let start = serialized_symbol
6485 .start
6486 .ok_or_else(|| anyhow!("invalid start"))?;
6487 let end = serialized_symbol
6488 .end
6489 .ok_or_else(|| anyhow!("invalid end"))?;
6490 Ok(CoreSymbol {
6491 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
6492 source_worktree_id,
6493 path,
6494 name: serialized_symbol.name,
6495 range: Unclipped(PointUtf16::new(start.row, start.column))
6496 ..Unclipped(PointUtf16::new(end.row, end.column)),
6497 kind,
6498 signature: serialized_symbol
6499 .signature
6500 .try_into()
6501 .map_err(|_| anyhow!("invalid signature"))?,
6502 })
6503 }
6504
6505 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
6506 proto::Completion {
6507 old_start: Some(serialize_anchor(&completion.old_range.start)),
6508 old_end: Some(serialize_anchor(&completion.old_range.end)),
6509 new_text: completion.new_text.clone(),
6510 server_id: completion.server_id.0 as u64,
6511 lsp_completion: serde_json::to_vec(&completion.lsp_completion).unwrap(),
6512 }
6513 }
6514
6515 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
6516 let old_start = completion
6517 .old_start
6518 .and_then(deserialize_anchor)
6519 .ok_or_else(|| anyhow!("invalid old start"))?;
6520 let old_end = completion
6521 .old_end
6522 .and_then(deserialize_anchor)
6523 .ok_or_else(|| anyhow!("invalid old end"))?;
6524 let lsp_completion = serde_json::from_slice(&completion.lsp_completion)?;
6525
6526 Ok(CoreCompletion {
6527 old_range: old_start..old_end,
6528 new_text: completion.new_text,
6529 server_id: LanguageServerId(completion.server_id as usize),
6530 lsp_completion,
6531 })
6532 }
6533
6534 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
6535 proto::CodeAction {
6536 server_id: action.server_id.0 as u64,
6537 start: Some(serialize_anchor(&action.range.start)),
6538 end: Some(serialize_anchor(&action.range.end)),
6539 lsp_action: serde_json::to_vec(&action.lsp_action).unwrap(),
6540 }
6541 }
6542
6543 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
6544 let start = action
6545 .start
6546 .and_then(deserialize_anchor)
6547 .ok_or_else(|| anyhow!("invalid start"))?;
6548 let end = action
6549 .end
6550 .and_then(deserialize_anchor)
6551 .ok_or_else(|| anyhow!("invalid end"))?;
6552 let lsp_action = serde_json::from_slice(&action.lsp_action)?;
6553 Ok(CodeAction {
6554 server_id: LanguageServerId(action.server_id as usize),
6555 range: start..end,
6556 lsp_action,
6557 })
6558 }
6559}
6560
6561impl EventEmitter<LspStoreEvent> for LspStore {}
6562
6563fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
6564 hover
6565 .contents
6566 .retain(|hover_block| !hover_block.text.trim().is_empty());
6567 if hover.contents.is_empty() {
6568 None
6569 } else {
6570 Some(hover)
6571 }
6572}
6573
6574async fn populate_labels_for_completions(
6575 mut new_completions: Vec<CoreCompletion>,
6576 language_registry: &Arc<LanguageRegistry>,
6577 language: Option<Arc<Language>>,
6578 lsp_adapter: Option<Arc<CachedLspAdapter>>,
6579 completions: &mut Vec<Completion>,
6580) {
6581 let lsp_completions = new_completions
6582 .iter_mut()
6583 .map(|completion| mem::take(&mut completion.lsp_completion))
6584 .collect::<Vec<_>>();
6585
6586 let labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
6587 lsp_adapter
6588 .labels_for_completions(&lsp_completions, language)
6589 .await
6590 .log_err()
6591 .unwrap_or_default()
6592 } else {
6593 Vec::new()
6594 };
6595
6596 for ((completion, lsp_completion), label) in new_completions
6597 .into_iter()
6598 .zip(lsp_completions)
6599 .zip(labels.into_iter().chain(iter::repeat(None)))
6600 {
6601 let documentation = if let Some(docs) = &lsp_completion.documentation {
6602 Some(prepare_completion_documentation(docs, language_registry, language.clone()).await)
6603 } else {
6604 None
6605 };
6606
6607 completions.push(Completion {
6608 old_range: completion.old_range,
6609 new_text: completion.new_text,
6610 label: label.unwrap_or_else(|| {
6611 CodeLabel::plain(
6612 lsp_completion.label.clone(),
6613 lsp_completion.filter_text.as_deref(),
6614 )
6615 }),
6616 server_id: completion.server_id,
6617 documentation,
6618 lsp_completion,
6619 confirm: None,
6620 })
6621 }
6622}
6623
6624#[derive(Debug)]
6625pub enum LanguageServerToQuery {
6626 Primary,
6627 Other(LanguageServerId),
6628}
6629
6630#[derive(Default)]
6631struct LanguageServerWatchedPaths {
6632 worktree_paths: HashMap<WorktreeId, GlobSet>,
6633 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
6634}
6635
6636#[derive(Default)]
6637struct LanguageServerWatchedPathsBuilder {
6638 worktree_paths: HashMap<WorktreeId, GlobSet>,
6639 abs_paths: HashMap<Arc<Path>, GlobSet>,
6640}
6641
6642impl LanguageServerWatchedPathsBuilder {
6643 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
6644 self.worktree_paths.insert(worktree_id, glob_set);
6645 }
6646 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
6647 self.abs_paths.insert(path, glob_set);
6648 }
6649 fn build(
6650 self,
6651 fs: Arc<dyn Fs>,
6652 language_server_id: LanguageServerId,
6653 cx: &mut ModelContext<LspStore>,
6654 ) -> Model<LanguageServerWatchedPaths> {
6655 let project = cx.weak_model();
6656
6657 cx.new_model(|cx| {
6658 let this_id = cx.entity_id();
6659 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
6660 let abs_paths = self
6661 .abs_paths
6662 .into_iter()
6663 .map(|(abs_path, globset)| {
6664 let task = cx.spawn({
6665 let abs_path = abs_path.clone();
6666 let fs = fs.clone();
6667
6668 let lsp_store = project.clone();
6669 |_, mut cx| async move {
6670 maybe!(async move {
6671 let mut push_updates =
6672 fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
6673 while let Some(update) = push_updates.0.next().await {
6674 let action = lsp_store
6675 .update(&mut cx, |this, cx| {
6676 let Some(local) = this.as_local() else {
6677 return ControlFlow::Break(());
6678 };
6679 let Some(watcher) = local
6680 .language_server_watched_paths
6681 .get(&language_server_id)
6682 else {
6683 return ControlFlow::Break(());
6684 };
6685 if watcher.entity_id() != this_id {
6686 // This watcher is no longer registered on the project, which means that we should
6687 // cease operations.
6688 return ControlFlow::Break(());
6689 }
6690 let (globs, _) = watcher
6691 .read(cx)
6692 .abs_paths
6693 .get(&abs_path)
6694 .expect(
6695 "Watched abs path is not registered with a watcher",
6696 );
6697 let matching_entries = update
6698 .into_iter()
6699 .filter(|event| globs.is_match(&event.path))
6700 .collect::<Vec<_>>();
6701 this.lsp_notify_abs_paths_changed(
6702 language_server_id,
6703 matching_entries,
6704 );
6705 ControlFlow::Continue(())
6706 })
6707 .ok()?;
6708
6709 if action.is_break() {
6710 break;
6711 }
6712 }
6713 Some(())
6714 })
6715 .await;
6716 }
6717 });
6718 (abs_path, (globset, task))
6719 })
6720 .collect();
6721 LanguageServerWatchedPaths {
6722 worktree_paths: self.worktree_paths,
6723 abs_paths,
6724 }
6725 })
6726 }
6727}
6728
6729struct LspBufferSnapshot {
6730 version: i32,
6731 snapshot: TextBufferSnapshot,
6732}
6733
6734/// A prompt requested by LSP server.
6735#[derive(Clone, Debug)]
6736pub struct LanguageServerPromptRequest {
6737 pub level: PromptLevel,
6738 pub message: String,
6739 pub actions: Vec<MessageActionItem>,
6740 pub lsp_name: String,
6741 pub(crate) response_channel: Sender<MessageActionItem>,
6742}
6743
6744impl LanguageServerPromptRequest {
6745 pub async fn respond(self, index: usize) -> Option<()> {
6746 if let Some(response) = self.actions.into_iter().nth(index) {
6747 self.response_channel.send(response).await.ok()
6748 } else {
6749 None
6750 }
6751 }
6752}
6753impl PartialEq for LanguageServerPromptRequest {
6754 fn eq(&self, other: &Self) -> bool {
6755 self.message == other.message && self.actions == other.actions
6756 }
6757}
6758
6759#[derive(Clone, Debug, PartialEq)]
6760pub enum LanguageServerLogType {
6761 Log(MessageType),
6762 Trace(Option<String>),
6763}
6764
6765pub enum LanguageServerState {
6766 Starting(Task<Option<Arc<LanguageServer>>>),
6767
6768 Running {
6769 language: LanguageName,
6770 adapter: Arc<CachedLspAdapter>,
6771 server: Arc<LanguageServer>,
6772 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
6773 },
6774}
6775
6776impl std::fmt::Debug for LanguageServerState {
6777 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6778 match self {
6779 LanguageServerState::Starting(_) => {
6780 f.debug_struct("LanguageServerState::Starting").finish()
6781 }
6782 LanguageServerState::Running { language, .. } => f
6783 .debug_struct("LanguageServerState::Running")
6784 .field("language", &language)
6785 .finish(),
6786 }
6787 }
6788}
6789
6790#[derive(Clone, Debug, Serialize)]
6791pub struct LanguageServerProgress {
6792 pub is_disk_based_diagnostics_progress: bool,
6793 pub is_cancellable: bool,
6794 pub title: Option<String>,
6795 pub message: Option<String>,
6796 pub percentage: Option<usize>,
6797 #[serde(skip_serializing)]
6798 pub last_update_at: Instant,
6799}
6800
6801#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
6802pub struct DiagnosticSummary {
6803 pub error_count: usize,
6804 pub warning_count: usize,
6805}
6806
6807impl DiagnosticSummary {
6808 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
6809 let mut this = Self {
6810 error_count: 0,
6811 warning_count: 0,
6812 };
6813
6814 for entry in diagnostics {
6815 if entry.diagnostic.is_primary {
6816 match entry.diagnostic.severity {
6817 DiagnosticSeverity::ERROR => this.error_count += 1,
6818 DiagnosticSeverity::WARNING => this.warning_count += 1,
6819 _ => {}
6820 }
6821 }
6822 }
6823
6824 this
6825 }
6826
6827 pub fn is_empty(&self) -> bool {
6828 self.error_count == 0 && self.warning_count == 0
6829 }
6830
6831 pub fn to_proto(
6832 &self,
6833 language_server_id: LanguageServerId,
6834 path: &Path,
6835 ) -> proto::DiagnosticSummary {
6836 proto::DiagnosticSummary {
6837 path: path.to_string_lossy().to_string(),
6838 language_server_id: language_server_id.0 as u64,
6839 error_count: self.error_count as u32,
6840 warning_count: self.warning_count as u32,
6841 }
6842 }
6843}
6844
6845fn glob_literal_prefix(glob: &str) -> &str {
6846 let is_absolute = glob.starts_with(path::MAIN_SEPARATOR);
6847
6848 let mut literal_end = is_absolute as usize;
6849 for (i, part) in glob.split(path::MAIN_SEPARATOR).enumerate() {
6850 if part.contains(['*', '?', '{', '}']) {
6851 break;
6852 } else {
6853 if i > 0 {
6854 // Account for separator prior to this part
6855 literal_end += path::MAIN_SEPARATOR.len_utf8();
6856 }
6857 literal_end += part.len();
6858 }
6859 }
6860 let literal_end = literal_end.min(glob.len());
6861 &glob[..literal_end]
6862}
6863
6864pub struct SshLspAdapter {
6865 name: LanguageServerName,
6866 binary: LanguageServerBinary,
6867 initialization_options: Option<String>,
6868 code_action_kinds: Option<Vec<CodeActionKind>>,
6869}
6870
6871impl SshLspAdapter {
6872 pub fn new(
6873 name: LanguageServerName,
6874 binary: LanguageServerBinary,
6875 initialization_options: Option<String>,
6876 code_action_kinds: Option<String>,
6877 ) -> Self {
6878 Self {
6879 name,
6880 binary,
6881 initialization_options,
6882 code_action_kinds: code_action_kinds
6883 .as_ref()
6884 .and_then(|c| serde_json::from_str(c).ok()),
6885 }
6886 }
6887}
6888
6889#[async_trait(?Send)]
6890impl LspAdapter for SshLspAdapter {
6891 fn name(&self) -> LanguageServerName {
6892 self.name.clone()
6893 }
6894
6895 async fn initialization_options(
6896 self: Arc<Self>,
6897 _: &Arc<dyn LspAdapterDelegate>,
6898 ) -> Result<Option<serde_json::Value>> {
6899 let Some(options) = &self.initialization_options else {
6900 return Ok(None);
6901 };
6902 let result = serde_json::from_str(options)?;
6903 Ok(result)
6904 }
6905
6906 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
6907 self.code_action_kinds.clone()
6908 }
6909
6910 async fn check_if_user_installed(
6911 &self,
6912 _: &dyn LspAdapterDelegate,
6913 _: &AsyncAppContext,
6914 ) -> Option<LanguageServerBinary> {
6915 Some(self.binary.clone())
6916 }
6917
6918 async fn cached_server_binary(
6919 &self,
6920 _: PathBuf,
6921 _: &dyn LspAdapterDelegate,
6922 ) -> Option<LanguageServerBinary> {
6923 None
6924 }
6925
6926 async fn fetch_latest_server_version(
6927 &self,
6928 _: &dyn LspAdapterDelegate,
6929 ) -> Result<Box<dyn 'static + Send + Any>> {
6930 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
6931 }
6932
6933 async fn fetch_server_binary(
6934 &self,
6935 _: Box<dyn 'static + Send + Any>,
6936 _: PathBuf,
6937 _: &dyn LspAdapterDelegate,
6938 ) -> Result<LanguageServerBinary> {
6939 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
6940 }
6941
6942 async fn installation_test_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
6943 None
6944 }
6945}
6946
6947pub struct ProjectLspAdapterDelegate {
6948 lsp_store: WeakModel<LspStore>,
6949 worktree: worktree::Snapshot,
6950 fs: Option<Arc<dyn Fs>>,
6951 http_client: Arc<dyn HttpClient>,
6952 language_registry: Arc<LanguageRegistry>,
6953 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
6954 upstream_client: Option<AnyProtoClient>,
6955}
6956
6957impl ProjectLspAdapterDelegate {
6958 fn for_local(
6959 lsp_store: &LspStore,
6960 worktree: &Model<Worktree>,
6961 cx: &mut ModelContext<LspStore>,
6962 ) -> Arc<Self> {
6963 let local = lsp_store
6964 .as_local()
6965 .expect("ProjectLspAdapterDelegate cannot be constructed on a remote");
6966
6967 let http_client = local
6968 .http_client
6969 .clone()
6970 .unwrap_or_else(|| Arc::new(BlockedHttpClient));
6971
6972 Self::new(
6973 lsp_store,
6974 worktree,
6975 http_client,
6976 Some(local.fs.clone()),
6977 None,
6978 cx,
6979 )
6980 }
6981
6982 fn for_ssh(
6983 lsp_store: &LspStore,
6984 worktree: &Model<Worktree>,
6985 upstream_client: AnyProtoClient,
6986 cx: &mut ModelContext<LspStore>,
6987 ) -> Arc<Self> {
6988 Self::new(
6989 lsp_store,
6990 worktree,
6991 Arc::new(BlockedHttpClient),
6992 None,
6993 Some(upstream_client),
6994 cx,
6995 )
6996 }
6997
6998 pub fn new(
6999 lsp_store: &LspStore,
7000 worktree: &Model<Worktree>,
7001 http_client: Arc<dyn HttpClient>,
7002 fs: Option<Arc<dyn Fs>>,
7003 upstream_client: Option<AnyProtoClient>,
7004 cx: &mut ModelContext<LspStore>,
7005 ) -> Arc<Self> {
7006 let worktree_id = worktree.read(cx).id();
7007 let worktree_abs_path = worktree.read(cx).abs_path();
7008 let load_shell_env_task = if let Some(environment) =
7009 &lsp_store.as_local().map(|local| local.environment.clone())
7010 {
7011 environment.update(cx, |env, cx| {
7012 env.get_environment(Some(worktree_id), Some(worktree_abs_path), cx)
7013 })
7014 } else {
7015 Task::ready(None).shared()
7016 };
7017
7018 Arc::new(Self {
7019 lsp_store: cx.weak_model(),
7020 worktree: worktree.read(cx).snapshot(),
7021 fs,
7022 http_client,
7023 upstream_client,
7024 language_registry: lsp_store.languages.clone(),
7025 load_shell_env_task,
7026 })
7027 }
7028}
7029
7030struct BlockedHttpClient;
7031
7032impl HttpClient for BlockedHttpClient {
7033 fn send(
7034 &self,
7035 _req: Request<AsyncBody>,
7036 ) -> BoxFuture<'static, Result<Response<AsyncBody>, Error>> {
7037 Box::pin(async {
7038 Err(std::io::Error::new(
7039 std::io::ErrorKind::PermissionDenied,
7040 "ssh host blocked http connection",
7041 )
7042 .into())
7043 })
7044 }
7045
7046 fn proxy(&self) -> Option<&Uri> {
7047 None
7048 }
7049}
7050
7051pub fn language_server_settings<'a, 'b: 'a>(
7052 delegate: &'a dyn LspAdapterDelegate,
7053 language: &str,
7054 cx: &'b AppContext,
7055) -> Option<&'a LspSettings> {
7056 ProjectSettings::get(
7057 Some(SettingsLocation {
7058 worktree_id: delegate.worktree_id(),
7059 path: delegate.worktree_root_path(),
7060 }),
7061 cx,
7062 )
7063 .lsp
7064 .get(language)
7065}
7066
7067#[async_trait]
7068impl LspAdapterDelegate for ProjectLspAdapterDelegate {
7069 fn show_notification(&self, message: &str, cx: &mut AppContext) {
7070 self.lsp_store
7071 .update(cx, |_, cx| {
7072 cx.emit(LspStoreEvent::Notification(message.to_owned()))
7073 })
7074 .ok();
7075 }
7076
7077 fn http_client(&self) -> Arc<dyn HttpClient> {
7078 self.http_client.clone()
7079 }
7080
7081 fn worktree_id(&self) -> WorktreeId {
7082 self.worktree.id()
7083 }
7084
7085 fn worktree_root_path(&self) -> &Path {
7086 self.worktree.abs_path().as_ref()
7087 }
7088
7089 async fn shell_env(&self) -> HashMap<String, String> {
7090 if let Some(upstream_client) = &self.upstream_client {
7091 use rpc::proto::SSH_PROJECT_ID;
7092
7093 return upstream_client
7094 .request(proto::ShellEnv {
7095 project_id: SSH_PROJECT_ID,
7096 worktree_id: self.worktree_id().to_proto(),
7097 })
7098 .await
7099 .map(|response| response.env.into_iter().collect())
7100 .unwrap_or_default();
7101 }
7102
7103 let task = self.load_shell_env_task.clone();
7104 task.await.unwrap_or_default()
7105 }
7106
7107 #[cfg(not(target_os = "windows"))]
7108 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
7109 if let Some(upstream_client) = &self.upstream_client {
7110 use rpc::proto::SSH_PROJECT_ID;
7111
7112 return upstream_client
7113 .request(proto::WhichCommand {
7114 project_id: SSH_PROJECT_ID,
7115 worktree_id: self.worktree_id().to_proto(),
7116 command: command.to_string_lossy().to_string(),
7117 })
7118 .await
7119 .log_err()
7120 .and_then(|response| response.path)
7121 .map(PathBuf::from);
7122 }
7123
7124 self.fs.as_ref()?;
7125
7126 let worktree_abs_path = self.worktree.abs_path();
7127 let shell_path = self.shell_env().await.get("PATH").cloned();
7128 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
7129 }
7130
7131 #[cfg(target_os = "windows")]
7132 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
7133 self.fs.as_ref()?;
7134
7135 // todo(windows) Getting the shell env variables in a current directory on Windows is more complicated than other platforms
7136 // there isn't a 'default shell' necessarily. The closest would be the default profile on the windows terminal
7137 // SEE: https://learn.microsoft.com/en-us/windows/terminal/customize-settings/startup
7138 which::which(command).ok()
7139 }
7140
7141 fn update_status(
7142 &self,
7143 server_name: LanguageServerName,
7144 status: language::LanguageServerBinaryStatus,
7145 ) {
7146 self.language_registry
7147 .update_lsp_status(server_name, status);
7148 }
7149
7150 async fn read_text_file(&self, path: PathBuf) -> Result<String> {
7151 if self.worktree.entry_for_path(&path).is_none() {
7152 return Err(anyhow!("no such path {path:?}"));
7153 };
7154 if let Some(fs) = &self.fs {
7155 let content = fs.load(&path).await?;
7156 Ok(content)
7157 } else {
7158 return Err(anyhow!("cannot open {path:?} on ssh host (yet!)"));
7159 }
7160 }
7161}
7162
7163async fn populate_labels_for_symbols(
7164 symbols: Vec<CoreSymbol>,
7165 language_registry: &Arc<LanguageRegistry>,
7166 default_language: Option<LanguageName>,
7167 lsp_adapter: Option<Arc<CachedLspAdapter>>,
7168 output: &mut Vec<Symbol>,
7169) {
7170 #[allow(clippy::mutable_key_type)]
7171 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
7172
7173 let mut unknown_path = None;
7174 for symbol in symbols {
7175 let language = language_registry
7176 .language_for_file_path(&symbol.path.path)
7177 .await
7178 .ok()
7179 .or_else(|| {
7180 unknown_path.get_or_insert(symbol.path.path.clone());
7181 default_language.as_ref().and_then(|name| {
7182 language_registry
7183 .language_for_name(&name.0)
7184 .now_or_never()?
7185 .ok()
7186 })
7187 });
7188 symbols_by_language
7189 .entry(language)
7190 .or_default()
7191 .push(symbol);
7192 }
7193
7194 if let Some(unknown_path) = unknown_path {
7195 log::info!(
7196 "no language found for symbol path {}",
7197 unknown_path.display()
7198 );
7199 }
7200
7201 let mut label_params = Vec::new();
7202 for (language, mut symbols) in symbols_by_language {
7203 label_params.clear();
7204 label_params.extend(
7205 symbols
7206 .iter_mut()
7207 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
7208 );
7209
7210 let mut labels = Vec::new();
7211 if let Some(language) = language {
7212 let lsp_adapter = lsp_adapter.clone().or_else(|| {
7213 language_registry
7214 .lsp_adapters(&language.name())
7215 .first()
7216 .cloned()
7217 });
7218 if let Some(lsp_adapter) = lsp_adapter {
7219 labels = lsp_adapter
7220 .labels_for_symbols(&label_params, &language)
7221 .await
7222 .log_err()
7223 .unwrap_or_default();
7224 }
7225 }
7226
7227 for ((symbol, (name, _)), label) in symbols
7228 .into_iter()
7229 .zip(label_params.drain(..))
7230 .zip(labels.into_iter().chain(iter::repeat(None)))
7231 {
7232 output.push(Symbol {
7233 language_server_name: symbol.language_server_name,
7234 source_worktree_id: symbol.source_worktree_id,
7235 path: symbol.path,
7236 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
7237 name,
7238 kind: symbol.kind,
7239 range: symbol.range,
7240 signature: symbol.signature,
7241 });
7242 }
7243 }
7244}
7245
7246fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
7247 match server.capabilities().text_document_sync.as_ref()? {
7248 lsp::TextDocumentSyncCapability::Kind(kind) => match *kind {
7249 lsp::TextDocumentSyncKind::NONE => None,
7250 lsp::TextDocumentSyncKind::FULL => Some(true),
7251 lsp::TextDocumentSyncKind::INCREMENTAL => Some(false),
7252 _ => None,
7253 },
7254 lsp::TextDocumentSyncCapability::Options(options) => match options.save.as_ref()? {
7255 lsp::TextDocumentSyncSaveOptions::Supported(supported) => {
7256 if *supported {
7257 Some(true)
7258 } else {
7259 None
7260 }
7261 }
7262 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
7263 Some(save_options.include_text.unwrap_or(false))
7264 }
7265 },
7266 }
7267}
7268
7269#[cfg(test)]
7270#[test]
7271fn test_glob_literal_prefix() {
7272 assert_eq!(glob_literal_prefix("**/*.js"), "");
7273 assert_eq!(glob_literal_prefix("node_modules/**/*.js"), "node_modules");
7274 assert_eq!(glob_literal_prefix("foo/{bar,baz}.js"), "foo");
7275 assert_eq!(glob_literal_prefix("foo/bar/baz.js"), "foo/bar/baz.js");
7276}