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