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