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