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