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