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