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