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