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