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