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