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