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