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