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