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