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