1mod db;
2pub mod fs;
3mod ignore;
4mod lsp_command;
5pub mod search;
6pub mod worktree;
7
8#[cfg(test)]
9mod project_tests;
10
11use anyhow::{anyhow, Context, Result};
12use client::{proto, Client, PeerId, TypedEnvelope, User, UserStore};
13use clock::ReplicaId;
14use collections::{hash_map, BTreeMap, HashMap, HashSet};
15use futures::{future::Shared, AsyncWriteExt, Future, FutureExt, SinkExt, StreamExt, TryFutureExt};
16use fuzzy::{PathMatch, PathMatchCandidate, PathMatchCandidateSet};
17use gpui::{
18 AnyModelHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
19 MutableAppContext, Task, UpgradeModelHandle, WeakModelHandle,
20};
21use language::{
22 point_to_lsp,
23 proto::{
24 deserialize_anchor, deserialize_line_ending, deserialize_version, serialize_anchor,
25 serialize_version,
26 },
27 range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CharKind, CodeAction, CodeLabel,
28 Completion, Diagnostic, DiagnosticEntry, DiagnosticSet, Event as BufferEvent, File as _,
29 Language, LanguageRegistry, LanguageServerName, LineEnding, LocalFile, LspAdapter,
30 OffsetRangeExt, Operation, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
31 Transaction,
32};
33use lsp::{
34 DiagnosticSeverity, DiagnosticTag, DocumentHighlightKind, LanguageServer, LanguageString,
35 MarkedString,
36};
37use lsp_command::*;
38use parking_lot::Mutex;
39use postage::stream::Stream;
40use postage::watch;
41use rand::prelude::*;
42use search::SearchQuery;
43use serde::Serialize;
44use settings::Settings;
45use sha2::{Digest, Sha256};
46use similar::{ChangeTag, TextDiff};
47use std::{
48 cell::RefCell,
49 cmp::{self, Ordering},
50 convert::TryInto,
51 ffi::OsString,
52 hash::Hash,
53 mem,
54 num::NonZeroU32,
55 ops::Range,
56 os::unix::{ffi::OsStrExt, prelude::OsStringExt},
57 path::{Component, Path, PathBuf},
58 rc::Rc,
59 str,
60 sync::{
61 atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
62 Arc,
63 },
64 time::Instant,
65};
66use thiserror::Error;
67use util::{post_inc, ResultExt, TryFutureExt as _};
68
69pub use db::Db;
70pub use fs::*;
71pub use worktree::*;
72
73pub trait Item: Entity {
74 fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId>;
75}
76
77pub struct ProjectStore {
78 db: Arc<Db>,
79 projects: Vec<WeakModelHandle<Project>>,
80}
81
82// Language server state is stored across 3 collections:
83// language_servers =>
84// a mapping from unique server id to LanguageServerState which can either be a task for a
85// server in the process of starting, or a running server with adapter and language server arcs
86// language_server_ids => a mapping from worktreeId and server name to the unique server id
87// language_server_statuses => a mapping from unique server id to the current server status
88//
89// Multiple worktrees can map to the same language server for example when you jump to the definition
90// of a file in the standard library. So language_server_ids is used to look up which server is active
91// for a given worktree and language server name
92//
93// When starting a language server, first the id map is checked to make sure a server isn't already available
94// for that worktree. If there is one, it finishes early. Otherwise, a new id is allocated and and
95// the Starting variant of LanguageServerState is stored in the language_servers map.
96pub struct Project {
97 worktrees: Vec<WorktreeHandle>,
98 active_entry: Option<ProjectEntryId>,
99 languages: Arc<LanguageRegistry>,
100 language_servers: HashMap<usize, LanguageServerState>,
101 language_server_ids: HashMap<(WorktreeId, LanguageServerName), usize>,
102 language_server_statuses: BTreeMap<usize, LanguageServerStatus>,
103 language_server_settings: Arc<Mutex<serde_json::Value>>,
104 last_workspace_edits_by_language_server: HashMap<usize, ProjectTransaction>,
105 next_language_server_id: usize,
106 client: Arc<client::Client>,
107 next_entry_id: Arc<AtomicUsize>,
108 next_diagnostic_group_id: usize,
109 user_store: ModelHandle<UserStore>,
110 project_store: ModelHandle<ProjectStore>,
111 fs: Arc<dyn Fs>,
112 client_state: ProjectClientState,
113 collaborators: HashMap<PeerId, Collaborator>,
114 client_subscriptions: Vec<client::Subscription>,
115 _subscriptions: Vec<gpui::Subscription>,
116 opened_buffer: (Rc<RefCell<watch::Sender<()>>>, watch::Receiver<()>),
117 shared_buffers: HashMap<PeerId, HashSet<u64>>,
118 loading_buffers: HashMap<
119 ProjectPath,
120 postage::watch::Receiver<Option<Result<ModelHandle<Buffer>, Arc<anyhow::Error>>>>,
121 >,
122 loading_local_worktrees:
123 HashMap<Arc<Path>, Shared<Task<Result<ModelHandle<Worktree>, Arc<anyhow::Error>>>>>,
124 opened_buffers: HashMap<u64, OpenBuffer>,
125 buffer_snapshots: HashMap<u64, Vec<(i32, TextBufferSnapshot)>>,
126 nonce: u128,
127 initialized_persistent_state: bool,
128}
129
130#[derive(Error, Debug)]
131pub enum JoinProjectError {
132 #[error("host declined join request")]
133 HostDeclined,
134 #[error("host closed the project")]
135 HostClosedProject,
136 #[error("host went offline")]
137 HostWentOffline,
138 #[error("{0}")]
139 Other(#[from] anyhow::Error),
140}
141
142enum OpenBuffer {
143 Strong(ModelHandle<Buffer>),
144 Weak(WeakModelHandle<Buffer>),
145 Loading(Vec<Operation>),
146}
147
148enum WorktreeHandle {
149 Strong(ModelHandle<Worktree>),
150 Weak(WeakModelHandle<Worktree>),
151}
152
153enum ProjectClientState {
154 Local {
155 is_shared: bool,
156 remote_id_tx: watch::Sender<Option<u64>>,
157 remote_id_rx: watch::Receiver<Option<u64>>,
158 online_tx: watch::Sender<bool>,
159 online_rx: watch::Receiver<bool>,
160 _maintain_remote_id: Task<Option<()>>,
161 _maintain_online_status: Task<Option<()>>,
162 },
163 Remote {
164 sharing_has_stopped: bool,
165 remote_id: u64,
166 replica_id: ReplicaId,
167 _detect_unshare: Task<Option<()>>,
168 },
169}
170
171#[derive(Clone, Debug)]
172pub struct Collaborator {
173 pub user: Arc<User>,
174 pub peer_id: PeerId,
175 pub replica_id: ReplicaId,
176}
177
178#[derive(Clone, Debug, PartialEq, Eq)]
179pub enum Event {
180 ActiveEntryChanged(Option<ProjectEntryId>),
181 WorktreeAdded,
182 WorktreeRemoved(WorktreeId),
183 DiskBasedDiagnosticsStarted {
184 language_server_id: usize,
185 },
186 DiskBasedDiagnosticsFinished {
187 language_server_id: usize,
188 },
189 DiagnosticsUpdated {
190 path: ProjectPath,
191 language_server_id: usize,
192 },
193 RemoteIdChanged(Option<u64>),
194 CollaboratorLeft(PeerId),
195 ContactRequestedJoin(Arc<User>),
196 ContactCancelledJoinRequest(Arc<User>),
197}
198
199pub enum LanguageServerState {
200 Starting(Task<Option<Arc<LanguageServer>>>),
201 Running {
202 adapter: Arc<LspAdapter>,
203 server: Arc<LanguageServer>,
204 },
205}
206
207#[derive(Serialize)]
208pub struct LanguageServerStatus {
209 pub name: String,
210 pub pending_work: BTreeMap<String, LanguageServerProgress>,
211 pub has_pending_diagnostic_updates: bool,
212 progress_tokens: HashSet<String>,
213}
214
215#[derive(Clone, Debug, Serialize)]
216pub struct LanguageServerProgress {
217 pub message: Option<String>,
218 pub percentage: Option<usize>,
219 #[serde(skip_serializing)]
220 pub last_update_at: Instant,
221}
222
223#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
224pub struct ProjectPath {
225 pub worktree_id: WorktreeId,
226 pub path: Arc<Path>,
227}
228
229#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
230pub struct DiagnosticSummary {
231 pub language_server_id: usize,
232 pub error_count: usize,
233 pub warning_count: usize,
234}
235
236#[derive(Debug, Clone)]
237pub struct Location {
238 pub buffer: ModelHandle<Buffer>,
239 pub range: Range<language::Anchor>,
240}
241
242#[derive(Debug, Clone)]
243pub struct LocationLink {
244 pub origin: Option<Location>,
245 pub target: Location,
246}
247
248#[derive(Debug)]
249pub struct DocumentHighlight {
250 pub range: Range<language::Anchor>,
251 pub kind: DocumentHighlightKind,
252}
253
254#[derive(Clone, Debug)]
255pub struct Symbol {
256 pub source_worktree_id: WorktreeId,
257 pub worktree_id: WorktreeId,
258 pub language_server_name: LanguageServerName,
259 pub path: PathBuf,
260 pub label: CodeLabel,
261 pub name: String,
262 pub kind: lsp::SymbolKind,
263 pub range: Range<PointUtf16>,
264 pub signature: [u8; 32],
265}
266
267#[derive(Clone, Debug, PartialEq)]
268pub struct HoverBlock {
269 pub text: String,
270 pub language: Option<String>,
271}
272
273impl HoverBlock {
274 fn try_new(marked_string: MarkedString) -> Option<Self> {
275 let result = match marked_string {
276 MarkedString::LanguageString(LanguageString { language, value }) => HoverBlock {
277 text: value,
278 language: Some(language),
279 },
280 MarkedString::String(text) => HoverBlock {
281 text,
282 language: None,
283 },
284 };
285 if result.text.is_empty() {
286 None
287 } else {
288 Some(result)
289 }
290 }
291}
292
293#[derive(Debug)]
294pub struct Hover {
295 pub contents: Vec<HoverBlock>,
296 pub range: Option<Range<language::Anchor>>,
297}
298
299#[derive(Default)]
300pub struct ProjectTransaction(pub HashMap<ModelHandle<Buffer>, language::Transaction>);
301
302impl DiagnosticSummary {
303 fn new<'a, T: 'a>(
304 language_server_id: usize,
305 diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>,
306 ) -> Self {
307 let mut this = Self {
308 language_server_id,
309 error_count: 0,
310 warning_count: 0,
311 };
312
313 for entry in diagnostics {
314 if entry.diagnostic.is_primary {
315 match entry.diagnostic.severity {
316 DiagnosticSeverity::ERROR => this.error_count += 1,
317 DiagnosticSeverity::WARNING => this.warning_count += 1,
318 _ => {}
319 }
320 }
321 }
322
323 this
324 }
325
326 pub fn is_empty(&self) -> bool {
327 self.error_count == 0 && self.warning_count == 0
328 }
329
330 pub fn to_proto(&self, path: &Path) -> proto::DiagnosticSummary {
331 proto::DiagnosticSummary {
332 path: path.to_string_lossy().to_string(),
333 language_server_id: self.language_server_id as u64,
334 error_count: self.error_count as u32,
335 warning_count: self.warning_count as u32,
336 }
337 }
338}
339
340#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
341pub struct ProjectEntryId(usize);
342
343impl ProjectEntryId {
344 pub const MAX: Self = Self(usize::MAX);
345
346 pub fn new(counter: &AtomicUsize) -> Self {
347 Self(counter.fetch_add(1, SeqCst))
348 }
349
350 pub fn from_proto(id: u64) -> Self {
351 Self(id as usize)
352 }
353
354 pub fn to_proto(&self) -> u64 {
355 self.0 as u64
356 }
357
358 pub fn to_usize(&self) -> usize {
359 self.0
360 }
361}
362
363impl Project {
364 pub fn init(client: &Arc<Client>) {
365 client.add_model_message_handler(Self::handle_request_join_project);
366 client.add_model_message_handler(Self::handle_add_collaborator);
367 client.add_model_message_handler(Self::handle_buffer_reloaded);
368 client.add_model_message_handler(Self::handle_buffer_saved);
369 client.add_model_message_handler(Self::handle_start_language_server);
370 client.add_model_message_handler(Self::handle_update_language_server);
371 client.add_model_message_handler(Self::handle_remove_collaborator);
372 client.add_model_message_handler(Self::handle_join_project_request_cancelled);
373 client.add_model_message_handler(Self::handle_update_project);
374 client.add_model_message_handler(Self::handle_unregister_project);
375 client.add_model_message_handler(Self::handle_project_unshared);
376 client.add_model_message_handler(Self::handle_update_buffer_file);
377 client.add_model_message_handler(Self::handle_update_buffer);
378 client.add_model_message_handler(Self::handle_update_diagnostic_summary);
379 client.add_model_message_handler(Self::handle_update_worktree);
380 client.add_model_request_handler(Self::handle_create_project_entry);
381 client.add_model_request_handler(Self::handle_rename_project_entry);
382 client.add_model_request_handler(Self::handle_copy_project_entry);
383 client.add_model_request_handler(Self::handle_delete_project_entry);
384 client.add_model_request_handler(Self::handle_apply_additional_edits_for_completion);
385 client.add_model_request_handler(Self::handle_apply_code_action);
386 client.add_model_request_handler(Self::handle_reload_buffers);
387 client.add_model_request_handler(Self::handle_format_buffers);
388 client.add_model_request_handler(Self::handle_get_code_actions);
389 client.add_model_request_handler(Self::handle_get_completions);
390 client.add_model_request_handler(Self::handle_lsp_command::<GetHover>);
391 client.add_model_request_handler(Self::handle_lsp_command::<GetDefinition>);
392 client.add_model_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
393 client.add_model_request_handler(Self::handle_lsp_command::<GetReferences>);
394 client.add_model_request_handler(Self::handle_lsp_command::<PrepareRename>);
395 client.add_model_request_handler(Self::handle_lsp_command::<PerformRename>);
396 client.add_model_request_handler(Self::handle_search_project);
397 client.add_model_request_handler(Self::handle_get_project_symbols);
398 client.add_model_request_handler(Self::handle_open_buffer_for_symbol);
399 client.add_model_request_handler(Self::handle_open_buffer_by_id);
400 client.add_model_request_handler(Self::handle_open_buffer_by_path);
401 client.add_model_request_handler(Self::handle_save_buffer);
402 }
403
404 pub fn local(
405 online: bool,
406 client: Arc<Client>,
407 user_store: ModelHandle<UserStore>,
408 project_store: ModelHandle<ProjectStore>,
409 languages: Arc<LanguageRegistry>,
410 fs: Arc<dyn Fs>,
411 cx: &mut MutableAppContext,
412 ) -> ModelHandle<Self> {
413 cx.add_model(|cx: &mut ModelContext<Self>| {
414 let (remote_id_tx, remote_id_rx) = watch::channel();
415 let _maintain_remote_id = cx.spawn_weak({
416 let mut status_rx = client.clone().status();
417 move |this, mut cx| async move {
418 while let Some(status) = status_rx.recv().await {
419 let this = this.upgrade(&cx)?;
420 if status.is_connected() {
421 this.update(&mut cx, |this, cx| this.register(cx))
422 .await
423 .log_err()?;
424 } else {
425 this.update(&mut cx, |this, cx| this.unregister(cx))
426 .await
427 .log_err();
428 }
429 }
430 None
431 }
432 });
433
434 let (online_tx, online_rx) = watch::channel_with(online);
435 let _maintain_online_status = cx.spawn_weak({
436 let mut online_rx = online_rx.clone();
437 move |this, mut cx| async move {
438 while let Some(online) = online_rx.recv().await {
439 let this = this.upgrade(&cx)?;
440 this.update(&mut cx, |this, cx| {
441 if !online {
442 this.unshared(cx);
443 }
444 this.metadata_changed(false, cx)
445 });
446 }
447 None
448 }
449 });
450
451 let handle = cx.weak_handle();
452 project_store.update(cx, |store, cx| store.add_project(handle, cx));
453
454 let (opened_buffer_tx, opened_buffer_rx) = watch::channel();
455 Self {
456 worktrees: Default::default(),
457 collaborators: Default::default(),
458 opened_buffers: Default::default(),
459 shared_buffers: Default::default(),
460 loading_buffers: Default::default(),
461 loading_local_worktrees: Default::default(),
462 buffer_snapshots: Default::default(),
463 client_state: ProjectClientState::Local {
464 is_shared: false,
465 remote_id_tx,
466 remote_id_rx,
467 online_tx,
468 online_rx,
469 _maintain_remote_id,
470 _maintain_online_status,
471 },
472 opened_buffer: (Rc::new(RefCell::new(opened_buffer_tx)), opened_buffer_rx),
473 client_subscriptions: Vec::new(),
474 _subscriptions: vec![cx.observe_global::<Settings, _>(Self::on_settings_changed)],
475 active_entry: None,
476 languages,
477 client,
478 user_store,
479 project_store,
480 fs,
481 next_entry_id: Default::default(),
482 next_diagnostic_group_id: Default::default(),
483 language_servers: Default::default(),
484 language_server_ids: Default::default(),
485 language_server_statuses: Default::default(),
486 last_workspace_edits_by_language_server: Default::default(),
487 language_server_settings: Default::default(),
488 next_language_server_id: 0,
489 nonce: StdRng::from_entropy().gen(),
490 initialized_persistent_state: false,
491 }
492 })
493 }
494
495 pub async fn remote(
496 remote_id: u64,
497 client: Arc<Client>,
498 user_store: ModelHandle<UserStore>,
499 project_store: ModelHandle<ProjectStore>,
500 languages: Arc<LanguageRegistry>,
501 fs: Arc<dyn Fs>,
502 mut cx: AsyncAppContext,
503 ) -> Result<ModelHandle<Self>, JoinProjectError> {
504 client.authenticate_and_connect(true, &cx).await?;
505
506 let response = client
507 .request(proto::JoinProject {
508 project_id: remote_id,
509 })
510 .await?;
511
512 let response = match response.variant.ok_or_else(|| anyhow!("missing variant"))? {
513 proto::join_project_response::Variant::Accept(response) => response,
514 proto::join_project_response::Variant::Decline(decline) => {
515 match proto::join_project_response::decline::Reason::from_i32(decline.reason) {
516 Some(proto::join_project_response::decline::Reason::Declined) => {
517 Err(JoinProjectError::HostDeclined)?
518 }
519 Some(proto::join_project_response::decline::Reason::Closed) => {
520 Err(JoinProjectError::HostClosedProject)?
521 }
522 Some(proto::join_project_response::decline::Reason::WentOffline) => {
523 Err(JoinProjectError::HostWentOffline)?
524 }
525 None => Err(anyhow!("missing decline reason"))?,
526 }
527 }
528 };
529
530 let replica_id = response.replica_id as ReplicaId;
531
532 let mut worktrees = Vec::new();
533 for worktree in response.worktrees {
534 let worktree = cx
535 .update(|cx| Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx));
536 worktrees.push(worktree);
537 }
538
539 let (opened_buffer_tx, opened_buffer_rx) = watch::channel();
540 let this = cx.add_model(|cx: &mut ModelContext<Self>| {
541 let handle = cx.weak_handle();
542 project_store.update(cx, |store, cx| store.add_project(handle, cx));
543
544 let mut this = Self {
545 worktrees: Vec::new(),
546 loading_buffers: Default::default(),
547 opened_buffer: (Rc::new(RefCell::new(opened_buffer_tx)), opened_buffer_rx),
548 shared_buffers: Default::default(),
549 loading_local_worktrees: Default::default(),
550 active_entry: None,
551 collaborators: Default::default(),
552 languages,
553 user_store: user_store.clone(),
554 project_store,
555 fs,
556 next_entry_id: Default::default(),
557 next_diagnostic_group_id: Default::default(),
558 client_subscriptions: vec![client.add_model_for_remote_entity(remote_id, cx)],
559 _subscriptions: Default::default(),
560 client: client.clone(),
561 client_state: ProjectClientState::Remote {
562 sharing_has_stopped: false,
563 remote_id,
564 replica_id,
565 _detect_unshare: cx.spawn_weak(move |this, mut cx| {
566 async move {
567 let mut status = client.status();
568 let is_connected =
569 status.next().await.map_or(false, |s| s.is_connected());
570 // Even if we're initially connected, any future change of the status means we momentarily disconnected.
571 if !is_connected || status.next().await.is_some() {
572 if let Some(this) = this.upgrade(&cx) {
573 this.update(&mut cx, |this, cx| this.removed_from_project(cx))
574 }
575 }
576 Ok(())
577 }
578 .log_err()
579 }),
580 },
581 language_servers: Default::default(),
582 language_server_ids: Default::default(),
583 language_server_settings: Default::default(),
584 language_server_statuses: response
585 .language_servers
586 .into_iter()
587 .map(|server| {
588 (
589 server.id as usize,
590 LanguageServerStatus {
591 name: server.name,
592 pending_work: Default::default(),
593 has_pending_diagnostic_updates: false,
594 progress_tokens: Default::default(),
595 },
596 )
597 })
598 .collect(),
599 last_workspace_edits_by_language_server: Default::default(),
600 next_language_server_id: 0,
601 opened_buffers: Default::default(),
602 buffer_snapshots: Default::default(),
603 nonce: StdRng::from_entropy().gen(),
604 initialized_persistent_state: false,
605 };
606 for worktree in worktrees {
607 this.add_worktree(&worktree, cx);
608 }
609 this
610 });
611
612 let user_ids = response
613 .collaborators
614 .iter()
615 .map(|peer| peer.user_id)
616 .collect();
617 user_store
618 .update(&mut cx, |user_store, cx| user_store.get_users(user_ids, cx))
619 .await?;
620 let mut collaborators = HashMap::default();
621 for message in response.collaborators {
622 let collaborator = Collaborator::from_proto(message, &user_store, &mut cx).await?;
623 collaborators.insert(collaborator.peer_id, collaborator);
624 }
625
626 this.update(&mut cx, |this, _| {
627 this.collaborators = collaborators;
628 });
629
630 Ok(this)
631 }
632
633 #[cfg(any(test, feature = "test-support"))]
634 pub async fn test(
635 fs: Arc<dyn Fs>,
636 root_paths: impl IntoIterator<Item = &Path>,
637 cx: &mut gpui::TestAppContext,
638 ) -> ModelHandle<Project> {
639 if !cx.read(|cx| cx.has_global::<Settings>()) {
640 cx.update(|cx| cx.set_global(Settings::test(cx)));
641 }
642
643 let languages = Arc::new(LanguageRegistry::test());
644 let http_client = client::test::FakeHttpClient::with_404_response();
645 let client = client::Client::new(http_client.clone());
646 let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
647 let project_store = cx.add_model(|_| ProjectStore::new(Db::open_fake()));
648 let project = cx.update(|cx| {
649 Project::local(true, client, user_store, project_store, languages, fs, cx)
650 });
651 for path in root_paths {
652 let (tree, _) = project
653 .update(cx, |project, cx| {
654 project.find_or_create_local_worktree(path, true, cx)
655 })
656 .await
657 .unwrap();
658 tree.read_with(cx, |tree, _| tree.as_local().unwrap().scan_complete())
659 .await;
660 }
661 project
662 }
663
664 pub fn restore_state(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
665 if self.is_remote() {
666 return Task::ready(Ok(()));
667 }
668
669 let db = self.project_store.read(cx).db.clone();
670 let keys = self.db_keys_for_online_state(cx);
671 let online_by_default = cx.global::<Settings>().projects_online_by_default;
672 let read_online = cx.background().spawn(async move {
673 let values = db.read(keys)?;
674 anyhow::Ok(
675 values
676 .into_iter()
677 .all(|e| e.map_or(online_by_default, |e| e == [true as u8])),
678 )
679 });
680 cx.spawn(|this, mut cx| async move {
681 let online = read_online.await.log_err().unwrap_or(false);
682 this.update(&mut cx, |this, cx| {
683 this.initialized_persistent_state = true;
684 if let ProjectClientState::Local { online_tx, .. } = &mut this.client_state {
685 let mut online_tx = online_tx.borrow_mut();
686 if *online_tx != online {
687 *online_tx = online;
688 drop(online_tx);
689 this.metadata_changed(false, cx);
690 }
691 }
692 });
693 Ok(())
694 })
695 }
696
697 fn persist_state(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
698 if self.is_remote() || !self.initialized_persistent_state {
699 return Task::ready(Ok(()));
700 }
701
702 let db = self.project_store.read(cx).db.clone();
703 let keys = self.db_keys_for_online_state(cx);
704 let is_online = self.is_online();
705 cx.background().spawn(async move {
706 let value = &[is_online as u8];
707 db.write(keys.into_iter().map(|key| (key, value)))
708 })
709 }
710
711 fn on_settings_changed(&mut self, cx: &mut ModelContext<Self>) {
712 let settings = cx.global::<Settings>();
713
714 let mut language_servers_to_start = Vec::new();
715 for buffer in self.opened_buffers.values() {
716 if let Some(buffer) = buffer.upgrade(cx) {
717 let buffer = buffer.read(cx);
718 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language())
719 {
720 if settings.enable_language_server(Some(&language.name())) {
721 let worktree = file.worktree.read(cx);
722 language_servers_to_start.push((
723 worktree.id(),
724 worktree.as_local().unwrap().abs_path().clone(),
725 language.clone(),
726 ));
727 }
728 }
729 }
730 }
731
732 let mut language_servers_to_stop = Vec::new();
733 for language in self.languages.to_vec() {
734 if let Some(lsp_adapter) = language.lsp_adapter() {
735 if !settings.enable_language_server(Some(&language.name())) {
736 let lsp_name = &lsp_adapter.name;
737 for (worktree_id, started_lsp_name) in self.language_server_ids.keys() {
738 if lsp_name == started_lsp_name {
739 language_servers_to_stop.push((*worktree_id, started_lsp_name.clone()));
740 }
741 }
742 }
743 }
744 }
745
746 // Stop all newly-disabled language servers.
747 for (worktree_id, adapter_name) in language_servers_to_stop {
748 self.stop_language_server(worktree_id, adapter_name, cx)
749 .detach();
750 }
751
752 // Start all the newly-enabled language servers.
753 for (worktree_id, worktree_path, language) in language_servers_to_start {
754 self.start_language_server(worktree_id, worktree_path, language, cx);
755 }
756
757 cx.notify();
758 }
759
760 pub fn buffer_for_id(&self, remote_id: u64, cx: &AppContext) -> Option<ModelHandle<Buffer>> {
761 self.opened_buffers
762 .get(&remote_id)
763 .and_then(|buffer| buffer.upgrade(cx))
764 }
765
766 pub fn languages(&self) -> &Arc<LanguageRegistry> {
767 &self.languages
768 }
769
770 pub fn client(&self) -> Arc<Client> {
771 self.client.clone()
772 }
773
774 pub fn user_store(&self) -> ModelHandle<UserStore> {
775 self.user_store.clone()
776 }
777
778 pub fn project_store(&self) -> ModelHandle<ProjectStore> {
779 self.project_store.clone()
780 }
781
782 #[cfg(any(test, feature = "test-support"))]
783 pub fn check_invariants(&self, cx: &AppContext) {
784 if self.is_local() {
785 let mut worktree_root_paths = HashMap::default();
786 for worktree in self.worktrees(cx) {
787 let worktree = worktree.read(cx);
788 let abs_path = worktree.as_local().unwrap().abs_path().clone();
789 let prev_worktree_id = worktree_root_paths.insert(abs_path.clone(), worktree.id());
790 assert_eq!(
791 prev_worktree_id,
792 None,
793 "abs path {:?} for worktree {:?} is not unique ({:?} was already registered with the same path)",
794 abs_path,
795 worktree.id(),
796 prev_worktree_id
797 )
798 }
799 } else {
800 let replica_id = self.replica_id();
801 for buffer in self.opened_buffers.values() {
802 if let Some(buffer) = buffer.upgrade(cx) {
803 let buffer = buffer.read(cx);
804 assert_eq!(
805 buffer.deferred_ops_len(),
806 0,
807 "replica {}, buffer {} has deferred operations",
808 replica_id,
809 buffer.remote_id()
810 );
811 }
812 }
813 }
814 }
815
816 #[cfg(any(test, feature = "test-support"))]
817 pub fn has_open_buffer(&self, path: impl Into<ProjectPath>, cx: &AppContext) -> bool {
818 let path = path.into();
819 if let Some(worktree) = self.worktree_for_id(path.worktree_id, cx) {
820 self.opened_buffers.iter().any(|(_, buffer)| {
821 if let Some(buffer) = buffer.upgrade(cx) {
822 if let Some(file) = File::from_dyn(buffer.read(cx).file()) {
823 if file.worktree == worktree && file.path() == &path.path {
824 return true;
825 }
826 }
827 }
828 false
829 })
830 } else {
831 false
832 }
833 }
834
835 pub fn fs(&self) -> &Arc<dyn Fs> {
836 &self.fs
837 }
838
839 pub fn set_online(&mut self, online: bool, _: &mut ModelContext<Self>) {
840 if let ProjectClientState::Local { online_tx, .. } = &mut self.client_state {
841 let mut online_tx = online_tx.borrow_mut();
842 if *online_tx != online {
843 *online_tx = online;
844 }
845 }
846 }
847
848 pub fn is_online(&self) -> bool {
849 match &self.client_state {
850 ProjectClientState::Local { online_rx, .. } => *online_rx.borrow(),
851 ProjectClientState::Remote { .. } => true,
852 }
853 }
854
855 fn unregister(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
856 self.unshared(cx);
857 if let ProjectClientState::Local { remote_id_rx, .. } = &mut self.client_state {
858 if let Some(remote_id) = *remote_id_rx.borrow() {
859 let request = self.client.request(proto::UnregisterProject {
860 project_id: remote_id,
861 });
862 return cx.spawn(|this, mut cx| async move {
863 let response = request.await;
864
865 // Unregistering the project causes the server to send out a
866 // contact update removing this project from the host's list
867 // of online projects. Wait until this contact update has been
868 // processed before clearing out this project's remote id, so
869 // that there is no moment where this project appears in the
870 // contact metadata and *also* has no remote id.
871 this.update(&mut cx, |this, cx| {
872 this.user_store()
873 .update(cx, |store, _| store.contact_updates_done())
874 })
875 .await;
876
877 this.update(&mut cx, |this, cx| {
878 if let ProjectClientState::Local { remote_id_tx, .. } =
879 &mut this.client_state
880 {
881 *remote_id_tx.borrow_mut() = None;
882 }
883 this.client_subscriptions.clear();
884 this.metadata_changed(false, cx);
885 });
886 response.map(drop)
887 });
888 }
889 }
890 Task::ready(Ok(()))
891 }
892
893 fn register(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
894 if let ProjectClientState::Local {
895 remote_id_rx,
896 online_rx,
897 ..
898 } = &self.client_state
899 {
900 if remote_id_rx.borrow().is_some() {
901 return Task::ready(Ok(()));
902 }
903
904 let response = self.client.request(proto::RegisterProject {
905 online: *online_rx.borrow(),
906 });
907 cx.spawn(|this, mut cx| async move {
908 let remote_id = response.await?.project_id;
909 this.update(&mut cx, |this, cx| {
910 if let ProjectClientState::Local { remote_id_tx, .. } = &mut this.client_state {
911 *remote_id_tx.borrow_mut() = Some(remote_id);
912 }
913
914 this.metadata_changed(false, cx);
915 cx.emit(Event::RemoteIdChanged(Some(remote_id)));
916 this.client_subscriptions
917 .push(this.client.add_model_for_remote_entity(remote_id, cx));
918 Ok(())
919 })
920 })
921 } else {
922 Task::ready(Err(anyhow!("can't register a remote project")))
923 }
924 }
925
926 pub fn remote_id(&self) -> Option<u64> {
927 match &self.client_state {
928 ProjectClientState::Local { remote_id_rx, .. } => *remote_id_rx.borrow(),
929 ProjectClientState::Remote { remote_id, .. } => Some(*remote_id),
930 }
931 }
932
933 pub fn next_remote_id(&self) -> impl Future<Output = u64> {
934 let mut id = None;
935 let mut watch = None;
936 match &self.client_state {
937 ProjectClientState::Local { remote_id_rx, .. } => watch = Some(remote_id_rx.clone()),
938 ProjectClientState::Remote { remote_id, .. } => id = Some(*remote_id),
939 }
940
941 async move {
942 if let Some(id) = id {
943 return id;
944 }
945 let mut watch = watch.unwrap();
946 loop {
947 let id = *watch.borrow();
948 if let Some(id) = id {
949 return id;
950 }
951 watch.next().await;
952 }
953 }
954 }
955
956 pub fn shared_remote_id(&self) -> Option<u64> {
957 match &self.client_state {
958 ProjectClientState::Local {
959 remote_id_rx,
960 is_shared,
961 ..
962 } => {
963 if *is_shared {
964 *remote_id_rx.borrow()
965 } else {
966 None
967 }
968 }
969 ProjectClientState::Remote { remote_id, .. } => Some(*remote_id),
970 }
971 }
972
973 pub fn replica_id(&self) -> ReplicaId {
974 match &self.client_state {
975 ProjectClientState::Local { .. } => 0,
976 ProjectClientState::Remote { replica_id, .. } => *replica_id,
977 }
978 }
979
980 fn metadata_changed(&mut self, persist: bool, cx: &mut ModelContext<Self>) {
981 if let ProjectClientState::Local {
982 remote_id_rx,
983 online_rx,
984 ..
985 } = &self.client_state
986 {
987 // Broadcast worktrees only if the project is online.
988 let worktrees = if *online_rx.borrow() {
989 self.worktrees
990 .iter()
991 .filter_map(|worktree| {
992 worktree
993 .upgrade(&cx)
994 .map(|worktree| worktree.read(cx).as_local().unwrap().metadata_proto())
995 })
996 .collect()
997 } else {
998 Default::default()
999 };
1000 if let Some(project_id) = *remote_id_rx.borrow() {
1001 let online = *online_rx.borrow();
1002 self.client
1003 .send(proto::UpdateProject {
1004 project_id,
1005 worktrees,
1006 online,
1007 })
1008 .log_err();
1009
1010 if online {
1011 let worktrees = self.visible_worktrees(cx).collect::<Vec<_>>();
1012 let scans_complete =
1013 futures::future::join_all(worktrees.iter().filter_map(|worktree| {
1014 Some(worktree.read(cx).as_local()?.scan_complete())
1015 }));
1016
1017 let worktrees = worktrees.into_iter().map(|handle| handle.downgrade());
1018 cx.spawn_weak(move |_, cx| async move {
1019 scans_complete.await;
1020 cx.read(|cx| {
1021 for worktree in worktrees {
1022 if let Some(worktree) = worktree
1023 .upgrade(cx)
1024 .and_then(|worktree| worktree.read(cx).as_local())
1025 {
1026 worktree.send_extension_counts(project_id);
1027 }
1028 }
1029 })
1030 })
1031 .detach();
1032 }
1033 }
1034
1035 self.project_store.update(cx, |_, cx| cx.notify());
1036 if persist {
1037 self.persist_state(cx).detach_and_log_err(cx);
1038 }
1039 cx.notify();
1040 }
1041 }
1042
1043 pub fn collaborators(&self) -> &HashMap<PeerId, Collaborator> {
1044 &self.collaborators
1045 }
1046
1047 pub fn worktrees<'a>(
1048 &'a self,
1049 cx: &'a AppContext,
1050 ) -> impl 'a + DoubleEndedIterator<Item = ModelHandle<Worktree>> {
1051 self.worktrees
1052 .iter()
1053 .filter_map(move |worktree| worktree.upgrade(cx))
1054 }
1055
1056 pub fn visible_worktrees<'a>(
1057 &'a self,
1058 cx: &'a AppContext,
1059 ) -> impl 'a + DoubleEndedIterator<Item = ModelHandle<Worktree>> {
1060 self.worktrees.iter().filter_map(|worktree| {
1061 worktree.upgrade(cx).and_then(|worktree| {
1062 if worktree.read(cx).is_visible() {
1063 Some(worktree)
1064 } else {
1065 None
1066 }
1067 })
1068 })
1069 }
1070
1071 pub fn worktree_root_names<'a>(&'a self, cx: &'a AppContext) -> impl Iterator<Item = &'a str> {
1072 self.visible_worktrees(cx)
1073 .map(|tree| tree.read(cx).root_name())
1074 }
1075
1076 fn db_keys_for_online_state(&self, cx: &AppContext) -> Vec<String> {
1077 self.worktrees
1078 .iter()
1079 .filter_map(|worktree| {
1080 let worktree = worktree.upgrade(&cx)?.read(cx);
1081 if worktree.is_visible() {
1082 Some(format!(
1083 "project-path-online:{}",
1084 worktree.as_local().unwrap().abs_path().to_string_lossy()
1085 ))
1086 } else {
1087 None
1088 }
1089 })
1090 .collect::<Vec<_>>()
1091 }
1092
1093 pub fn worktree_for_id(
1094 &self,
1095 id: WorktreeId,
1096 cx: &AppContext,
1097 ) -> Option<ModelHandle<Worktree>> {
1098 self.worktrees(cx)
1099 .find(|worktree| worktree.read(cx).id() == id)
1100 }
1101
1102 pub fn worktree_for_entry(
1103 &self,
1104 entry_id: ProjectEntryId,
1105 cx: &AppContext,
1106 ) -> Option<ModelHandle<Worktree>> {
1107 self.worktrees(cx)
1108 .find(|worktree| worktree.read(cx).contains_entry(entry_id))
1109 }
1110
1111 pub fn worktree_id_for_entry(
1112 &self,
1113 entry_id: ProjectEntryId,
1114 cx: &AppContext,
1115 ) -> Option<WorktreeId> {
1116 self.worktree_for_entry(entry_id, cx)
1117 .map(|worktree| worktree.read(cx).id())
1118 }
1119
1120 pub fn contains_paths(&self, paths: &[PathBuf], cx: &AppContext) -> bool {
1121 paths.iter().all(|path| self.contains_path(&path, cx))
1122 }
1123
1124 pub fn contains_path(&self, path: &Path, cx: &AppContext) -> bool {
1125 for worktree in self.worktrees(cx) {
1126 let worktree = worktree.read(cx).as_local();
1127 if worktree.map_or(false, |w| w.contains_abs_path(path)) {
1128 return true;
1129 }
1130 }
1131 false
1132 }
1133
1134 pub fn create_entry(
1135 &mut self,
1136 project_path: impl Into<ProjectPath>,
1137 is_directory: bool,
1138 cx: &mut ModelContext<Self>,
1139 ) -> Option<Task<Result<Entry>>> {
1140 let project_path = project_path.into();
1141 let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
1142 if self.is_local() {
1143 Some(worktree.update(cx, |worktree, cx| {
1144 worktree
1145 .as_local_mut()
1146 .unwrap()
1147 .create_entry(project_path.path, is_directory, cx)
1148 }))
1149 } else {
1150 let client = self.client.clone();
1151 let project_id = self.remote_id().unwrap();
1152 Some(cx.spawn_weak(|_, mut cx| async move {
1153 let response = client
1154 .request(proto::CreateProjectEntry {
1155 worktree_id: project_path.worktree_id.to_proto(),
1156 project_id,
1157 path: project_path.path.as_os_str().as_bytes().to_vec(),
1158 is_directory,
1159 })
1160 .await?;
1161 let entry = response
1162 .entry
1163 .ok_or_else(|| anyhow!("missing entry in response"))?;
1164 worktree
1165 .update(&mut cx, |worktree, cx| {
1166 worktree.as_remote_mut().unwrap().insert_entry(
1167 entry,
1168 response.worktree_scan_id as usize,
1169 cx,
1170 )
1171 })
1172 .await
1173 }))
1174 }
1175 }
1176
1177 pub fn copy_entry(
1178 &mut self,
1179 entry_id: ProjectEntryId,
1180 new_path: impl Into<Arc<Path>>,
1181 cx: &mut ModelContext<Self>,
1182 ) -> Option<Task<Result<Entry>>> {
1183 let worktree = self.worktree_for_entry(entry_id, cx)?;
1184 let new_path = new_path.into();
1185 if self.is_local() {
1186 worktree.update(cx, |worktree, cx| {
1187 worktree
1188 .as_local_mut()
1189 .unwrap()
1190 .copy_entry(entry_id, new_path, cx)
1191 })
1192 } else {
1193 let client = self.client.clone();
1194 let project_id = self.remote_id().unwrap();
1195
1196 Some(cx.spawn_weak(|_, mut cx| async move {
1197 let response = client
1198 .request(proto::CopyProjectEntry {
1199 project_id,
1200 entry_id: entry_id.to_proto(),
1201 new_path: new_path.as_os_str().as_bytes().to_vec(),
1202 })
1203 .await?;
1204 let entry = response
1205 .entry
1206 .ok_or_else(|| anyhow!("missing entry in response"))?;
1207 worktree
1208 .update(&mut cx, |worktree, cx| {
1209 worktree.as_remote_mut().unwrap().insert_entry(
1210 entry,
1211 response.worktree_scan_id as usize,
1212 cx,
1213 )
1214 })
1215 .await
1216 }))
1217 }
1218 }
1219
1220 pub fn rename_entry(
1221 &mut self,
1222 entry_id: ProjectEntryId,
1223 new_path: impl Into<Arc<Path>>,
1224 cx: &mut ModelContext<Self>,
1225 ) -> Option<Task<Result<Entry>>> {
1226 let worktree = self.worktree_for_entry(entry_id, cx)?;
1227 let new_path = new_path.into();
1228 if self.is_local() {
1229 worktree.update(cx, |worktree, cx| {
1230 worktree
1231 .as_local_mut()
1232 .unwrap()
1233 .rename_entry(entry_id, new_path, cx)
1234 })
1235 } else {
1236 let client = self.client.clone();
1237 let project_id = self.remote_id().unwrap();
1238
1239 Some(cx.spawn_weak(|_, mut cx| async move {
1240 let response = client
1241 .request(proto::RenameProjectEntry {
1242 project_id,
1243 entry_id: entry_id.to_proto(),
1244 new_path: new_path.as_os_str().as_bytes().to_vec(),
1245 })
1246 .await?;
1247 let entry = response
1248 .entry
1249 .ok_or_else(|| anyhow!("missing entry in response"))?;
1250 worktree
1251 .update(&mut cx, |worktree, cx| {
1252 worktree.as_remote_mut().unwrap().insert_entry(
1253 entry,
1254 response.worktree_scan_id as usize,
1255 cx,
1256 )
1257 })
1258 .await
1259 }))
1260 }
1261 }
1262
1263 pub fn delete_entry(
1264 &mut self,
1265 entry_id: ProjectEntryId,
1266 cx: &mut ModelContext<Self>,
1267 ) -> Option<Task<Result<()>>> {
1268 let worktree = self.worktree_for_entry(entry_id, cx)?;
1269 if self.is_local() {
1270 worktree.update(cx, |worktree, cx| {
1271 worktree.as_local_mut().unwrap().delete_entry(entry_id, cx)
1272 })
1273 } else {
1274 let client = self.client.clone();
1275 let project_id = self.remote_id().unwrap();
1276 Some(cx.spawn_weak(|_, mut cx| async move {
1277 let response = client
1278 .request(proto::DeleteProjectEntry {
1279 project_id,
1280 entry_id: entry_id.to_proto(),
1281 })
1282 .await?;
1283 worktree
1284 .update(&mut cx, move |worktree, cx| {
1285 worktree.as_remote_mut().unwrap().delete_entry(
1286 entry_id,
1287 response.worktree_scan_id as usize,
1288 cx,
1289 )
1290 })
1291 .await
1292 }))
1293 }
1294 }
1295
1296 fn share(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
1297 if !self.is_online() {
1298 return Task::ready(Err(anyhow!("can't share an offline project")));
1299 }
1300
1301 let project_id;
1302 if let ProjectClientState::Local {
1303 remote_id_rx,
1304 is_shared,
1305 ..
1306 } = &mut self.client_state
1307 {
1308 if *is_shared {
1309 return Task::ready(Ok(()));
1310 }
1311 *is_shared = true;
1312 if let Some(id) = *remote_id_rx.borrow() {
1313 project_id = id;
1314 } else {
1315 return Task::ready(Err(anyhow!("project hasn't been registered")));
1316 }
1317 } else {
1318 return Task::ready(Err(anyhow!("can't share a remote project")));
1319 };
1320
1321 for open_buffer in self.opened_buffers.values_mut() {
1322 match open_buffer {
1323 OpenBuffer::Strong(_) => {}
1324 OpenBuffer::Weak(buffer) => {
1325 if let Some(buffer) = buffer.upgrade(cx) {
1326 *open_buffer = OpenBuffer::Strong(buffer);
1327 }
1328 }
1329 OpenBuffer::Loading(_) => unreachable!(),
1330 }
1331 }
1332
1333 for worktree_handle in self.worktrees.iter_mut() {
1334 match worktree_handle {
1335 WorktreeHandle::Strong(_) => {}
1336 WorktreeHandle::Weak(worktree) => {
1337 if let Some(worktree) = worktree.upgrade(cx) {
1338 *worktree_handle = WorktreeHandle::Strong(worktree);
1339 }
1340 }
1341 }
1342 }
1343
1344 let mut tasks = Vec::new();
1345 for worktree in self.worktrees(cx).collect::<Vec<_>>() {
1346 worktree.update(cx, |worktree, cx| {
1347 let worktree = worktree.as_local_mut().unwrap();
1348 tasks.push(worktree.share(project_id, cx));
1349 });
1350 }
1351
1352 for (server_id, status) in &self.language_server_statuses {
1353 self.client
1354 .send(proto::StartLanguageServer {
1355 project_id,
1356 server: Some(proto::LanguageServer {
1357 id: *server_id as u64,
1358 name: status.name.clone(),
1359 }),
1360 })
1361 .log_err();
1362 }
1363
1364 cx.spawn(|this, mut cx| async move {
1365 for task in tasks {
1366 task.await?;
1367 }
1368 this.update(&mut cx, |_, cx| cx.notify());
1369 Ok(())
1370 })
1371 }
1372
1373 fn unshared(&mut self, cx: &mut ModelContext<Self>) {
1374 if let ProjectClientState::Local { is_shared, .. } = &mut self.client_state {
1375 if !*is_shared {
1376 return;
1377 }
1378
1379 *is_shared = false;
1380 self.collaborators.clear();
1381 self.shared_buffers.clear();
1382 for worktree_handle in self.worktrees.iter_mut() {
1383 if let WorktreeHandle::Strong(worktree) = worktree_handle {
1384 let is_visible = worktree.update(cx, |worktree, _| {
1385 worktree.as_local_mut().unwrap().unshare();
1386 worktree.is_visible()
1387 });
1388 if !is_visible {
1389 *worktree_handle = WorktreeHandle::Weak(worktree.downgrade());
1390 }
1391 }
1392 }
1393
1394 for open_buffer in self.opened_buffers.values_mut() {
1395 match open_buffer {
1396 OpenBuffer::Strong(buffer) => {
1397 *open_buffer = OpenBuffer::Weak(buffer.downgrade());
1398 }
1399 _ => {}
1400 }
1401 }
1402
1403 cx.notify();
1404 } else {
1405 log::error!("attempted to unshare a remote project");
1406 }
1407 }
1408
1409 pub fn respond_to_join_request(
1410 &mut self,
1411 requester_id: u64,
1412 allow: bool,
1413 cx: &mut ModelContext<Self>,
1414 ) {
1415 if let Some(project_id) = self.remote_id() {
1416 let share = if self.is_online() && allow {
1417 Some(self.share(cx))
1418 } else {
1419 None
1420 };
1421 let client = self.client.clone();
1422 cx.foreground()
1423 .spawn(async move {
1424 client.send(proto::RespondToJoinProjectRequest {
1425 requester_id,
1426 project_id,
1427 allow,
1428 })?;
1429 if let Some(share) = share {
1430 share.await?;
1431 }
1432 anyhow::Ok(())
1433 })
1434 .detach_and_log_err(cx);
1435 }
1436 }
1437
1438 fn removed_from_project(&mut self, cx: &mut ModelContext<Self>) {
1439 if let ProjectClientState::Remote {
1440 sharing_has_stopped,
1441 ..
1442 } = &mut self.client_state
1443 {
1444 *sharing_has_stopped = true;
1445 self.collaborators.clear();
1446 for worktree in &self.worktrees {
1447 if let Some(worktree) = worktree.upgrade(cx) {
1448 worktree.update(cx, |worktree, _| {
1449 if let Some(worktree) = worktree.as_remote_mut() {
1450 worktree.disconnected_from_host();
1451 }
1452 });
1453 }
1454 }
1455 cx.notify();
1456 }
1457 }
1458
1459 pub fn is_read_only(&self) -> bool {
1460 match &self.client_state {
1461 ProjectClientState::Local { .. } => false,
1462 ProjectClientState::Remote {
1463 sharing_has_stopped,
1464 ..
1465 } => *sharing_has_stopped,
1466 }
1467 }
1468
1469 pub fn is_local(&self) -> bool {
1470 match &self.client_state {
1471 ProjectClientState::Local { .. } => true,
1472 ProjectClientState::Remote { .. } => false,
1473 }
1474 }
1475
1476 pub fn is_remote(&self) -> bool {
1477 !self.is_local()
1478 }
1479
1480 pub fn create_buffer(
1481 &mut self,
1482 text: &str,
1483 language: Option<Arc<Language>>,
1484 cx: &mut ModelContext<Self>,
1485 ) -> Result<ModelHandle<Buffer>> {
1486 if self.is_remote() {
1487 return Err(anyhow!("creating buffers as a guest is not supported yet"));
1488 }
1489
1490 let buffer = cx.add_model(|cx| {
1491 Buffer::new(self.replica_id(), text, cx)
1492 .with_language(language.unwrap_or(language::PLAIN_TEXT.clone()), cx)
1493 });
1494 self.register_buffer(&buffer, cx)?;
1495 Ok(buffer)
1496 }
1497
1498 pub fn open_path(
1499 &mut self,
1500 path: impl Into<ProjectPath>,
1501 cx: &mut ModelContext<Self>,
1502 ) -> Task<Result<(ProjectEntryId, AnyModelHandle)>> {
1503 let task = self.open_buffer(path, cx);
1504 cx.spawn_weak(|_, cx| async move {
1505 let buffer = task.await?;
1506 let project_entry_id = buffer
1507 .read_with(&cx, |buffer, cx| {
1508 File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx))
1509 })
1510 .ok_or_else(|| anyhow!("no project entry"))?;
1511 Ok((project_entry_id, buffer.into()))
1512 })
1513 }
1514
1515 pub fn open_local_buffer(
1516 &mut self,
1517 abs_path: impl AsRef<Path>,
1518 cx: &mut ModelContext<Self>,
1519 ) -> Task<Result<ModelHandle<Buffer>>> {
1520 if let Some((worktree, relative_path)) = self.find_local_worktree(abs_path.as_ref(), cx) {
1521 self.open_buffer((worktree.read(cx).id(), relative_path), cx)
1522 } else {
1523 Task::ready(Err(anyhow!("no such path")))
1524 }
1525 }
1526
1527 pub fn open_buffer(
1528 &mut self,
1529 path: impl Into<ProjectPath>,
1530 cx: &mut ModelContext<Self>,
1531 ) -> Task<Result<ModelHandle<Buffer>>> {
1532 let project_path = path.into();
1533 let worktree = if let Some(worktree) = self.worktree_for_id(project_path.worktree_id, cx) {
1534 worktree
1535 } else {
1536 return Task::ready(Err(anyhow!("no such worktree")));
1537 };
1538
1539 // If there is already a buffer for the given path, then return it.
1540 let existing_buffer = self.get_open_buffer(&project_path, cx);
1541 if let Some(existing_buffer) = existing_buffer {
1542 return Task::ready(Ok(existing_buffer));
1543 }
1544
1545 let mut loading_watch = match self.loading_buffers.entry(project_path.clone()) {
1546 // If the given path is already being loaded, then wait for that existing
1547 // task to complete and return the same buffer.
1548 hash_map::Entry::Occupied(e) => e.get().clone(),
1549
1550 // Otherwise, record the fact that this path is now being loaded.
1551 hash_map::Entry::Vacant(entry) => {
1552 let (mut tx, rx) = postage::watch::channel();
1553 entry.insert(rx.clone());
1554
1555 let load_buffer = if worktree.read(cx).is_local() {
1556 self.open_local_buffer_internal(&project_path.path, &worktree, cx)
1557 } else {
1558 self.open_remote_buffer_internal(&project_path.path, &worktree, cx)
1559 };
1560
1561 cx.spawn(move |this, mut cx| async move {
1562 let load_result = load_buffer.await;
1563 *tx.borrow_mut() = Some(this.update(&mut cx, |this, _| {
1564 // Record the fact that the buffer is no longer loading.
1565 this.loading_buffers.remove(&project_path);
1566 let buffer = load_result.map_err(Arc::new)?;
1567 Ok(buffer)
1568 }));
1569 })
1570 .detach();
1571 rx
1572 }
1573 };
1574
1575 cx.foreground().spawn(async move {
1576 loop {
1577 if let Some(result) = loading_watch.borrow().as_ref() {
1578 match result {
1579 Ok(buffer) => return Ok(buffer.clone()),
1580 Err(error) => return Err(anyhow!("{}", error)),
1581 }
1582 }
1583 loading_watch.next().await;
1584 }
1585 })
1586 }
1587
1588 fn open_local_buffer_internal(
1589 &mut self,
1590 path: &Arc<Path>,
1591 worktree: &ModelHandle<Worktree>,
1592 cx: &mut ModelContext<Self>,
1593 ) -> Task<Result<ModelHandle<Buffer>>> {
1594 let load_buffer = worktree.update(cx, |worktree, cx| {
1595 let worktree = worktree.as_local_mut().unwrap();
1596 worktree.load_buffer(path, cx)
1597 });
1598 cx.spawn(|this, mut cx| async move {
1599 let buffer = load_buffer.await?;
1600 this.update(&mut cx, |this, cx| this.register_buffer(&buffer, cx))?;
1601 Ok(buffer)
1602 })
1603 }
1604
1605 fn open_remote_buffer_internal(
1606 &mut self,
1607 path: &Arc<Path>,
1608 worktree: &ModelHandle<Worktree>,
1609 cx: &mut ModelContext<Self>,
1610 ) -> Task<Result<ModelHandle<Buffer>>> {
1611 let rpc = self.client.clone();
1612 let project_id = self.remote_id().unwrap();
1613 let remote_worktree_id = worktree.read(cx).id();
1614 let path = path.clone();
1615 let path_string = path.to_string_lossy().to_string();
1616 cx.spawn(|this, mut cx| async move {
1617 let response = rpc
1618 .request(proto::OpenBufferByPath {
1619 project_id,
1620 worktree_id: remote_worktree_id.to_proto(),
1621 path: path_string,
1622 })
1623 .await?;
1624 let buffer = response.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
1625 this.update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
1626 .await
1627 })
1628 }
1629
1630 /// LanguageServerName is owned, because it is inserted into a map
1631 fn open_local_buffer_via_lsp(
1632 &mut self,
1633 abs_path: lsp::Url,
1634 language_server_id: usize,
1635 language_server_name: LanguageServerName,
1636 cx: &mut ModelContext<Self>,
1637 ) -> Task<Result<ModelHandle<Buffer>>> {
1638 cx.spawn(|this, mut cx| async move {
1639 let abs_path = abs_path
1640 .to_file_path()
1641 .map_err(|_| anyhow!("can't convert URI to path"))?;
1642 let (worktree, relative_path) = if let Some(result) =
1643 this.read_with(&cx, |this, cx| this.find_local_worktree(&abs_path, cx))
1644 {
1645 result
1646 } else {
1647 let worktree = this
1648 .update(&mut cx, |this, cx| {
1649 this.create_local_worktree(&abs_path, false, cx)
1650 })
1651 .await?;
1652 this.update(&mut cx, |this, cx| {
1653 this.language_server_ids.insert(
1654 (worktree.read(cx).id(), language_server_name),
1655 language_server_id,
1656 );
1657 });
1658 (worktree, PathBuf::new())
1659 };
1660
1661 let project_path = ProjectPath {
1662 worktree_id: worktree.read_with(&cx, |worktree, _| worktree.id()),
1663 path: relative_path.into(),
1664 };
1665 this.update(&mut cx, |this, cx| this.open_buffer(project_path, cx))
1666 .await
1667 })
1668 }
1669
1670 pub fn open_buffer_by_id(
1671 &mut self,
1672 id: u64,
1673 cx: &mut ModelContext<Self>,
1674 ) -> Task<Result<ModelHandle<Buffer>>> {
1675 if let Some(buffer) = self.buffer_for_id(id, cx) {
1676 Task::ready(Ok(buffer))
1677 } else if self.is_local() {
1678 Task::ready(Err(anyhow!("buffer {} does not exist", id)))
1679 } else if let Some(project_id) = self.remote_id() {
1680 let request = self
1681 .client
1682 .request(proto::OpenBufferById { project_id, id });
1683 cx.spawn(|this, mut cx| async move {
1684 let buffer = request
1685 .await?
1686 .buffer
1687 .ok_or_else(|| anyhow!("invalid buffer"))?;
1688 this.update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
1689 .await
1690 })
1691 } else {
1692 Task::ready(Err(anyhow!("cannot open buffer while disconnected")))
1693 }
1694 }
1695
1696 pub fn save_buffer_as(
1697 &mut self,
1698 buffer: ModelHandle<Buffer>,
1699 abs_path: PathBuf,
1700 cx: &mut ModelContext<Project>,
1701 ) -> Task<Result<()>> {
1702 let worktree_task = self.find_or_create_local_worktree(&abs_path, true, cx);
1703 let old_path =
1704 File::from_dyn(buffer.read(cx).file()).and_then(|f| Some(f.as_local()?.abs_path(cx)));
1705 cx.spawn(|this, mut cx| async move {
1706 if let Some(old_path) = old_path {
1707 this.update(&mut cx, |this, cx| {
1708 this.unregister_buffer_from_language_server(&buffer, old_path, cx);
1709 });
1710 }
1711 let (worktree, path) = worktree_task.await?;
1712 worktree
1713 .update(&mut cx, |worktree, cx| {
1714 worktree
1715 .as_local_mut()
1716 .unwrap()
1717 .save_buffer_as(buffer.clone(), path, cx)
1718 })
1719 .await?;
1720 this.update(&mut cx, |this, cx| {
1721 this.assign_language_to_buffer(&buffer, cx);
1722 this.register_buffer_with_language_server(&buffer, cx)
1723 });
1724 Ok(())
1725 })
1726 }
1727
1728 pub fn get_open_buffer(
1729 &mut self,
1730 path: &ProjectPath,
1731 cx: &mut ModelContext<Self>,
1732 ) -> Option<ModelHandle<Buffer>> {
1733 let worktree = self.worktree_for_id(path.worktree_id, cx)?;
1734 self.opened_buffers.values().find_map(|buffer| {
1735 let buffer = buffer.upgrade(cx)?;
1736 let file = File::from_dyn(buffer.read(cx).file())?;
1737 if file.worktree == worktree && file.path() == &path.path {
1738 Some(buffer)
1739 } else {
1740 None
1741 }
1742 })
1743 }
1744
1745 fn register_buffer(
1746 &mut self,
1747 buffer: &ModelHandle<Buffer>,
1748 cx: &mut ModelContext<Self>,
1749 ) -> Result<()> {
1750 let remote_id = buffer.read(cx).remote_id();
1751 let open_buffer = if self.is_remote() || self.is_shared() {
1752 OpenBuffer::Strong(buffer.clone())
1753 } else {
1754 OpenBuffer::Weak(buffer.downgrade())
1755 };
1756
1757 match self.opened_buffers.insert(remote_id, open_buffer) {
1758 None => {}
1759 Some(OpenBuffer::Loading(operations)) => {
1760 buffer.update(cx, |buffer, cx| buffer.apply_ops(operations, cx))?
1761 }
1762 Some(OpenBuffer::Weak(existing_handle)) => {
1763 if existing_handle.upgrade(cx).is_some() {
1764 Err(anyhow!(
1765 "already registered buffer with remote id {}",
1766 remote_id
1767 ))?
1768 }
1769 }
1770 Some(OpenBuffer::Strong(_)) => Err(anyhow!(
1771 "already registered buffer with remote id {}",
1772 remote_id
1773 ))?,
1774 }
1775 cx.subscribe(buffer, |this, buffer, event, cx| {
1776 this.on_buffer_event(buffer, event, cx);
1777 })
1778 .detach();
1779
1780 self.assign_language_to_buffer(buffer, cx);
1781 self.register_buffer_with_language_server(buffer, cx);
1782 cx.observe_release(buffer, |this, buffer, cx| {
1783 if let Some(file) = File::from_dyn(buffer.file()) {
1784 if file.is_local() {
1785 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
1786 if let Some((_, server)) = this.language_server_for_buffer(buffer, cx) {
1787 server
1788 .notify::<lsp::notification::DidCloseTextDocument>(
1789 lsp::DidCloseTextDocumentParams {
1790 text_document: lsp::TextDocumentIdentifier::new(uri.clone()),
1791 },
1792 )
1793 .log_err();
1794 }
1795 }
1796 }
1797 })
1798 .detach();
1799
1800 Ok(())
1801 }
1802
1803 fn register_buffer_with_language_server(
1804 &mut self,
1805 buffer_handle: &ModelHandle<Buffer>,
1806 cx: &mut ModelContext<'_, Self>,
1807 ) {
1808 let buffer = buffer_handle.read(cx);
1809 let buffer_id = buffer.remote_id();
1810 if let Some(file) = File::from_dyn(buffer.file()) {
1811 if file.is_local() {
1812 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
1813 let initial_snapshot = buffer.text_snapshot();
1814
1815 let mut language_server = None;
1816 let mut language_id = None;
1817 if let Some(language) = buffer.language() {
1818 let worktree_id = file.worktree_id(cx);
1819 if let Some(adapter) = language.lsp_adapter() {
1820 language_id = adapter.id_for_language.clone();
1821 language_server = self
1822 .language_server_ids
1823 .get(&(worktree_id, adapter.name.clone()))
1824 .and_then(|id| self.language_servers.get(&id))
1825 .and_then(|server_state| {
1826 if let LanguageServerState::Running { server, .. } = server_state {
1827 Some(server.clone())
1828 } else {
1829 None
1830 }
1831 });
1832 }
1833 }
1834
1835 if let Some(local_worktree) = file.worktree.read(cx).as_local() {
1836 if let Some(diagnostics) = local_worktree.diagnostics_for_path(file.path()) {
1837 self.update_buffer_diagnostics(&buffer_handle, diagnostics, None, cx)
1838 .log_err();
1839 }
1840 }
1841
1842 if let Some(server) = language_server {
1843 server
1844 .notify::<lsp::notification::DidOpenTextDocument>(
1845 lsp::DidOpenTextDocumentParams {
1846 text_document: lsp::TextDocumentItem::new(
1847 uri,
1848 language_id.unwrap_or_default(),
1849 0,
1850 initial_snapshot.text(),
1851 ),
1852 }
1853 .clone(),
1854 )
1855 .log_err();
1856 buffer_handle.update(cx, |buffer, cx| {
1857 buffer.set_completion_triggers(
1858 server
1859 .capabilities()
1860 .completion_provider
1861 .as_ref()
1862 .and_then(|provider| provider.trigger_characters.clone())
1863 .unwrap_or(Vec::new()),
1864 cx,
1865 )
1866 });
1867 self.buffer_snapshots
1868 .insert(buffer_id, vec![(0, initial_snapshot)]);
1869 }
1870 }
1871 }
1872 }
1873
1874 fn unregister_buffer_from_language_server(
1875 &mut self,
1876 buffer: &ModelHandle<Buffer>,
1877 old_path: PathBuf,
1878 cx: &mut ModelContext<Self>,
1879 ) {
1880 buffer.update(cx, |buffer, cx| {
1881 buffer.update_diagnostics(Default::default(), cx);
1882 self.buffer_snapshots.remove(&buffer.remote_id());
1883 if let Some((_, language_server)) = self.language_server_for_buffer(buffer, cx) {
1884 language_server
1885 .notify::<lsp::notification::DidCloseTextDocument>(
1886 lsp::DidCloseTextDocumentParams {
1887 text_document: lsp::TextDocumentIdentifier::new(
1888 lsp::Url::from_file_path(old_path).unwrap(),
1889 ),
1890 },
1891 )
1892 .log_err();
1893 }
1894 });
1895 }
1896
1897 fn on_buffer_event(
1898 &mut self,
1899 buffer: ModelHandle<Buffer>,
1900 event: &BufferEvent,
1901 cx: &mut ModelContext<'_, Self>,
1902 ) -> Option<()> {
1903 match event {
1904 BufferEvent::Operation(operation) => {
1905 if let Some(project_id) = self.shared_remote_id() {
1906 let request = self.client.request(proto::UpdateBuffer {
1907 project_id,
1908 buffer_id: buffer.read(cx).remote_id(),
1909 operations: vec![language::proto::serialize_operation(&operation)],
1910 });
1911 cx.background().spawn(request).detach_and_log_err(cx);
1912 } else if let Some(project_id) = self.remote_id() {
1913 let _ = self
1914 .client
1915 .send(proto::RegisterProjectActivity { project_id });
1916 }
1917 }
1918 BufferEvent::Edited { .. } => {
1919 let language_server = self
1920 .language_server_for_buffer(buffer.read(cx), cx)
1921 .map(|(_, server)| server.clone())?;
1922 let buffer = buffer.read(cx);
1923 let file = File::from_dyn(buffer.file())?;
1924 let abs_path = file.as_local()?.abs_path(cx);
1925 let uri = lsp::Url::from_file_path(abs_path).unwrap();
1926 let buffer_snapshots = self.buffer_snapshots.get_mut(&buffer.remote_id())?;
1927 let (version, prev_snapshot) = buffer_snapshots.last()?;
1928 let next_snapshot = buffer.text_snapshot();
1929 let next_version = version + 1;
1930
1931 let content_changes = buffer
1932 .edits_since::<(PointUtf16, usize)>(prev_snapshot.version())
1933 .map(|edit| {
1934 let edit_start = edit.new.start.0;
1935 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
1936 let new_text = next_snapshot
1937 .text_for_range(edit.new.start.1..edit.new.end.1)
1938 .collect();
1939 lsp::TextDocumentContentChangeEvent {
1940 range: Some(lsp::Range::new(
1941 point_to_lsp(edit_start),
1942 point_to_lsp(edit_end),
1943 )),
1944 range_length: None,
1945 text: new_text,
1946 }
1947 })
1948 .collect();
1949
1950 buffer_snapshots.push((next_version, next_snapshot));
1951
1952 language_server
1953 .notify::<lsp::notification::DidChangeTextDocument>(
1954 lsp::DidChangeTextDocumentParams {
1955 text_document: lsp::VersionedTextDocumentIdentifier::new(
1956 uri,
1957 next_version,
1958 ),
1959 content_changes,
1960 },
1961 )
1962 .log_err();
1963 }
1964 BufferEvent::Saved => {
1965 let file = File::from_dyn(buffer.read(cx).file())?;
1966 let worktree_id = file.worktree_id(cx);
1967 let abs_path = file.as_local()?.abs_path(cx);
1968 let text_document = lsp::TextDocumentIdentifier {
1969 uri: lsp::Url::from_file_path(abs_path).unwrap(),
1970 };
1971
1972 for (_, server) in self.language_servers_for_worktree(worktree_id) {
1973 server
1974 .notify::<lsp::notification::DidSaveTextDocument>(
1975 lsp::DidSaveTextDocumentParams {
1976 text_document: text_document.clone(),
1977 text: None,
1978 },
1979 )
1980 .log_err();
1981 }
1982
1983 // After saving a buffer, simulate disk-based diagnostics being finished for languages
1984 // that don't support a disk-based progress token.
1985 let (lsp_adapter, language_server) =
1986 self.language_server_for_buffer(buffer.read(cx), cx)?;
1987 if lsp_adapter.disk_based_diagnostics_progress_token.is_none() {
1988 let server_id = language_server.server_id();
1989 self.disk_based_diagnostics_finished(server_id, cx);
1990 self.broadcast_language_server_update(
1991 server_id,
1992 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
1993 proto::LspDiskBasedDiagnosticsUpdated {},
1994 ),
1995 );
1996 }
1997 }
1998 _ => {}
1999 }
2000
2001 None
2002 }
2003
2004 fn language_servers_for_worktree(
2005 &self,
2006 worktree_id: WorktreeId,
2007 ) -> impl Iterator<Item = (&Arc<LspAdapter>, &Arc<LanguageServer>)> {
2008 self.language_server_ids
2009 .iter()
2010 .filter_map(move |((language_server_worktree_id, _), id)| {
2011 if *language_server_worktree_id == worktree_id {
2012 if let Some(LanguageServerState::Running { adapter, server }) =
2013 self.language_servers.get(&id)
2014 {
2015 return Some((adapter, server));
2016 }
2017 }
2018 None
2019 })
2020 }
2021
2022 fn assign_language_to_buffer(
2023 &mut self,
2024 buffer: &ModelHandle<Buffer>,
2025 cx: &mut ModelContext<Self>,
2026 ) -> Option<()> {
2027 // If the buffer has a language, set it and start the language server if we haven't already.
2028 let full_path = buffer.read(cx).file()?.full_path(cx);
2029 let language = self.languages.select_language(&full_path)?;
2030 buffer.update(cx, |buffer, cx| {
2031 buffer.set_language(Some(language.clone()), cx);
2032 });
2033
2034 let file = File::from_dyn(buffer.read(cx).file())?;
2035 let worktree = file.worktree.read(cx).as_local()?;
2036 let worktree_id = worktree.id();
2037 let worktree_abs_path = worktree.abs_path().clone();
2038 self.start_language_server(worktree_id, worktree_abs_path, language, cx);
2039
2040 None
2041 }
2042
2043 fn start_language_server(
2044 &mut self,
2045 worktree_id: WorktreeId,
2046 worktree_path: Arc<Path>,
2047 language: Arc<Language>,
2048 cx: &mut ModelContext<Self>,
2049 ) {
2050 if !cx
2051 .global::<Settings>()
2052 .enable_language_server(Some(&language.name()))
2053 {
2054 return;
2055 }
2056
2057 let adapter = if let Some(adapter) = language.lsp_adapter() {
2058 adapter
2059 } else {
2060 return;
2061 };
2062 let key = (worktree_id, adapter.name.clone());
2063
2064 self.language_server_ids
2065 .entry(key.clone())
2066 .or_insert_with(|| {
2067 let server_id = post_inc(&mut self.next_language_server_id);
2068 let language_server = self.languages.start_language_server(
2069 server_id,
2070 language.clone(),
2071 worktree_path,
2072 self.client.http_client(),
2073 cx,
2074 );
2075 self.language_servers.insert(
2076 server_id,
2077 LanguageServerState::Starting(cx.spawn_weak(|this, mut cx| async move {
2078 let language_server = language_server?.await.log_err()?;
2079 let language_server = language_server
2080 .initialize(adapter.initialization_options.clone())
2081 .await
2082 .log_err()?;
2083 let this = this.upgrade(&cx)?;
2084
2085 language_server
2086 .on_notification::<lsp::notification::PublishDiagnostics, _>({
2087 let this = this.downgrade();
2088 let adapter = adapter.clone();
2089 move |params, mut cx| {
2090 if let Some(this) = this.upgrade(&cx) {
2091 this.update(&mut cx, |this, cx| {
2092 this.on_lsp_diagnostics_published(
2093 server_id, params, &adapter, cx,
2094 );
2095 });
2096 }
2097 }
2098 })
2099 .detach();
2100
2101 language_server
2102 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
2103 let settings = this.read_with(&cx, |this, _| {
2104 this.language_server_settings.clone()
2105 });
2106 move |params, _| {
2107 let settings = settings.lock().clone();
2108 async move {
2109 Ok(params
2110 .items
2111 .into_iter()
2112 .map(|item| {
2113 if let Some(section) = &item.section {
2114 settings
2115 .get(section)
2116 .cloned()
2117 .unwrap_or(serde_json::Value::Null)
2118 } else {
2119 settings.clone()
2120 }
2121 })
2122 .collect())
2123 }
2124 }
2125 })
2126 .detach();
2127
2128 // Even though we don't have handling for these requests, respond to them to
2129 // avoid stalling any language server like `gopls` which waits for a response
2130 // to these requests when initializing.
2131 language_server
2132 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
2133 let this = this.downgrade();
2134 move |params, mut cx| async move {
2135 if let Some(this) = this.upgrade(&cx) {
2136 this.update(&mut cx, |this, _| {
2137 if let Some(status) =
2138 this.language_server_statuses.get_mut(&server_id)
2139 {
2140 if let lsp::NumberOrString::String(token) =
2141 params.token
2142 {
2143 status.progress_tokens.insert(token);
2144 }
2145 }
2146 });
2147 }
2148 Ok(())
2149 }
2150 })
2151 .detach();
2152 language_server
2153 .on_request::<lsp::request::RegisterCapability, _, _>(|_, _| async {
2154 Ok(())
2155 })
2156 .detach();
2157
2158 language_server
2159 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
2160 let this = this.downgrade();
2161 let adapter = adapter.clone();
2162 let language_server = language_server.clone();
2163 move |params, cx| {
2164 Self::on_lsp_workspace_edit(
2165 this,
2166 params,
2167 server_id,
2168 adapter.clone(),
2169 language_server.clone(),
2170 cx,
2171 )
2172 }
2173 })
2174 .detach();
2175
2176 let disk_based_diagnostics_progress_token =
2177 adapter.disk_based_diagnostics_progress_token.clone();
2178
2179 language_server
2180 .on_notification::<lsp::notification::Progress, _>({
2181 let this = this.downgrade();
2182 move |params, mut cx| {
2183 if let Some(this) = this.upgrade(&cx) {
2184 this.update(&mut cx, |this, cx| {
2185 this.on_lsp_progress(
2186 params,
2187 server_id,
2188 disk_based_diagnostics_progress_token.clone(),
2189 cx,
2190 );
2191 });
2192 }
2193 }
2194 })
2195 .detach();
2196
2197 this.update(&mut cx, |this, cx| {
2198 // If the language server for this key doesn't match the server id, don't store the
2199 // server. Which will cause it to be dropped, killing the process
2200 if this
2201 .language_server_ids
2202 .get(&key)
2203 .map(|id| id != &server_id)
2204 .unwrap_or(false)
2205 {
2206 return None;
2207 }
2208
2209 // Update language_servers collection with Running variant of LanguageServerState
2210 // indicating that the server is up and running and ready
2211 this.language_servers.insert(
2212 server_id,
2213 LanguageServerState::Running {
2214 adapter: adapter.clone(),
2215 server: language_server.clone(),
2216 },
2217 );
2218 this.language_server_statuses.insert(
2219 server_id,
2220 LanguageServerStatus {
2221 name: language_server.name().to_string(),
2222 pending_work: Default::default(),
2223 has_pending_diagnostic_updates: false,
2224 progress_tokens: Default::default(),
2225 },
2226 );
2227 language_server
2228 .notify::<lsp::notification::DidChangeConfiguration>(
2229 lsp::DidChangeConfigurationParams {
2230 settings: this.language_server_settings.lock().clone(),
2231 },
2232 )
2233 .ok();
2234
2235 if let Some(project_id) = this.shared_remote_id() {
2236 this.client
2237 .send(proto::StartLanguageServer {
2238 project_id,
2239 server: Some(proto::LanguageServer {
2240 id: server_id as u64,
2241 name: language_server.name().to_string(),
2242 }),
2243 })
2244 .log_err();
2245 }
2246
2247 // Tell the language server about every open buffer in the worktree that matches the language.
2248 for buffer in this.opened_buffers.values() {
2249 if let Some(buffer_handle) = buffer.upgrade(cx) {
2250 let buffer = buffer_handle.read(cx);
2251 let file = if let Some(file) = File::from_dyn(buffer.file()) {
2252 file
2253 } else {
2254 continue;
2255 };
2256 let language = if let Some(language) = buffer.language() {
2257 language
2258 } else {
2259 continue;
2260 };
2261 if file.worktree.read(cx).id() != key.0
2262 || language.lsp_adapter().map(|a| a.name.clone())
2263 != Some(key.1.clone())
2264 {
2265 continue;
2266 }
2267
2268 let file = file.as_local()?;
2269 let versions = this
2270 .buffer_snapshots
2271 .entry(buffer.remote_id())
2272 .or_insert_with(|| vec![(0, buffer.text_snapshot())]);
2273 let (version, initial_snapshot) = versions.last().unwrap();
2274 let uri = lsp::Url::from_file_path(file.abs_path(cx)).unwrap();
2275 language_server
2276 .notify::<lsp::notification::DidOpenTextDocument>(
2277 lsp::DidOpenTextDocumentParams {
2278 text_document: lsp::TextDocumentItem::new(
2279 uri,
2280 adapter
2281 .id_for_language
2282 .clone()
2283 .unwrap_or_default(),
2284 *version,
2285 initial_snapshot.text(),
2286 ),
2287 },
2288 )
2289 .log_err()?;
2290 buffer_handle.update(cx, |buffer, cx| {
2291 buffer.set_completion_triggers(
2292 language_server
2293 .capabilities()
2294 .completion_provider
2295 .as_ref()
2296 .and_then(|provider| {
2297 provider.trigger_characters.clone()
2298 })
2299 .unwrap_or(Vec::new()),
2300 cx,
2301 )
2302 });
2303 }
2304 }
2305
2306 cx.notify();
2307 Some(language_server)
2308 })
2309 })),
2310 );
2311
2312 server_id
2313 });
2314 }
2315
2316 // Returns a list of all of the worktrees which no longer have a language server and the root path
2317 // for the stopped server
2318 fn stop_language_server(
2319 &mut self,
2320 worktree_id: WorktreeId,
2321 adapter_name: LanguageServerName,
2322 cx: &mut ModelContext<Self>,
2323 ) -> Task<(Option<PathBuf>, Vec<WorktreeId>)> {
2324 let key = (worktree_id, adapter_name);
2325 if let Some(server_id) = self.language_server_ids.remove(&key) {
2326 // Remove other entries for this language server as well
2327 let mut orphaned_worktrees = vec![worktree_id];
2328 let other_keys = self.language_server_ids.keys().cloned().collect::<Vec<_>>();
2329 for other_key in other_keys {
2330 if self.language_server_ids.get(&other_key) == Some(&server_id) {
2331 self.language_server_ids.remove(&other_key);
2332 orphaned_worktrees.push(other_key.0);
2333 }
2334 }
2335
2336 self.language_server_statuses.remove(&server_id);
2337 cx.notify();
2338
2339 let server_state = self.language_servers.remove(&server_id);
2340 cx.spawn_weak(|this, mut cx| async move {
2341 let mut root_path = None;
2342
2343 let server = match server_state {
2344 Some(LanguageServerState::Starting(started_language_server)) => {
2345 started_language_server.await
2346 }
2347 Some(LanguageServerState::Running { server, .. }) => Some(server),
2348 None => None,
2349 };
2350
2351 if let Some(server) = server {
2352 root_path = Some(server.root_path().clone());
2353 if let Some(shutdown) = server.shutdown() {
2354 shutdown.await;
2355 }
2356 }
2357
2358 if let Some(this) = this.upgrade(&cx) {
2359 this.update(&mut cx, |this, cx| {
2360 this.language_server_statuses.remove(&server_id);
2361 cx.notify();
2362 });
2363 }
2364
2365 (root_path, orphaned_worktrees)
2366 })
2367 } else {
2368 Task::ready((None, Vec::new()))
2369 }
2370 }
2371
2372 pub fn restart_language_servers_for_buffers(
2373 &mut self,
2374 buffers: impl IntoIterator<Item = ModelHandle<Buffer>>,
2375 cx: &mut ModelContext<Self>,
2376 ) -> Option<()> {
2377 let language_server_lookup_info: HashSet<(WorktreeId, Arc<Path>, PathBuf)> = buffers
2378 .into_iter()
2379 .filter_map(|buffer| {
2380 let file = File::from_dyn(buffer.read(cx).file())?;
2381 let worktree = file.worktree.read(cx).as_local()?;
2382 let worktree_id = worktree.id();
2383 let worktree_abs_path = worktree.abs_path().clone();
2384 let full_path = file.full_path(cx);
2385 Some((worktree_id, worktree_abs_path, full_path))
2386 })
2387 .collect();
2388 for (worktree_id, worktree_abs_path, full_path) in language_server_lookup_info {
2389 let language = self.languages.select_language(&full_path)?;
2390 self.restart_language_server(worktree_id, worktree_abs_path, language, cx);
2391 }
2392
2393 None
2394 }
2395
2396 fn restart_language_server(
2397 &mut self,
2398 worktree_id: WorktreeId,
2399 fallback_path: Arc<Path>,
2400 language: Arc<Language>,
2401 cx: &mut ModelContext<Self>,
2402 ) {
2403 let adapter = if let Some(adapter) = language.lsp_adapter() {
2404 adapter
2405 } else {
2406 return;
2407 };
2408
2409 let server_name = adapter.name.clone();
2410 let stop = self.stop_language_server(worktree_id, server_name.clone(), cx);
2411 cx.spawn_weak(|this, mut cx| async move {
2412 let (original_root_path, orphaned_worktrees) = stop.await;
2413 if let Some(this) = this.upgrade(&cx) {
2414 this.update(&mut cx, |this, cx| {
2415 // Attempt to restart using original server path. Fallback to passed in
2416 // path if we could not retrieve the root path
2417 let root_path = original_root_path
2418 .map(|path_buf| Arc::from(path_buf.as_path()))
2419 .unwrap_or(fallback_path);
2420
2421 this.start_language_server(worktree_id, root_path, language, cx);
2422
2423 // Lookup new server id and set it for each of the orphaned worktrees
2424 if let Some(new_server_id) = this
2425 .language_server_ids
2426 .get(&(worktree_id, server_name.clone()))
2427 .cloned()
2428 {
2429 for orphaned_worktree in orphaned_worktrees {
2430 this.language_server_ids.insert(
2431 (orphaned_worktree, server_name.clone()),
2432 new_server_id.clone(),
2433 );
2434 }
2435 }
2436 });
2437 }
2438 })
2439 .detach();
2440 }
2441
2442 async fn on_lsp_diagnostics_published(
2443 &mut self,
2444 server_id: usize,
2445 mut params: lsp::PublishDiagnosticsParams,
2446 adapter: &Arc<LspAdapter>,
2447 cx: &mut ModelContext<'_, Self>,
2448 ) {
2449 adapter.process_diagnostics(&mut params).await;
2450 self.update_diagnostics(
2451 server_id,
2452 params,
2453 &adapter.disk_based_diagnostic_sources,
2454 cx,
2455 )
2456 .log_err();
2457 }
2458
2459 fn on_lsp_progress(
2460 &mut self,
2461 progress: lsp::ProgressParams,
2462 server_id: usize,
2463 disk_based_diagnostics_progress_token: Option<String>,
2464 cx: &mut ModelContext<Self>,
2465 ) {
2466 let token = match progress.token {
2467 lsp::NumberOrString::String(token) => token,
2468 lsp::NumberOrString::Number(token) => {
2469 log::info!("skipping numeric progress token {}", token);
2470 return;
2471 }
2472 };
2473 let progress = match progress.value {
2474 lsp::ProgressParamsValue::WorkDone(value) => value,
2475 };
2476 let language_server_status =
2477 if let Some(status) = self.language_server_statuses.get_mut(&server_id) {
2478 status
2479 } else {
2480 return;
2481 };
2482
2483 if !language_server_status.progress_tokens.contains(&token) {
2484 return;
2485 }
2486
2487 let same_token =
2488 Some(token.as_ref()) == disk_based_diagnostics_progress_token.as_ref().map(|x| &**x);
2489
2490 match progress {
2491 lsp::WorkDoneProgress::Begin(report) => {
2492 if same_token {
2493 language_server_status.has_pending_diagnostic_updates = true;
2494 self.disk_based_diagnostics_started(server_id, cx);
2495 self.broadcast_language_server_update(
2496 server_id,
2497 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
2498 proto::LspDiskBasedDiagnosticsUpdating {},
2499 ),
2500 );
2501 } else {
2502 self.on_lsp_work_start(
2503 server_id,
2504 token.clone(),
2505 LanguageServerProgress {
2506 message: report.message.clone(),
2507 percentage: report.percentage.map(|p| p as usize),
2508 last_update_at: Instant::now(),
2509 },
2510 cx,
2511 );
2512 self.broadcast_language_server_update(
2513 server_id,
2514 proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
2515 token,
2516 message: report.message,
2517 percentage: report.percentage.map(|p| p as u32),
2518 }),
2519 );
2520 }
2521 }
2522 lsp::WorkDoneProgress::Report(report) => {
2523 if !same_token {
2524 self.on_lsp_work_progress(
2525 server_id,
2526 token.clone(),
2527 LanguageServerProgress {
2528 message: report.message.clone(),
2529 percentage: report.percentage.map(|p| p as usize),
2530 last_update_at: Instant::now(),
2531 },
2532 cx,
2533 );
2534 self.broadcast_language_server_update(
2535 server_id,
2536 proto::update_language_server::Variant::WorkProgress(
2537 proto::LspWorkProgress {
2538 token,
2539 message: report.message,
2540 percentage: report.percentage.map(|p| p as u32),
2541 },
2542 ),
2543 );
2544 }
2545 }
2546 lsp::WorkDoneProgress::End(_) => {
2547 language_server_status.progress_tokens.remove(&token);
2548
2549 if same_token {
2550 language_server_status.has_pending_diagnostic_updates = false;
2551 self.disk_based_diagnostics_finished(server_id, cx);
2552 self.broadcast_language_server_update(
2553 server_id,
2554 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
2555 proto::LspDiskBasedDiagnosticsUpdated {},
2556 ),
2557 );
2558 } else {
2559 self.on_lsp_work_end(server_id, token.clone(), cx);
2560 self.broadcast_language_server_update(
2561 server_id,
2562 proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
2563 token,
2564 }),
2565 );
2566 }
2567 }
2568 }
2569 }
2570
2571 fn on_lsp_work_start(
2572 &mut self,
2573 language_server_id: usize,
2574 token: String,
2575 progress: LanguageServerProgress,
2576 cx: &mut ModelContext<Self>,
2577 ) {
2578 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
2579 status.pending_work.insert(token, progress);
2580 cx.notify();
2581 }
2582 }
2583
2584 fn on_lsp_work_progress(
2585 &mut self,
2586 language_server_id: usize,
2587 token: String,
2588 progress: LanguageServerProgress,
2589 cx: &mut ModelContext<Self>,
2590 ) {
2591 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
2592 let entry = status
2593 .pending_work
2594 .entry(token)
2595 .or_insert(LanguageServerProgress {
2596 message: Default::default(),
2597 percentage: Default::default(),
2598 last_update_at: progress.last_update_at,
2599 });
2600 if progress.message.is_some() {
2601 entry.message = progress.message;
2602 }
2603 if progress.percentage.is_some() {
2604 entry.percentage = progress.percentage;
2605 }
2606 entry.last_update_at = progress.last_update_at;
2607 cx.notify();
2608 }
2609 }
2610
2611 fn on_lsp_work_end(
2612 &mut self,
2613 language_server_id: usize,
2614 token: String,
2615 cx: &mut ModelContext<Self>,
2616 ) {
2617 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
2618 status.pending_work.remove(&token);
2619 cx.notify();
2620 }
2621 }
2622
2623 async fn on_lsp_workspace_edit(
2624 this: WeakModelHandle<Self>,
2625 params: lsp::ApplyWorkspaceEditParams,
2626 server_id: usize,
2627 adapter: Arc<LspAdapter>,
2628 language_server: Arc<LanguageServer>,
2629 mut cx: AsyncAppContext,
2630 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
2631 let this = this
2632 .upgrade(&cx)
2633 .ok_or_else(|| anyhow!("project project closed"))?;
2634 let transaction = Self::deserialize_workspace_edit(
2635 this.clone(),
2636 params.edit,
2637 true,
2638 adapter.clone(),
2639 language_server.clone(),
2640 &mut cx,
2641 )
2642 .await
2643 .log_err();
2644 this.update(&mut cx, |this, _| {
2645 if let Some(transaction) = transaction {
2646 this.last_workspace_edits_by_language_server
2647 .insert(server_id, transaction);
2648 }
2649 });
2650 Ok(lsp::ApplyWorkspaceEditResponse {
2651 applied: true,
2652 failed_change: None,
2653 failure_reason: None,
2654 })
2655 }
2656
2657 fn broadcast_language_server_update(
2658 &self,
2659 language_server_id: usize,
2660 event: proto::update_language_server::Variant,
2661 ) {
2662 if let Some(project_id) = self.shared_remote_id() {
2663 self.client
2664 .send(proto::UpdateLanguageServer {
2665 project_id,
2666 language_server_id: language_server_id as u64,
2667 variant: Some(event),
2668 })
2669 .log_err();
2670 }
2671 }
2672
2673 pub fn set_language_server_settings(&mut self, settings: serde_json::Value) {
2674 for server_state in self.language_servers.values() {
2675 if let LanguageServerState::Running { server, .. } = server_state {
2676 server
2677 .notify::<lsp::notification::DidChangeConfiguration>(
2678 lsp::DidChangeConfigurationParams {
2679 settings: settings.clone(),
2680 },
2681 )
2682 .ok();
2683 }
2684 }
2685 *self.language_server_settings.lock() = settings;
2686 }
2687
2688 pub fn language_server_statuses(
2689 &self,
2690 ) -> impl DoubleEndedIterator<Item = &LanguageServerStatus> {
2691 self.language_server_statuses.values()
2692 }
2693
2694 pub fn update_diagnostics(
2695 &mut self,
2696 language_server_id: usize,
2697 params: lsp::PublishDiagnosticsParams,
2698 disk_based_sources: &[String],
2699 cx: &mut ModelContext<Self>,
2700 ) -> Result<()> {
2701 let abs_path = params
2702 .uri
2703 .to_file_path()
2704 .map_err(|_| anyhow!("URI is not a file"))?;
2705 let mut diagnostics = Vec::default();
2706 let mut primary_diagnostic_group_ids = HashMap::default();
2707 let mut sources_by_group_id = HashMap::default();
2708 let mut supporting_diagnostics = HashMap::default();
2709 for diagnostic in ¶ms.diagnostics {
2710 let source = diagnostic.source.as_ref();
2711 let code = diagnostic.code.as_ref().map(|code| match code {
2712 lsp::NumberOrString::Number(code) => code.to_string(),
2713 lsp::NumberOrString::String(code) => code.clone(),
2714 });
2715 let range = range_from_lsp(diagnostic.range);
2716 let is_supporting = diagnostic
2717 .related_information
2718 .as_ref()
2719 .map_or(false, |infos| {
2720 infos.iter().any(|info| {
2721 primary_diagnostic_group_ids.contains_key(&(
2722 source,
2723 code.clone(),
2724 range_from_lsp(info.location.range),
2725 ))
2726 })
2727 });
2728
2729 let is_unnecessary = diagnostic.tags.as_ref().map_or(false, |tags| {
2730 tags.iter().any(|tag| *tag == DiagnosticTag::UNNECESSARY)
2731 });
2732
2733 if is_supporting {
2734 supporting_diagnostics.insert(
2735 (source, code.clone(), range),
2736 (diagnostic.severity, is_unnecessary),
2737 );
2738 } else {
2739 let group_id = post_inc(&mut self.next_diagnostic_group_id);
2740 let is_disk_based =
2741 source.map_or(false, |source| disk_based_sources.contains(&source));
2742
2743 sources_by_group_id.insert(group_id, source);
2744 primary_diagnostic_group_ids
2745 .insert((source, code.clone(), range.clone()), group_id);
2746
2747 diagnostics.push(DiagnosticEntry {
2748 range,
2749 diagnostic: Diagnostic {
2750 code: code.clone(),
2751 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
2752 message: diagnostic.message.clone(),
2753 group_id,
2754 is_primary: true,
2755 is_valid: true,
2756 is_disk_based,
2757 is_unnecessary,
2758 },
2759 });
2760 if let Some(infos) = &diagnostic.related_information {
2761 for info in infos {
2762 if info.location.uri == params.uri && !info.message.is_empty() {
2763 let range = range_from_lsp(info.location.range);
2764 diagnostics.push(DiagnosticEntry {
2765 range,
2766 diagnostic: Diagnostic {
2767 code: code.clone(),
2768 severity: DiagnosticSeverity::INFORMATION,
2769 message: info.message.clone(),
2770 group_id,
2771 is_primary: false,
2772 is_valid: true,
2773 is_disk_based,
2774 is_unnecessary: false,
2775 },
2776 });
2777 }
2778 }
2779 }
2780 }
2781 }
2782
2783 for entry in &mut diagnostics {
2784 let diagnostic = &mut entry.diagnostic;
2785 if !diagnostic.is_primary {
2786 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
2787 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
2788 source,
2789 diagnostic.code.clone(),
2790 entry.range.clone(),
2791 )) {
2792 if let Some(severity) = severity {
2793 diagnostic.severity = severity;
2794 }
2795 diagnostic.is_unnecessary = is_unnecessary;
2796 }
2797 }
2798 }
2799
2800 self.update_diagnostic_entries(
2801 language_server_id,
2802 abs_path,
2803 params.version,
2804 diagnostics,
2805 cx,
2806 )?;
2807 Ok(())
2808 }
2809
2810 pub fn update_diagnostic_entries(
2811 &mut self,
2812 language_server_id: usize,
2813 abs_path: PathBuf,
2814 version: Option<i32>,
2815 diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
2816 cx: &mut ModelContext<Project>,
2817 ) -> Result<(), anyhow::Error> {
2818 let (worktree, relative_path) = self
2819 .find_local_worktree(&abs_path, cx)
2820 .ok_or_else(|| anyhow!("no worktree found for diagnostics"))?;
2821
2822 let project_path = ProjectPath {
2823 worktree_id: worktree.read(cx).id(),
2824 path: relative_path.into(),
2825 };
2826 if let Some(buffer) = self.get_open_buffer(&project_path, cx) {
2827 self.update_buffer_diagnostics(&buffer, diagnostics.clone(), version, cx)?;
2828 }
2829
2830 let updated = worktree.update(cx, |worktree, cx| {
2831 worktree
2832 .as_local_mut()
2833 .ok_or_else(|| anyhow!("not a local worktree"))?
2834 .update_diagnostics(
2835 language_server_id,
2836 project_path.path.clone(),
2837 diagnostics,
2838 cx,
2839 )
2840 })?;
2841 if updated {
2842 cx.emit(Event::DiagnosticsUpdated {
2843 language_server_id,
2844 path: project_path,
2845 });
2846 }
2847 Ok(())
2848 }
2849
2850 fn update_buffer_diagnostics(
2851 &mut self,
2852 buffer: &ModelHandle<Buffer>,
2853 mut diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
2854 version: Option<i32>,
2855 cx: &mut ModelContext<Self>,
2856 ) -> Result<()> {
2857 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2858 Ordering::Equal
2859 .then_with(|| b.is_primary.cmp(&a.is_primary))
2860 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2861 .then_with(|| a.severity.cmp(&b.severity))
2862 .then_with(|| a.message.cmp(&b.message))
2863 }
2864
2865 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, version, cx)?;
2866
2867 diagnostics.sort_unstable_by(|a, b| {
2868 Ordering::Equal
2869 .then_with(|| a.range.start.cmp(&b.range.start))
2870 .then_with(|| b.range.end.cmp(&a.range.end))
2871 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2872 });
2873
2874 let mut sanitized_diagnostics = Vec::new();
2875 let edits_since_save = Patch::new(
2876 snapshot
2877 .edits_since::<PointUtf16>(buffer.read(cx).saved_version())
2878 .collect(),
2879 );
2880 for entry in diagnostics {
2881 let start;
2882 let end;
2883 if entry.diagnostic.is_disk_based {
2884 // Some diagnostics are based on files on disk instead of buffers'
2885 // current contents. Adjust these diagnostics' ranges to reflect
2886 // any unsaved edits.
2887 start = edits_since_save.old_to_new(entry.range.start);
2888 end = edits_since_save.old_to_new(entry.range.end);
2889 } else {
2890 start = entry.range.start;
2891 end = entry.range.end;
2892 }
2893
2894 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2895 ..snapshot.clip_point_utf16(end, Bias::Right);
2896
2897 // Expand empty ranges by one character
2898 if range.start == range.end {
2899 range.end.column += 1;
2900 range.end = snapshot.clip_point_utf16(range.end, Bias::Right);
2901 if range.start == range.end && range.end.column > 0 {
2902 range.start.column -= 1;
2903 range.start = snapshot.clip_point_utf16(range.start, Bias::Left);
2904 }
2905 }
2906
2907 sanitized_diagnostics.push(DiagnosticEntry {
2908 range,
2909 diagnostic: entry.diagnostic,
2910 });
2911 }
2912 drop(edits_since_save);
2913
2914 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2915 buffer.update(cx, |buffer, cx| buffer.update_diagnostics(set, cx));
2916 Ok(())
2917 }
2918
2919 pub fn reload_buffers(
2920 &self,
2921 buffers: HashSet<ModelHandle<Buffer>>,
2922 push_to_history: bool,
2923 cx: &mut ModelContext<Self>,
2924 ) -> Task<Result<ProjectTransaction>> {
2925 let mut local_buffers = Vec::new();
2926 let mut remote_buffers = None;
2927 for buffer_handle in buffers {
2928 let buffer = buffer_handle.read(cx);
2929 if buffer.is_dirty() {
2930 if let Some(file) = File::from_dyn(buffer.file()) {
2931 if file.is_local() {
2932 local_buffers.push(buffer_handle);
2933 } else {
2934 remote_buffers.get_or_insert(Vec::new()).push(buffer_handle);
2935 }
2936 }
2937 }
2938 }
2939
2940 let remote_buffers = self.remote_id().zip(remote_buffers);
2941 let client = self.client.clone();
2942
2943 cx.spawn(|this, mut cx| async move {
2944 let mut project_transaction = ProjectTransaction::default();
2945
2946 if let Some((project_id, remote_buffers)) = remote_buffers {
2947 let response = client
2948 .request(proto::ReloadBuffers {
2949 project_id,
2950 buffer_ids: remote_buffers
2951 .iter()
2952 .map(|buffer| buffer.read_with(&cx, |buffer, _| buffer.remote_id()))
2953 .collect(),
2954 })
2955 .await?
2956 .transaction
2957 .ok_or_else(|| anyhow!("missing transaction"))?;
2958 project_transaction = this
2959 .update(&mut cx, |this, cx| {
2960 this.deserialize_project_transaction(response, push_to_history, cx)
2961 })
2962 .await?;
2963 }
2964
2965 for buffer in local_buffers {
2966 let transaction = buffer
2967 .update(&mut cx, |buffer, cx| buffer.reload(cx))
2968 .await?;
2969 buffer.update(&mut cx, |buffer, cx| {
2970 if let Some(transaction) = transaction {
2971 if !push_to_history {
2972 buffer.forget_transaction(transaction.id);
2973 }
2974 project_transaction.0.insert(cx.handle(), transaction);
2975 }
2976 });
2977 }
2978
2979 Ok(project_transaction)
2980 })
2981 }
2982
2983 pub fn format(
2984 &self,
2985 buffers: HashSet<ModelHandle<Buffer>>,
2986 push_to_history: bool,
2987 cx: &mut ModelContext<Project>,
2988 ) -> Task<Result<ProjectTransaction>> {
2989 let mut local_buffers = Vec::new();
2990 let mut remote_buffers = None;
2991 for buffer_handle in buffers {
2992 let buffer = buffer_handle.read(cx);
2993 if let Some(file) = File::from_dyn(buffer.file()) {
2994 if let Some(buffer_abs_path) = file.as_local().map(|f| f.abs_path(cx)) {
2995 if let Some((_, server)) = self.language_server_for_buffer(buffer, cx) {
2996 local_buffers.push((buffer_handle, buffer_abs_path, server.clone()));
2997 }
2998 } else {
2999 remote_buffers.get_or_insert(Vec::new()).push(buffer_handle);
3000 }
3001 } else {
3002 return Task::ready(Ok(Default::default()));
3003 }
3004 }
3005
3006 let remote_buffers = self.remote_id().zip(remote_buffers);
3007 let client = self.client.clone();
3008
3009 cx.spawn(|this, mut cx| async move {
3010 let mut project_transaction = ProjectTransaction::default();
3011
3012 if let Some((project_id, remote_buffers)) = remote_buffers {
3013 let response = client
3014 .request(proto::FormatBuffers {
3015 project_id,
3016 buffer_ids: remote_buffers
3017 .iter()
3018 .map(|buffer| buffer.read_with(&cx, |buffer, _| buffer.remote_id()))
3019 .collect(),
3020 })
3021 .await?
3022 .transaction
3023 .ok_or_else(|| anyhow!("missing transaction"))?;
3024 project_transaction = this
3025 .update(&mut cx, |this, cx| {
3026 this.deserialize_project_transaction(response, push_to_history, cx)
3027 })
3028 .await?;
3029 }
3030
3031 for (buffer, buffer_abs_path, language_server) in local_buffers {
3032 let (format_on_save, tab_size) = buffer.read_with(&cx, |buffer, cx| {
3033 let settings = cx.global::<Settings>();
3034 let language_name = buffer.language().map(|language| language.name());
3035 (
3036 settings.format_on_save(language_name.as_deref()),
3037 settings.tab_size(language_name.as_deref()),
3038 )
3039 });
3040
3041 let transaction = match format_on_save {
3042 settings::FormatOnSave::Off => continue,
3043 settings::FormatOnSave::LanguageServer => Self::format_via_lsp(
3044 &this,
3045 &buffer,
3046 &buffer_abs_path,
3047 &language_server,
3048 tab_size,
3049 &mut cx,
3050 )
3051 .await
3052 .context("failed to format via language server")?,
3053 settings::FormatOnSave::External { command, arguments } => {
3054 Self::format_via_external_command(
3055 &buffer,
3056 &buffer_abs_path,
3057 &command,
3058 &arguments,
3059 &mut cx,
3060 )
3061 .await
3062 .context(format!(
3063 "failed to format via external command {:?}",
3064 command
3065 ))?
3066 }
3067 };
3068
3069 if let Some(transaction) = transaction {
3070 if !push_to_history {
3071 buffer.update(&mut cx, |buffer, _| {
3072 buffer.forget_transaction(transaction.id)
3073 });
3074 }
3075 project_transaction.0.insert(buffer, transaction);
3076 }
3077 }
3078
3079 Ok(project_transaction)
3080 })
3081 }
3082
3083 async fn format_via_lsp(
3084 this: &ModelHandle<Self>,
3085 buffer: &ModelHandle<Buffer>,
3086 abs_path: &Path,
3087 language_server: &Arc<LanguageServer>,
3088 tab_size: NonZeroU32,
3089 cx: &mut AsyncAppContext,
3090 ) -> Result<Option<Transaction>> {
3091 let text_document =
3092 lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(abs_path).unwrap());
3093 let capabilities = &language_server.capabilities();
3094 let lsp_edits = if capabilities
3095 .document_formatting_provider
3096 .as_ref()
3097 .map_or(false, |provider| *provider != lsp::OneOf::Left(false))
3098 {
3099 language_server
3100 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
3101 text_document,
3102 options: lsp::FormattingOptions {
3103 tab_size: tab_size.into(),
3104 insert_spaces: true,
3105 insert_final_newline: Some(true),
3106 ..Default::default()
3107 },
3108 work_done_progress_params: Default::default(),
3109 })
3110 .await?
3111 } else if capabilities
3112 .document_range_formatting_provider
3113 .as_ref()
3114 .map_or(false, |provider| *provider != lsp::OneOf::Left(false))
3115 {
3116 let buffer_start = lsp::Position::new(0, 0);
3117 let buffer_end =
3118 buffer.read_with(cx, |buffer, _| point_to_lsp(buffer.max_point_utf16()));
3119 language_server
3120 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
3121 text_document,
3122 range: lsp::Range::new(buffer_start, buffer_end),
3123 options: lsp::FormattingOptions {
3124 tab_size: tab_size.into(),
3125 insert_spaces: true,
3126 insert_final_newline: Some(true),
3127 ..Default::default()
3128 },
3129 work_done_progress_params: Default::default(),
3130 })
3131 .await?
3132 } else {
3133 None
3134 };
3135
3136 if let Some(lsp_edits) = lsp_edits {
3137 let edits = this
3138 .update(cx, |this, cx| {
3139 this.edits_from_lsp(&buffer, lsp_edits, None, cx)
3140 })
3141 .await?;
3142 buffer.update(cx, |buffer, cx| {
3143 buffer.finalize_last_transaction();
3144 buffer.start_transaction();
3145 for (range, text) in edits {
3146 buffer.edit([(range, text)], cx);
3147 }
3148 if buffer.end_transaction(cx).is_some() {
3149 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3150 Ok(Some(transaction))
3151 } else {
3152 Ok(None)
3153 }
3154 })
3155 } else {
3156 Ok(None)
3157 }
3158 }
3159
3160 async fn format_via_external_command(
3161 buffer: &ModelHandle<Buffer>,
3162 buffer_abs_path: &Path,
3163 command: &str,
3164 arguments: &[String],
3165 cx: &mut AsyncAppContext,
3166 ) -> Result<Option<Transaction>> {
3167 let working_dir_path = buffer.read_with(cx, |buffer, cx| {
3168 let file = File::from_dyn(buffer.file())?;
3169 let worktree = file.worktree.read(cx).as_local()?;
3170 let mut worktree_path = worktree.abs_path().to_path_buf();
3171 if worktree.root_entry()?.is_file() {
3172 worktree_path.pop();
3173 }
3174 Some(worktree_path)
3175 });
3176
3177 if let Some(working_dir_path) = working_dir_path {
3178 let mut child =
3179 smol::process::Command::new(command)
3180 .args(arguments.iter().map(|arg| {
3181 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
3182 }))
3183 .current_dir(&working_dir_path)
3184 .stdin(smol::process::Stdio::piped())
3185 .stdout(smol::process::Stdio::piped())
3186 .stderr(smol::process::Stdio::piped())
3187 .spawn()?;
3188 let stdin = child
3189 .stdin
3190 .as_mut()
3191 .ok_or_else(|| anyhow!("failed to acquire stdin"))?;
3192 let text = buffer.read_with(cx, |buffer, _| buffer.as_rope().clone());
3193 for chunk in text.chunks() {
3194 stdin.write_all(chunk.as_bytes()).await?;
3195 }
3196 stdin.flush().await?;
3197
3198 let output = child.output().await?;
3199 if !output.status.success() {
3200 return Err(anyhow!(
3201 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
3202 output.status.code(),
3203 String::from_utf8_lossy(&output.stdout),
3204 String::from_utf8_lossy(&output.stderr),
3205 ));
3206 }
3207
3208 let stdout = String::from_utf8(output.stdout)?;
3209 let diff = buffer
3210 .read_with(cx, |buffer, cx| buffer.diff(stdout, cx))
3211 .await;
3212 Ok(buffer.update(cx, |buffer, cx| buffer.apply_diff(diff, cx).cloned()))
3213 } else {
3214 Ok(None)
3215 }
3216 }
3217
3218 pub fn definition<T: ToPointUtf16>(
3219 &self,
3220 buffer: &ModelHandle<Buffer>,
3221 position: T,
3222 cx: &mut ModelContext<Self>,
3223 ) -> Task<Result<Vec<LocationLink>>> {
3224 let position = position.to_point_utf16(buffer.read(cx));
3225 self.request_lsp(buffer.clone(), GetDefinition { position }, cx)
3226 }
3227
3228 pub fn references<T: ToPointUtf16>(
3229 &self,
3230 buffer: &ModelHandle<Buffer>,
3231 position: T,
3232 cx: &mut ModelContext<Self>,
3233 ) -> Task<Result<Vec<Location>>> {
3234 let position = position.to_point_utf16(buffer.read(cx));
3235 self.request_lsp(buffer.clone(), GetReferences { position }, cx)
3236 }
3237
3238 pub fn document_highlights<T: ToPointUtf16>(
3239 &self,
3240 buffer: &ModelHandle<Buffer>,
3241 position: T,
3242 cx: &mut ModelContext<Self>,
3243 ) -> Task<Result<Vec<DocumentHighlight>>> {
3244 let position = position.to_point_utf16(buffer.read(cx));
3245
3246 self.request_lsp(buffer.clone(), GetDocumentHighlights { position }, cx)
3247 }
3248
3249 pub fn symbols(&self, query: &str, cx: &mut ModelContext<Self>) -> Task<Result<Vec<Symbol>>> {
3250 if self.is_local() {
3251 let mut requests = Vec::new();
3252 for ((worktree_id, _), server_id) in self.language_server_ids.iter() {
3253 let worktree_id = *worktree_id;
3254 if let Some(worktree) = self
3255 .worktree_for_id(worktree_id, cx)
3256 .and_then(|worktree| worktree.read(cx).as_local())
3257 {
3258 if let Some(LanguageServerState::Running { adapter, server }) =
3259 self.language_servers.get(server_id)
3260 {
3261 let adapter = adapter.clone();
3262 let worktree_abs_path = worktree.abs_path().clone();
3263 requests.push(
3264 server
3265 .request::<lsp::request::WorkspaceSymbol>(
3266 lsp::WorkspaceSymbolParams {
3267 query: query.to_string(),
3268 ..Default::default()
3269 },
3270 )
3271 .log_err()
3272 .map(move |response| {
3273 (
3274 adapter,
3275 worktree_id,
3276 worktree_abs_path,
3277 response.unwrap_or_default(),
3278 )
3279 }),
3280 );
3281 }
3282 }
3283 }
3284
3285 cx.spawn_weak(|this, cx| async move {
3286 let responses = futures::future::join_all(requests).await;
3287 let this = if let Some(this) = this.upgrade(&cx) {
3288 this
3289 } else {
3290 return Ok(Default::default());
3291 };
3292
3293 struct PartialSymbol {
3294 source_worktree_id: WorktreeId,
3295 worktree_id: WorktreeId,
3296 language_server_name: LanguageServerName,
3297 path: PathBuf,
3298 language: Option<Arc<Language>>,
3299 name: String,
3300 kind: lsp::SymbolKind,
3301 range: Range<PointUtf16>,
3302 signature: [u8; 32],
3303 }
3304
3305 let partial_symbols = this.read_with(&cx, |this, cx| {
3306 let mut partial_symbols = Vec::new();
3307 for (adapter, source_worktree_id, worktree_abs_path, response) in responses {
3308 for lsp_symbol in response.into_iter().flatten() {
3309 let abs_path = match lsp_symbol.location.uri.to_file_path().ok() {
3310 Some(abs_path) => abs_path,
3311 None => continue,
3312 };
3313 let mut worktree_id = source_worktree_id;
3314 let path;
3315 if let Some((worktree, rel_path)) =
3316 this.find_local_worktree(&abs_path, cx)
3317 {
3318 worktree_id = worktree.read(cx).id();
3319 path = rel_path;
3320 } else {
3321 path = relativize_path(&worktree_abs_path, &abs_path);
3322 }
3323
3324 let language = this.languages.select_language(&path).clone();
3325 let signature = this.symbol_signature(worktree_id, &path);
3326
3327 partial_symbols.push(PartialSymbol {
3328 source_worktree_id,
3329 worktree_id,
3330 language_server_name: adapter.name.clone(),
3331 name: lsp_symbol.name,
3332 kind: lsp_symbol.kind,
3333 language,
3334 path,
3335 range: range_from_lsp(lsp_symbol.location.range),
3336 signature,
3337 });
3338 }
3339 }
3340
3341 partial_symbols
3342 });
3343
3344 let mut symbols = Vec::new();
3345 for ps in partial_symbols.into_iter() {
3346 symbols.push(async move {
3347 let label = match ps.language {
3348 Some(language) => language.label_for_symbol(&ps.name, ps.kind).await,
3349 None => None,
3350 }
3351 .unwrap_or_else(|| CodeLabel::plain(ps.name.clone(), None));
3352
3353 Symbol {
3354 source_worktree_id: ps.source_worktree_id,
3355 worktree_id: ps.worktree_id,
3356 language_server_name: ps.language_server_name,
3357 name: ps.name,
3358 kind: ps.kind,
3359 label,
3360 path: ps.path,
3361 range: ps.range,
3362 signature: ps.signature,
3363 }
3364 });
3365 }
3366
3367 Ok(futures::future::join_all(symbols).await)
3368 })
3369 } else if let Some(project_id) = self.remote_id() {
3370 let request = self.client.request(proto::GetProjectSymbols {
3371 project_id,
3372 query: query.to_string(),
3373 });
3374 cx.spawn_weak(|this, cx| async move {
3375 let response = request.await?;
3376 let mut symbols = Vec::new();
3377 if let Some(this) = this.upgrade(&cx) {
3378 let new_symbols = this.read_with(&cx, |this, _| {
3379 let mut new_symbols = Vec::new();
3380 for symbol in response.symbols.into_iter() {
3381 new_symbols.push(this.deserialize_symbol(symbol));
3382 }
3383 new_symbols
3384 });
3385 for new_symbol in new_symbols {
3386 if let Some(new_symbol) = new_symbol.await.ok() {
3387 symbols.push(new_symbol);
3388 }
3389 }
3390 }
3391 Ok(symbols)
3392 })
3393 } else {
3394 Task::ready(Ok(Default::default()))
3395 }
3396 }
3397
3398 pub fn open_buffer_for_symbol(
3399 &mut self,
3400 symbol: &Symbol,
3401 cx: &mut ModelContext<Self>,
3402 ) -> Task<Result<ModelHandle<Buffer>>> {
3403 if self.is_local() {
3404 let language_server_id = if let Some(id) = self.language_server_ids.get(&(
3405 symbol.source_worktree_id,
3406 symbol.language_server_name.clone(),
3407 )) {
3408 *id
3409 } else {
3410 return Task::ready(Err(anyhow!(
3411 "language server for worktree and language not found"
3412 )));
3413 };
3414
3415 let worktree_abs_path = if let Some(worktree_abs_path) = self
3416 .worktree_for_id(symbol.worktree_id, cx)
3417 .and_then(|worktree| worktree.read(cx).as_local())
3418 .map(|local_worktree| local_worktree.abs_path())
3419 {
3420 worktree_abs_path
3421 } else {
3422 return Task::ready(Err(anyhow!("worktree not found for symbol")));
3423 };
3424 let symbol_abs_path = worktree_abs_path.join(&symbol.path);
3425 let symbol_uri = if let Ok(uri) = lsp::Url::from_file_path(symbol_abs_path) {
3426 uri
3427 } else {
3428 return Task::ready(Err(anyhow!("invalid symbol path")));
3429 };
3430
3431 self.open_local_buffer_via_lsp(
3432 symbol_uri,
3433 language_server_id,
3434 symbol.language_server_name.clone(),
3435 cx,
3436 )
3437 } else if let Some(project_id) = self.remote_id() {
3438 let request = self.client.request(proto::OpenBufferForSymbol {
3439 project_id,
3440 symbol: Some(serialize_symbol(symbol)),
3441 });
3442 cx.spawn(|this, mut cx| async move {
3443 let response = request.await?;
3444 let buffer = response.buffer.ok_or_else(|| anyhow!("invalid buffer"))?;
3445 this.update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
3446 .await
3447 })
3448 } else {
3449 Task::ready(Err(anyhow!("project does not have a remote id")))
3450 }
3451 }
3452
3453 pub fn hover<T: ToPointUtf16>(
3454 &self,
3455 buffer: &ModelHandle<Buffer>,
3456 position: T,
3457 cx: &mut ModelContext<Self>,
3458 ) -> Task<Result<Option<Hover>>> {
3459 let position = position.to_point_utf16(buffer.read(cx));
3460 self.request_lsp(buffer.clone(), GetHover { position }, cx)
3461 }
3462
3463 pub fn completions<T: ToPointUtf16>(
3464 &self,
3465 source_buffer_handle: &ModelHandle<Buffer>,
3466 position: T,
3467 cx: &mut ModelContext<Self>,
3468 ) -> Task<Result<Vec<Completion>>> {
3469 let source_buffer_handle = source_buffer_handle.clone();
3470 let source_buffer = source_buffer_handle.read(cx);
3471 let buffer_id = source_buffer.remote_id();
3472 let language = source_buffer.language().cloned();
3473 let worktree;
3474 let buffer_abs_path;
3475 if let Some(file) = File::from_dyn(source_buffer.file()) {
3476 worktree = file.worktree.clone();
3477 buffer_abs_path = file.as_local().map(|f| f.abs_path(cx));
3478 } else {
3479 return Task::ready(Ok(Default::default()));
3480 };
3481
3482 let position = position.to_point_utf16(source_buffer);
3483 let anchor = source_buffer.anchor_after(position);
3484
3485 if worktree.read(cx).as_local().is_some() {
3486 let buffer_abs_path = buffer_abs_path.unwrap();
3487 let lang_server =
3488 if let Some((_, server)) = self.language_server_for_buffer(source_buffer, cx) {
3489 server.clone()
3490 } else {
3491 return Task::ready(Ok(Default::default()));
3492 };
3493
3494 cx.spawn(|_, cx| async move {
3495 let completions = lang_server
3496 .request::<lsp::request::Completion>(lsp::CompletionParams {
3497 text_document_position: lsp::TextDocumentPositionParams::new(
3498 lsp::TextDocumentIdentifier::new(
3499 lsp::Url::from_file_path(buffer_abs_path).unwrap(),
3500 ),
3501 point_to_lsp(position),
3502 ),
3503 context: Default::default(),
3504 work_done_progress_params: Default::default(),
3505 partial_result_params: Default::default(),
3506 })
3507 .await
3508 .context("lsp completion request failed")?;
3509
3510 let completions = if let Some(completions) = completions {
3511 match completions {
3512 lsp::CompletionResponse::Array(completions) => completions,
3513 lsp::CompletionResponse::List(list) => list.items,
3514 }
3515 } else {
3516 Default::default()
3517 };
3518
3519 struct PartialCompletion {
3520 pub old_range: Range<Anchor>,
3521 pub new_text: String,
3522 pub language: Option<Arc<Language>>,
3523 pub lsp_completion: lsp::CompletionItem,
3524 }
3525
3526 let partial_completions = source_buffer_handle.read_with(&cx, |this, _| {
3527 let snapshot = this.snapshot();
3528 let clipped_position = this.clip_point_utf16(position, Bias::Left);
3529 let mut range_for_token = None;
3530 let mut partial_completions = Vec::new();
3531
3532 for lsp_completion in completions.into_iter() {
3533 // For now, we can only handle additional edits if they are returned
3534 // when resolving the completion, not if they are present initially.
3535 if lsp_completion
3536 .additional_text_edits
3537 .as_ref()
3538 .map_or(false, |edits| !edits.is_empty())
3539 {
3540 continue;
3541 }
3542
3543 let (old_range, new_text) = match lsp_completion.text_edit.as_ref() {
3544 // If the language server provides a range to overwrite, then
3545 // check that the range is valid.
3546 Some(lsp::CompletionTextEdit::Edit(edit)) => {
3547 let range = range_from_lsp(edit.range);
3548 let start = snapshot.clip_point_utf16(range.start, Bias::Left);
3549 let end = snapshot.clip_point_utf16(range.end, Bias::Left);
3550 if start != range.start || end != range.end {
3551 log::info!("completion out of expected range");
3552 continue;
3553 }
3554 (
3555 snapshot.anchor_before(start)..snapshot.anchor_after(end),
3556 edit.new_text.clone(),
3557 )
3558 }
3559 // If the language server does not provide a range, then infer
3560 // the range based on the syntax tree.
3561 None => {
3562 if position != clipped_position {
3563 log::info!("completion out of expected range");
3564 continue;
3565 }
3566 let Range { start, end } = range_for_token
3567 .get_or_insert_with(|| {
3568 let offset = position.to_offset(&snapshot);
3569 let (range, kind) = snapshot.surrounding_word(offset);
3570 if kind == Some(CharKind::Word) {
3571 range
3572 } else {
3573 offset..offset
3574 }
3575 })
3576 .clone();
3577 let text = lsp_completion
3578 .insert_text
3579 .as_ref()
3580 .unwrap_or(&lsp_completion.label)
3581 .clone();
3582 (
3583 snapshot.anchor_before(start)..snapshot.anchor_after(end),
3584 text.clone(),
3585 )
3586 }
3587 Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
3588 log::info!("unsupported insert/replace completion");
3589 continue;
3590 }
3591 };
3592
3593 let partial_completion = PartialCompletion {
3594 old_range,
3595 new_text,
3596 language: language.clone(),
3597 lsp_completion,
3598 };
3599
3600 partial_completions.push(partial_completion);
3601 }
3602 partial_completions
3603 });
3604
3605 let mut result = Vec::new();
3606
3607 for pc in partial_completions.into_iter() {
3608 result.push(async move {
3609 let label = match pc.language.as_ref() {
3610 Some(l) => l.label_for_completion(&pc.lsp_completion).await,
3611 None => None,
3612 }
3613 .unwrap_or_else(|| {
3614 CodeLabel::plain(
3615 pc.lsp_completion.label.clone(),
3616 pc.lsp_completion.filter_text.as_deref(),
3617 )
3618 });
3619
3620 let completion = Completion {
3621 old_range: pc.old_range,
3622 new_text: pc.new_text,
3623 label,
3624 lsp_completion: pc.lsp_completion,
3625 };
3626
3627 completion
3628 });
3629 }
3630
3631 Ok(futures::future::join_all(result).await)
3632 })
3633 } else if let Some(project_id) = self.remote_id() {
3634 let rpc = self.client.clone();
3635 let message = proto::GetCompletions {
3636 project_id,
3637 buffer_id,
3638 position: Some(language::proto::serialize_anchor(&anchor)),
3639 version: serialize_version(&source_buffer.version()),
3640 };
3641 cx.spawn_weak(|_, mut cx| async move {
3642 let response = rpc.request(message).await?;
3643
3644 source_buffer_handle
3645 .update(&mut cx, |buffer, _| {
3646 buffer.wait_for_version(deserialize_version(response.version))
3647 })
3648 .await;
3649
3650 let mut result = Vec::new();
3651 for completion in response.completions.into_iter() {
3652 let completion =
3653 language::proto::deserialize_completion(completion, language.clone())
3654 .await?;
3655 result.push(completion);
3656 }
3657 Ok(result)
3658 })
3659 } else {
3660 Task::ready(Ok(Default::default()))
3661 }
3662 }
3663
3664 pub fn apply_additional_edits_for_completion(
3665 &self,
3666 buffer_handle: ModelHandle<Buffer>,
3667 completion: Completion,
3668 push_to_history: bool,
3669 cx: &mut ModelContext<Self>,
3670 ) -> Task<Result<Option<Transaction>>> {
3671 let buffer = buffer_handle.read(cx);
3672 let buffer_id = buffer.remote_id();
3673
3674 if self.is_local() {
3675 let lang_server = if let Some((_, server)) = self.language_server_for_buffer(buffer, cx)
3676 {
3677 server.clone()
3678 } else {
3679 return Task::ready(Ok(Default::default()));
3680 };
3681
3682 cx.spawn(|this, mut cx| async move {
3683 let resolved_completion = lang_server
3684 .request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
3685 .await?;
3686 if let Some(edits) = resolved_completion.additional_text_edits {
3687 let edits = this
3688 .update(&mut cx, |this, cx| {
3689 this.edits_from_lsp(&buffer_handle, edits, None, cx)
3690 })
3691 .await?;
3692 buffer_handle.update(&mut cx, |buffer, cx| {
3693 buffer.finalize_last_transaction();
3694 buffer.start_transaction();
3695 for (range, text) in edits {
3696 buffer.edit([(range, text)], cx);
3697 }
3698 let transaction = if buffer.end_transaction(cx).is_some() {
3699 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3700 if !push_to_history {
3701 buffer.forget_transaction(transaction.id);
3702 }
3703 Some(transaction)
3704 } else {
3705 None
3706 };
3707 Ok(transaction)
3708 })
3709 } else {
3710 Ok(None)
3711 }
3712 })
3713 } else if let Some(project_id) = self.remote_id() {
3714 let client = self.client.clone();
3715 cx.spawn(|_, mut cx| async move {
3716 let response = client
3717 .request(proto::ApplyCompletionAdditionalEdits {
3718 project_id,
3719 buffer_id,
3720 completion: Some(language::proto::serialize_completion(&completion)),
3721 })
3722 .await?;
3723
3724 if let Some(transaction) = response.transaction {
3725 let transaction = language::proto::deserialize_transaction(transaction)?;
3726 buffer_handle
3727 .update(&mut cx, |buffer, _| {
3728 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
3729 })
3730 .await;
3731 if push_to_history {
3732 buffer_handle.update(&mut cx, |buffer, _| {
3733 buffer.push_transaction(transaction.clone(), Instant::now());
3734 });
3735 }
3736 Ok(Some(transaction))
3737 } else {
3738 Ok(None)
3739 }
3740 })
3741 } else {
3742 Task::ready(Err(anyhow!("project does not have a remote id")))
3743 }
3744 }
3745
3746 pub fn code_actions<T: Clone + ToOffset>(
3747 &self,
3748 buffer_handle: &ModelHandle<Buffer>,
3749 range: Range<T>,
3750 cx: &mut ModelContext<Self>,
3751 ) -> Task<Result<Vec<CodeAction>>> {
3752 let buffer_handle = buffer_handle.clone();
3753 let buffer = buffer_handle.read(cx);
3754 let snapshot = buffer.snapshot();
3755 let relevant_diagnostics = snapshot
3756 .diagnostics_in_range::<usize, usize>(range.to_offset(&snapshot), false)
3757 .map(|entry| entry.to_lsp_diagnostic_stub())
3758 .collect();
3759 let buffer_id = buffer.remote_id();
3760 let worktree;
3761 let buffer_abs_path;
3762 if let Some(file) = File::from_dyn(buffer.file()) {
3763 worktree = file.worktree.clone();
3764 buffer_abs_path = file.as_local().map(|f| f.abs_path(cx));
3765 } else {
3766 return Task::ready(Ok(Default::default()));
3767 };
3768 let range = buffer.anchor_before(range.start)..buffer.anchor_before(range.end);
3769
3770 if worktree.read(cx).as_local().is_some() {
3771 let buffer_abs_path = buffer_abs_path.unwrap();
3772 let lang_server = if let Some((_, server)) = self.language_server_for_buffer(buffer, cx)
3773 {
3774 server.clone()
3775 } else {
3776 return Task::ready(Ok(Default::default()));
3777 };
3778
3779 let lsp_range = range_to_lsp(range.to_point_utf16(buffer));
3780 cx.foreground().spawn(async move {
3781 if !lang_server.capabilities().code_action_provider.is_some() {
3782 return Ok(Default::default());
3783 }
3784
3785 Ok(lang_server
3786 .request::<lsp::request::CodeActionRequest>(lsp::CodeActionParams {
3787 text_document: lsp::TextDocumentIdentifier::new(
3788 lsp::Url::from_file_path(buffer_abs_path).unwrap(),
3789 ),
3790 range: lsp_range,
3791 work_done_progress_params: Default::default(),
3792 partial_result_params: Default::default(),
3793 context: lsp::CodeActionContext {
3794 diagnostics: relevant_diagnostics,
3795 only: Some(vec![
3796 lsp::CodeActionKind::QUICKFIX,
3797 lsp::CodeActionKind::REFACTOR,
3798 lsp::CodeActionKind::REFACTOR_EXTRACT,
3799 lsp::CodeActionKind::SOURCE,
3800 ]),
3801 },
3802 })
3803 .await?
3804 .unwrap_or_default()
3805 .into_iter()
3806 .filter_map(|entry| {
3807 if let lsp::CodeActionOrCommand::CodeAction(lsp_action) = entry {
3808 Some(CodeAction {
3809 range: range.clone(),
3810 lsp_action,
3811 })
3812 } else {
3813 None
3814 }
3815 })
3816 .collect())
3817 })
3818 } else if let Some(project_id) = self.remote_id() {
3819 let rpc = self.client.clone();
3820 let version = buffer.version();
3821 cx.spawn_weak(|_, mut cx| async move {
3822 let response = rpc
3823 .request(proto::GetCodeActions {
3824 project_id,
3825 buffer_id,
3826 start: Some(language::proto::serialize_anchor(&range.start)),
3827 end: Some(language::proto::serialize_anchor(&range.end)),
3828 version: serialize_version(&version),
3829 })
3830 .await?;
3831
3832 buffer_handle
3833 .update(&mut cx, |buffer, _| {
3834 buffer.wait_for_version(deserialize_version(response.version))
3835 })
3836 .await;
3837
3838 response
3839 .actions
3840 .into_iter()
3841 .map(language::proto::deserialize_code_action)
3842 .collect()
3843 })
3844 } else {
3845 Task::ready(Ok(Default::default()))
3846 }
3847 }
3848
3849 pub fn apply_code_action(
3850 &self,
3851 buffer_handle: ModelHandle<Buffer>,
3852 mut action: CodeAction,
3853 push_to_history: bool,
3854 cx: &mut ModelContext<Self>,
3855 ) -> Task<Result<ProjectTransaction>> {
3856 if self.is_local() {
3857 let buffer = buffer_handle.read(cx);
3858 let (lsp_adapter, lang_server) =
3859 if let Some((adapter, server)) = self.language_server_for_buffer(buffer, cx) {
3860 (adapter.clone(), server.clone())
3861 } else {
3862 return Task::ready(Ok(Default::default()));
3863 };
3864 let range = action.range.to_point_utf16(buffer);
3865
3866 cx.spawn(|this, mut cx| async move {
3867 if let Some(lsp_range) = action
3868 .lsp_action
3869 .data
3870 .as_mut()
3871 .and_then(|d| d.get_mut("codeActionParams"))
3872 .and_then(|d| d.get_mut("range"))
3873 {
3874 *lsp_range = serde_json::to_value(&range_to_lsp(range)).unwrap();
3875 action.lsp_action = lang_server
3876 .request::<lsp::request::CodeActionResolveRequest>(action.lsp_action)
3877 .await?;
3878 } else {
3879 let actions = this
3880 .update(&mut cx, |this, cx| {
3881 this.code_actions(&buffer_handle, action.range, cx)
3882 })
3883 .await?;
3884 action.lsp_action = actions
3885 .into_iter()
3886 .find(|a| a.lsp_action.title == action.lsp_action.title)
3887 .ok_or_else(|| anyhow!("code action is outdated"))?
3888 .lsp_action;
3889 }
3890
3891 if let Some(edit) = action.lsp_action.edit {
3892 Self::deserialize_workspace_edit(
3893 this,
3894 edit,
3895 push_to_history,
3896 lsp_adapter.clone(),
3897 lang_server.clone(),
3898 &mut cx,
3899 )
3900 .await
3901 } else if let Some(command) = action.lsp_action.command {
3902 this.update(&mut cx, |this, _| {
3903 this.last_workspace_edits_by_language_server
3904 .remove(&lang_server.server_id());
3905 });
3906 lang_server
3907 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
3908 command: command.command,
3909 arguments: command.arguments.unwrap_or_default(),
3910 ..Default::default()
3911 })
3912 .await?;
3913 Ok(this.update(&mut cx, |this, _| {
3914 this.last_workspace_edits_by_language_server
3915 .remove(&lang_server.server_id())
3916 .unwrap_or_default()
3917 }))
3918 } else {
3919 Ok(ProjectTransaction::default())
3920 }
3921 })
3922 } else if let Some(project_id) = self.remote_id() {
3923 let client = self.client.clone();
3924 let request = proto::ApplyCodeAction {
3925 project_id,
3926 buffer_id: buffer_handle.read(cx).remote_id(),
3927 action: Some(language::proto::serialize_code_action(&action)),
3928 };
3929 cx.spawn(|this, mut cx| async move {
3930 let response = client
3931 .request(request)
3932 .await?
3933 .transaction
3934 .ok_or_else(|| anyhow!("missing transaction"))?;
3935 this.update(&mut cx, |this, cx| {
3936 this.deserialize_project_transaction(response, push_to_history, cx)
3937 })
3938 .await
3939 })
3940 } else {
3941 Task::ready(Err(anyhow!("project does not have a remote id")))
3942 }
3943 }
3944
3945 async fn deserialize_workspace_edit(
3946 this: ModelHandle<Self>,
3947 edit: lsp::WorkspaceEdit,
3948 push_to_history: bool,
3949 lsp_adapter: Arc<LspAdapter>,
3950 language_server: Arc<LanguageServer>,
3951 cx: &mut AsyncAppContext,
3952 ) -> Result<ProjectTransaction> {
3953 let fs = this.read_with(cx, |this, _| this.fs.clone());
3954 let mut operations = Vec::new();
3955 if let Some(document_changes) = edit.document_changes {
3956 match document_changes {
3957 lsp::DocumentChanges::Edits(edits) => {
3958 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3959 }
3960 lsp::DocumentChanges::Operations(ops) => operations = ops,
3961 }
3962 } else if let Some(changes) = edit.changes {
3963 operations.extend(changes.into_iter().map(|(uri, edits)| {
3964 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3965 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3966 uri,
3967 version: None,
3968 },
3969 edits: edits.into_iter().map(lsp::OneOf::Left).collect(),
3970 })
3971 }));
3972 }
3973
3974 let mut project_transaction = ProjectTransaction::default();
3975 for operation in operations {
3976 match operation {
3977 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3978 let abs_path = op
3979 .uri
3980 .to_file_path()
3981 .map_err(|_| anyhow!("can't convert URI to path"))?;
3982
3983 if let Some(parent_path) = abs_path.parent() {
3984 fs.create_dir(parent_path).await?;
3985 }
3986 if abs_path.ends_with("/") {
3987 fs.create_dir(&abs_path).await?;
3988 } else {
3989 fs.create_file(&abs_path, op.options.map(Into::into).unwrap_or_default())
3990 .await?;
3991 }
3992 }
3993 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3994 let source_abs_path = op
3995 .old_uri
3996 .to_file_path()
3997 .map_err(|_| anyhow!("can't convert URI to path"))?;
3998 let target_abs_path = op
3999 .new_uri
4000 .to_file_path()
4001 .map_err(|_| anyhow!("can't convert URI to path"))?;
4002 fs.rename(
4003 &source_abs_path,
4004 &target_abs_path,
4005 op.options.map(Into::into).unwrap_or_default(),
4006 )
4007 .await?;
4008 }
4009 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
4010 let abs_path = op
4011 .uri
4012 .to_file_path()
4013 .map_err(|_| anyhow!("can't convert URI to path"))?;
4014 let options = op.options.map(Into::into).unwrap_or_default();
4015 if abs_path.ends_with("/") {
4016 fs.remove_dir(&abs_path, options).await?;
4017 } else {
4018 fs.remove_file(&abs_path, options).await?;
4019 }
4020 }
4021 lsp::DocumentChangeOperation::Edit(op) => {
4022 let buffer_to_edit = this
4023 .update(cx, |this, cx| {
4024 this.open_local_buffer_via_lsp(
4025 op.text_document.uri,
4026 language_server.server_id(),
4027 lsp_adapter.name.clone(),
4028 cx,
4029 )
4030 })
4031 .await?;
4032
4033 let edits = this
4034 .update(cx, |this, cx| {
4035 let edits = op.edits.into_iter().map(|edit| match edit {
4036 lsp::OneOf::Left(edit) => edit,
4037 lsp::OneOf::Right(edit) => edit.text_edit,
4038 });
4039 this.edits_from_lsp(
4040 &buffer_to_edit,
4041 edits,
4042 op.text_document.version,
4043 cx,
4044 )
4045 })
4046 .await?;
4047
4048 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
4049 buffer.finalize_last_transaction();
4050 buffer.start_transaction();
4051 for (range, text) in edits {
4052 buffer.edit([(range, text)], cx);
4053 }
4054 let transaction = if buffer.end_transaction(cx).is_some() {
4055 let transaction = buffer.finalize_last_transaction().unwrap().clone();
4056 if !push_to_history {
4057 buffer.forget_transaction(transaction.id);
4058 }
4059 Some(transaction)
4060 } else {
4061 None
4062 };
4063
4064 transaction
4065 });
4066 if let Some(transaction) = transaction {
4067 project_transaction.0.insert(buffer_to_edit, transaction);
4068 }
4069 }
4070 }
4071 }
4072
4073 Ok(project_transaction)
4074 }
4075
4076 pub fn prepare_rename<T: ToPointUtf16>(
4077 &self,
4078 buffer: ModelHandle<Buffer>,
4079 position: T,
4080 cx: &mut ModelContext<Self>,
4081 ) -> Task<Result<Option<Range<Anchor>>>> {
4082 let position = position.to_point_utf16(buffer.read(cx));
4083 self.request_lsp(buffer, PrepareRename { position }, cx)
4084 }
4085
4086 pub fn perform_rename<T: ToPointUtf16>(
4087 &self,
4088 buffer: ModelHandle<Buffer>,
4089 position: T,
4090 new_name: String,
4091 push_to_history: bool,
4092 cx: &mut ModelContext<Self>,
4093 ) -> Task<Result<ProjectTransaction>> {
4094 let position = position.to_point_utf16(buffer.read(cx));
4095 self.request_lsp(
4096 buffer,
4097 PerformRename {
4098 position,
4099 new_name,
4100 push_to_history,
4101 },
4102 cx,
4103 )
4104 }
4105
4106 pub fn search(
4107 &self,
4108 query: SearchQuery,
4109 cx: &mut ModelContext<Self>,
4110 ) -> Task<Result<HashMap<ModelHandle<Buffer>, Vec<Range<Anchor>>>>> {
4111 if self.is_local() {
4112 let snapshots = self
4113 .visible_worktrees(cx)
4114 .filter_map(|tree| {
4115 let tree = tree.read(cx).as_local()?;
4116 Some(tree.snapshot())
4117 })
4118 .collect::<Vec<_>>();
4119
4120 let background = cx.background().clone();
4121 let path_count: usize = snapshots.iter().map(|s| s.visible_file_count()).sum();
4122 if path_count == 0 {
4123 return Task::ready(Ok(Default::default()));
4124 }
4125 let workers = background.num_cpus().min(path_count);
4126 let (matching_paths_tx, mut matching_paths_rx) = smol::channel::bounded(1024);
4127 cx.background()
4128 .spawn({
4129 let fs = self.fs.clone();
4130 let background = cx.background().clone();
4131 let query = query.clone();
4132 async move {
4133 let fs = &fs;
4134 let query = &query;
4135 let matching_paths_tx = &matching_paths_tx;
4136 let paths_per_worker = (path_count + workers - 1) / workers;
4137 let snapshots = &snapshots;
4138 background
4139 .scoped(|scope| {
4140 for worker_ix in 0..workers {
4141 let worker_start_ix = worker_ix * paths_per_worker;
4142 let worker_end_ix = worker_start_ix + paths_per_worker;
4143 scope.spawn(async move {
4144 let mut snapshot_start_ix = 0;
4145 let mut abs_path = PathBuf::new();
4146 for snapshot in snapshots {
4147 let snapshot_end_ix =
4148 snapshot_start_ix + snapshot.visible_file_count();
4149 if worker_end_ix <= snapshot_start_ix {
4150 break;
4151 } else if worker_start_ix > snapshot_end_ix {
4152 snapshot_start_ix = snapshot_end_ix;
4153 continue;
4154 } else {
4155 let start_in_snapshot = worker_start_ix
4156 .saturating_sub(snapshot_start_ix);
4157 let end_in_snapshot =
4158 cmp::min(worker_end_ix, snapshot_end_ix)
4159 - snapshot_start_ix;
4160
4161 for entry in snapshot
4162 .files(false, start_in_snapshot)
4163 .take(end_in_snapshot - start_in_snapshot)
4164 {
4165 if matching_paths_tx.is_closed() {
4166 break;
4167 }
4168
4169 abs_path.clear();
4170 abs_path.push(&snapshot.abs_path());
4171 abs_path.push(&entry.path);
4172 let matches = if let Some(file) =
4173 fs.open_sync(&abs_path).await.log_err()
4174 {
4175 query.detect(file).unwrap_or(false)
4176 } else {
4177 false
4178 };
4179
4180 if matches {
4181 let project_path =
4182 (snapshot.id(), entry.path.clone());
4183 if matching_paths_tx
4184 .send(project_path)
4185 .await
4186 .is_err()
4187 {
4188 break;
4189 }
4190 }
4191 }
4192
4193 snapshot_start_ix = snapshot_end_ix;
4194 }
4195 }
4196 });
4197 }
4198 })
4199 .await;
4200 }
4201 })
4202 .detach();
4203
4204 let (buffers_tx, buffers_rx) = smol::channel::bounded(1024);
4205 let open_buffers = self
4206 .opened_buffers
4207 .values()
4208 .filter_map(|b| b.upgrade(cx))
4209 .collect::<HashSet<_>>();
4210 cx.spawn(|this, cx| async move {
4211 for buffer in &open_buffers {
4212 let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
4213 buffers_tx.send((buffer.clone(), snapshot)).await?;
4214 }
4215
4216 let open_buffers = Rc::new(RefCell::new(open_buffers));
4217 while let Some(project_path) = matching_paths_rx.next().await {
4218 if buffers_tx.is_closed() {
4219 break;
4220 }
4221
4222 let this = this.clone();
4223 let open_buffers = open_buffers.clone();
4224 let buffers_tx = buffers_tx.clone();
4225 cx.spawn(|mut cx| async move {
4226 if let Some(buffer) = this
4227 .update(&mut cx, |this, cx| this.open_buffer(project_path, cx))
4228 .await
4229 .log_err()
4230 {
4231 if open_buffers.borrow_mut().insert(buffer.clone()) {
4232 let snapshot = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
4233 buffers_tx.send((buffer, snapshot)).await?;
4234 }
4235 }
4236
4237 Ok::<_, anyhow::Error>(())
4238 })
4239 .detach();
4240 }
4241
4242 Ok::<_, anyhow::Error>(())
4243 })
4244 .detach_and_log_err(cx);
4245
4246 let background = cx.background().clone();
4247 cx.background().spawn(async move {
4248 let query = &query;
4249 let mut matched_buffers = Vec::new();
4250 for _ in 0..workers {
4251 matched_buffers.push(HashMap::default());
4252 }
4253 background
4254 .scoped(|scope| {
4255 for worker_matched_buffers in matched_buffers.iter_mut() {
4256 let mut buffers_rx = buffers_rx.clone();
4257 scope.spawn(async move {
4258 while let Some((buffer, snapshot)) = buffers_rx.next().await {
4259 let buffer_matches = query
4260 .search(snapshot.as_rope())
4261 .await
4262 .iter()
4263 .map(|range| {
4264 snapshot.anchor_before(range.start)
4265 ..snapshot.anchor_after(range.end)
4266 })
4267 .collect::<Vec<_>>();
4268 if !buffer_matches.is_empty() {
4269 worker_matched_buffers
4270 .insert(buffer.clone(), buffer_matches);
4271 }
4272 }
4273 });
4274 }
4275 })
4276 .await;
4277 Ok(matched_buffers.into_iter().flatten().collect())
4278 })
4279 } else if let Some(project_id) = self.remote_id() {
4280 let request = self.client.request(query.to_proto(project_id));
4281 cx.spawn(|this, mut cx| async move {
4282 let response = request.await?;
4283 let mut result = HashMap::default();
4284 for location in response.locations {
4285 let buffer = location.buffer.ok_or_else(|| anyhow!("missing buffer"))?;
4286 let target_buffer = this
4287 .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
4288 .await?;
4289 let start = location
4290 .start
4291 .and_then(deserialize_anchor)
4292 .ok_or_else(|| anyhow!("missing target start"))?;
4293 let end = location
4294 .end
4295 .and_then(deserialize_anchor)
4296 .ok_or_else(|| anyhow!("missing target end"))?;
4297 result
4298 .entry(target_buffer)
4299 .or_insert(Vec::new())
4300 .push(start..end)
4301 }
4302 Ok(result)
4303 })
4304 } else {
4305 Task::ready(Ok(Default::default()))
4306 }
4307 }
4308
4309 fn request_lsp<R: LspCommand>(
4310 &self,
4311 buffer_handle: ModelHandle<Buffer>,
4312 request: R,
4313 cx: &mut ModelContext<Self>,
4314 ) -> Task<Result<R::Response>>
4315 where
4316 <R::LspRequest as lsp::request::Request>::Result: Send,
4317 {
4318 let buffer = buffer_handle.read(cx);
4319 if self.is_local() {
4320 let file = File::from_dyn(buffer.file()).and_then(File::as_local);
4321 if let Some((file, language_server)) = file.zip(
4322 self.language_server_for_buffer(buffer, cx)
4323 .map(|(_, server)| server.clone()),
4324 ) {
4325 let lsp_params = request.to_lsp(&file.abs_path(cx), cx);
4326 return cx.spawn(|this, cx| async move {
4327 if !request.check_capabilities(&language_server.capabilities()) {
4328 return Ok(Default::default());
4329 }
4330
4331 let response = language_server
4332 .request::<R::LspRequest>(lsp_params)
4333 .await
4334 .context("lsp request failed")?;
4335 request
4336 .response_from_lsp(response, this, buffer_handle, cx)
4337 .await
4338 });
4339 }
4340 } else if let Some(project_id) = self.remote_id() {
4341 let rpc = self.client.clone();
4342 let message = request.to_proto(project_id, buffer);
4343 return cx.spawn(|this, cx| async move {
4344 let response = rpc.request(message).await?;
4345 request
4346 .response_from_proto(response, this, buffer_handle, cx)
4347 .await
4348 });
4349 }
4350 Task::ready(Ok(Default::default()))
4351 }
4352
4353 pub fn find_or_create_local_worktree(
4354 &mut self,
4355 abs_path: impl AsRef<Path>,
4356 visible: bool,
4357 cx: &mut ModelContext<Self>,
4358 ) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
4359 let abs_path = abs_path.as_ref();
4360 if let Some((tree, relative_path)) = self.find_local_worktree(abs_path, cx) {
4361 Task::ready(Ok((tree.clone(), relative_path.into())))
4362 } else {
4363 let worktree = self.create_local_worktree(abs_path, visible, cx);
4364 cx.foreground()
4365 .spawn(async move { Ok((worktree.await?, PathBuf::new())) })
4366 }
4367 }
4368
4369 pub fn find_local_worktree(
4370 &self,
4371 abs_path: &Path,
4372 cx: &AppContext,
4373 ) -> Option<(ModelHandle<Worktree>, PathBuf)> {
4374 for tree in &self.worktrees {
4375 if let Some(tree) = tree.upgrade(cx) {
4376 if let Some(relative_path) = tree
4377 .read(cx)
4378 .as_local()
4379 .and_then(|t| abs_path.strip_prefix(t.abs_path()).ok())
4380 {
4381 return Some((tree.clone(), relative_path.into()));
4382 }
4383 }
4384 }
4385 None
4386 }
4387
4388 pub fn is_shared(&self) -> bool {
4389 match &self.client_state {
4390 ProjectClientState::Local { is_shared, .. } => *is_shared,
4391 ProjectClientState::Remote { .. } => false,
4392 }
4393 }
4394
4395 fn create_local_worktree(
4396 &mut self,
4397 abs_path: impl AsRef<Path>,
4398 visible: bool,
4399 cx: &mut ModelContext<Self>,
4400 ) -> Task<Result<ModelHandle<Worktree>>> {
4401 let fs = self.fs.clone();
4402 let client = self.client.clone();
4403 let next_entry_id = self.next_entry_id.clone();
4404 let path: Arc<Path> = abs_path.as_ref().into();
4405 let task = self
4406 .loading_local_worktrees
4407 .entry(path.clone())
4408 .or_insert_with(|| {
4409 cx.spawn(|project, mut cx| {
4410 async move {
4411 let worktree = Worktree::local(
4412 client.clone(),
4413 path.clone(),
4414 visible,
4415 fs,
4416 next_entry_id,
4417 &mut cx,
4418 )
4419 .await;
4420 project.update(&mut cx, |project, _| {
4421 project.loading_local_worktrees.remove(&path);
4422 });
4423 let worktree = worktree?;
4424
4425 let project_id = project.update(&mut cx, |project, cx| {
4426 project.add_worktree(&worktree, cx);
4427 project.shared_remote_id()
4428 });
4429
4430 if let Some(project_id) = project_id {
4431 worktree
4432 .update(&mut cx, |worktree, cx| {
4433 worktree.as_local_mut().unwrap().share(project_id, cx)
4434 })
4435 .await
4436 .log_err();
4437 }
4438
4439 Ok(worktree)
4440 }
4441 .map_err(|err| Arc::new(err))
4442 })
4443 .shared()
4444 })
4445 .clone();
4446 cx.foreground().spawn(async move {
4447 match task.await {
4448 Ok(worktree) => Ok(worktree),
4449 Err(err) => Err(anyhow!("{}", err)),
4450 }
4451 })
4452 }
4453
4454 pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
4455 self.worktrees.retain(|worktree| {
4456 if let Some(worktree) = worktree.upgrade(cx) {
4457 let id = worktree.read(cx).id();
4458 if id == id_to_remove {
4459 cx.emit(Event::WorktreeRemoved(id));
4460 false
4461 } else {
4462 true
4463 }
4464 } else {
4465 false
4466 }
4467 });
4468 self.metadata_changed(true, cx);
4469 cx.notify();
4470 }
4471
4472 fn add_worktree(&mut self, worktree: &ModelHandle<Worktree>, cx: &mut ModelContext<Self>) {
4473 cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
4474 if worktree.read(cx).is_local() {
4475 cx.subscribe(&worktree, |this, worktree, _, cx| {
4476 this.update_local_worktree_buffers(worktree, cx);
4477 })
4478 .detach();
4479 }
4480
4481 let push_strong_handle = {
4482 let worktree = worktree.read(cx);
4483 self.is_shared() || worktree.is_visible() || worktree.is_remote()
4484 };
4485 if push_strong_handle {
4486 self.worktrees
4487 .push(WorktreeHandle::Strong(worktree.clone()));
4488 } else {
4489 self.worktrees
4490 .push(WorktreeHandle::Weak(worktree.downgrade()));
4491 }
4492
4493 self.metadata_changed(true, cx);
4494 cx.observe_release(&worktree, |this, worktree, cx| {
4495 this.remove_worktree(worktree.id(), cx);
4496 cx.notify();
4497 })
4498 .detach();
4499
4500 cx.emit(Event::WorktreeAdded);
4501 cx.notify();
4502 }
4503
4504 fn update_local_worktree_buffers(
4505 &mut self,
4506 worktree_handle: ModelHandle<Worktree>,
4507 cx: &mut ModelContext<Self>,
4508 ) {
4509 let snapshot = worktree_handle.read(cx).snapshot();
4510 let mut buffers_to_delete = Vec::new();
4511 let mut renamed_buffers = Vec::new();
4512 for (buffer_id, buffer) in &self.opened_buffers {
4513 if let Some(buffer) = buffer.upgrade(cx) {
4514 buffer.update(cx, |buffer, cx| {
4515 if let Some(old_file) = File::from_dyn(buffer.file()) {
4516 if old_file.worktree != worktree_handle {
4517 return;
4518 }
4519
4520 let new_file = if let Some(entry) = old_file
4521 .entry_id
4522 .and_then(|entry_id| snapshot.entry_for_id(entry_id))
4523 {
4524 File {
4525 is_local: true,
4526 entry_id: Some(entry.id),
4527 mtime: entry.mtime,
4528 path: entry.path.clone(),
4529 worktree: worktree_handle.clone(),
4530 }
4531 } else if let Some(entry) =
4532 snapshot.entry_for_path(old_file.path().as_ref())
4533 {
4534 File {
4535 is_local: true,
4536 entry_id: Some(entry.id),
4537 mtime: entry.mtime,
4538 path: entry.path.clone(),
4539 worktree: worktree_handle.clone(),
4540 }
4541 } else {
4542 File {
4543 is_local: true,
4544 entry_id: None,
4545 path: old_file.path().clone(),
4546 mtime: old_file.mtime(),
4547 worktree: worktree_handle.clone(),
4548 }
4549 };
4550
4551 let old_path = old_file.abs_path(cx);
4552 if new_file.abs_path(cx) != old_path {
4553 renamed_buffers.push((cx.handle(), old_path));
4554 }
4555
4556 if let Some(project_id) = self.shared_remote_id() {
4557 self.client
4558 .send(proto::UpdateBufferFile {
4559 project_id,
4560 buffer_id: *buffer_id as u64,
4561 file: Some(new_file.to_proto()),
4562 })
4563 .log_err();
4564 }
4565 buffer.file_updated(Arc::new(new_file), cx).detach();
4566 }
4567 });
4568 } else {
4569 buffers_to_delete.push(*buffer_id);
4570 }
4571 }
4572
4573 for buffer_id in buffers_to_delete {
4574 self.opened_buffers.remove(&buffer_id);
4575 }
4576
4577 for (buffer, old_path) in renamed_buffers {
4578 self.unregister_buffer_from_language_server(&buffer, old_path, cx);
4579 self.assign_language_to_buffer(&buffer, cx);
4580 self.register_buffer_with_language_server(&buffer, cx);
4581 }
4582 }
4583
4584 pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut ModelContext<Self>) {
4585 let new_active_entry = entry.and_then(|project_path| {
4586 let worktree = self.worktree_for_id(project_path.worktree_id, cx)?;
4587 let entry = worktree.read(cx).entry_for_path(project_path.path)?;
4588 Some(entry.id)
4589 });
4590 if new_active_entry != self.active_entry {
4591 self.active_entry = new_active_entry;
4592 cx.emit(Event::ActiveEntryChanged(new_active_entry));
4593 }
4594 }
4595
4596 pub fn language_servers_running_disk_based_diagnostics<'a>(
4597 &'a self,
4598 ) -> impl 'a + Iterator<Item = usize> {
4599 self.language_server_statuses
4600 .iter()
4601 .filter_map(|(id, status)| {
4602 if status.has_pending_diagnostic_updates {
4603 Some(*id)
4604 } else {
4605 None
4606 }
4607 })
4608 }
4609
4610 pub fn diagnostic_summary(&self, cx: &AppContext) -> DiagnosticSummary {
4611 let mut summary = DiagnosticSummary::default();
4612 for (_, path_summary) in self.diagnostic_summaries(cx) {
4613 summary.error_count += path_summary.error_count;
4614 summary.warning_count += path_summary.warning_count;
4615 }
4616 summary
4617 }
4618
4619 pub fn diagnostic_summaries<'a>(
4620 &'a self,
4621 cx: &'a AppContext,
4622 ) -> impl Iterator<Item = (ProjectPath, DiagnosticSummary)> + 'a {
4623 self.visible_worktrees(cx).flat_map(move |worktree| {
4624 let worktree = worktree.read(cx);
4625 let worktree_id = worktree.id();
4626 worktree
4627 .diagnostic_summaries()
4628 .map(move |(path, summary)| (ProjectPath { worktree_id, path }, summary))
4629 })
4630 }
4631
4632 pub fn disk_based_diagnostics_started(
4633 &mut self,
4634 language_server_id: usize,
4635 cx: &mut ModelContext<Self>,
4636 ) {
4637 cx.emit(Event::DiskBasedDiagnosticsStarted { language_server_id });
4638 }
4639
4640 pub fn disk_based_diagnostics_finished(
4641 &mut self,
4642 language_server_id: usize,
4643 cx: &mut ModelContext<Self>,
4644 ) {
4645 cx.emit(Event::DiskBasedDiagnosticsFinished { language_server_id });
4646 }
4647
4648 pub fn active_entry(&self) -> Option<ProjectEntryId> {
4649 self.active_entry
4650 }
4651
4652 pub fn entry_for_path(&self, path: &ProjectPath, cx: &AppContext) -> Option<ProjectEntryId> {
4653 self.worktree_for_id(path.worktree_id, cx)?
4654 .read(cx)
4655 .entry_for_path(&path.path)
4656 .map(|entry| entry.id)
4657 }
4658
4659 pub fn path_for_entry(&self, entry_id: ProjectEntryId, cx: &AppContext) -> Option<ProjectPath> {
4660 let worktree = self.worktree_for_entry(entry_id, cx)?;
4661 let worktree = worktree.read(cx);
4662 let worktree_id = worktree.id();
4663 let path = worktree.entry_for_id(entry_id)?.path.clone();
4664 Some(ProjectPath { worktree_id, path })
4665 }
4666
4667 // RPC message handlers
4668
4669 async fn handle_request_join_project(
4670 this: ModelHandle<Self>,
4671 message: TypedEnvelope<proto::RequestJoinProject>,
4672 _: Arc<Client>,
4673 mut cx: AsyncAppContext,
4674 ) -> Result<()> {
4675 let user_id = message.payload.requester_id;
4676 if this.read_with(&cx, |project, _| {
4677 project.collaborators.values().any(|c| c.user.id == user_id)
4678 }) {
4679 this.update(&mut cx, |this, cx| {
4680 this.respond_to_join_request(user_id, true, cx)
4681 });
4682 } else {
4683 let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
4684 let user = user_store
4685 .update(&mut cx, |store, cx| store.fetch_user(user_id, cx))
4686 .await?;
4687 this.update(&mut cx, |_, cx| cx.emit(Event::ContactRequestedJoin(user)));
4688 }
4689 Ok(())
4690 }
4691
4692 async fn handle_unregister_project(
4693 this: ModelHandle<Self>,
4694 _: TypedEnvelope<proto::UnregisterProject>,
4695 _: Arc<Client>,
4696 mut cx: AsyncAppContext,
4697 ) -> Result<()> {
4698 this.update(&mut cx, |this, cx| this.removed_from_project(cx));
4699 Ok(())
4700 }
4701
4702 async fn handle_project_unshared(
4703 this: ModelHandle<Self>,
4704 _: TypedEnvelope<proto::ProjectUnshared>,
4705 _: Arc<Client>,
4706 mut cx: AsyncAppContext,
4707 ) -> Result<()> {
4708 this.update(&mut cx, |this, cx| this.unshared(cx));
4709 Ok(())
4710 }
4711
4712 async fn handle_add_collaborator(
4713 this: ModelHandle<Self>,
4714 mut envelope: TypedEnvelope<proto::AddProjectCollaborator>,
4715 _: Arc<Client>,
4716 mut cx: AsyncAppContext,
4717 ) -> Result<()> {
4718 let user_store = this.read_with(&cx, |this, _| this.user_store.clone());
4719 let collaborator = envelope
4720 .payload
4721 .collaborator
4722 .take()
4723 .ok_or_else(|| anyhow!("empty collaborator"))?;
4724
4725 let collaborator = Collaborator::from_proto(collaborator, &user_store, &mut cx).await?;
4726 this.update(&mut cx, |this, cx| {
4727 this.collaborators
4728 .insert(collaborator.peer_id, collaborator);
4729 cx.notify();
4730 });
4731
4732 Ok(())
4733 }
4734
4735 async fn handle_remove_collaborator(
4736 this: ModelHandle<Self>,
4737 envelope: TypedEnvelope<proto::RemoveProjectCollaborator>,
4738 _: Arc<Client>,
4739 mut cx: AsyncAppContext,
4740 ) -> Result<()> {
4741 this.update(&mut cx, |this, cx| {
4742 let peer_id = PeerId(envelope.payload.peer_id);
4743 let replica_id = this
4744 .collaborators
4745 .remove(&peer_id)
4746 .ok_or_else(|| anyhow!("unknown peer {:?}", peer_id))?
4747 .replica_id;
4748 for (_, buffer) in &this.opened_buffers {
4749 if let Some(buffer) = buffer.upgrade(cx) {
4750 buffer.update(cx, |buffer, cx| buffer.remove_peer(replica_id, cx));
4751 }
4752 }
4753
4754 cx.emit(Event::CollaboratorLeft(peer_id));
4755 cx.notify();
4756 Ok(())
4757 })
4758 }
4759
4760 async fn handle_join_project_request_cancelled(
4761 this: ModelHandle<Self>,
4762 envelope: TypedEnvelope<proto::JoinProjectRequestCancelled>,
4763 _: Arc<Client>,
4764 mut cx: AsyncAppContext,
4765 ) -> Result<()> {
4766 let user = this
4767 .update(&mut cx, |this, cx| {
4768 this.user_store.update(cx, |user_store, cx| {
4769 user_store.fetch_user(envelope.payload.requester_id, cx)
4770 })
4771 })
4772 .await?;
4773
4774 this.update(&mut cx, |_, cx| {
4775 cx.emit(Event::ContactCancelledJoinRequest(user));
4776 });
4777
4778 Ok(())
4779 }
4780
4781 async fn handle_update_project(
4782 this: ModelHandle<Self>,
4783 envelope: TypedEnvelope<proto::UpdateProject>,
4784 client: Arc<Client>,
4785 mut cx: AsyncAppContext,
4786 ) -> Result<()> {
4787 this.update(&mut cx, |this, cx| {
4788 let replica_id = this.replica_id();
4789 let remote_id = this.remote_id().ok_or_else(|| anyhow!("invalid project"))?;
4790
4791 let mut old_worktrees_by_id = this
4792 .worktrees
4793 .drain(..)
4794 .filter_map(|worktree| {
4795 let worktree = worktree.upgrade(cx)?;
4796 Some((worktree.read(cx).id(), worktree))
4797 })
4798 .collect::<HashMap<_, _>>();
4799
4800 for worktree in envelope.payload.worktrees {
4801 if let Some(old_worktree) =
4802 old_worktrees_by_id.remove(&WorktreeId::from_proto(worktree.id))
4803 {
4804 this.worktrees.push(WorktreeHandle::Strong(old_worktree));
4805 } else {
4806 let worktree =
4807 Worktree::remote(remote_id, replica_id, worktree, client.clone(), cx);
4808 this.add_worktree(&worktree, cx);
4809 }
4810 }
4811
4812 this.metadata_changed(true, cx);
4813 for (id, _) in old_worktrees_by_id {
4814 cx.emit(Event::WorktreeRemoved(id));
4815 }
4816
4817 Ok(())
4818 })
4819 }
4820
4821 async fn handle_update_worktree(
4822 this: ModelHandle<Self>,
4823 envelope: TypedEnvelope<proto::UpdateWorktree>,
4824 _: Arc<Client>,
4825 mut cx: AsyncAppContext,
4826 ) -> Result<()> {
4827 this.update(&mut cx, |this, cx| {
4828 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4829 if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
4830 worktree.update(cx, |worktree, _| {
4831 let worktree = worktree.as_remote_mut().unwrap();
4832 worktree.update_from_remote(envelope.payload);
4833 });
4834 }
4835 Ok(())
4836 })
4837 }
4838
4839 async fn handle_create_project_entry(
4840 this: ModelHandle<Self>,
4841 envelope: TypedEnvelope<proto::CreateProjectEntry>,
4842 _: Arc<Client>,
4843 mut cx: AsyncAppContext,
4844 ) -> Result<proto::ProjectEntryResponse> {
4845 let worktree = this.update(&mut cx, |this, cx| {
4846 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4847 this.worktree_for_id(worktree_id, cx)
4848 .ok_or_else(|| anyhow!("worktree not found"))
4849 })?;
4850 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4851 let entry = worktree
4852 .update(&mut cx, |worktree, cx| {
4853 let worktree = worktree.as_local_mut().unwrap();
4854 let path = PathBuf::from(OsString::from_vec(envelope.payload.path));
4855 worktree.create_entry(path, envelope.payload.is_directory, cx)
4856 })
4857 .await?;
4858 Ok(proto::ProjectEntryResponse {
4859 entry: Some((&entry).into()),
4860 worktree_scan_id: worktree_scan_id as u64,
4861 })
4862 }
4863
4864 async fn handle_rename_project_entry(
4865 this: ModelHandle<Self>,
4866 envelope: TypedEnvelope<proto::RenameProjectEntry>,
4867 _: Arc<Client>,
4868 mut cx: AsyncAppContext,
4869 ) -> Result<proto::ProjectEntryResponse> {
4870 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4871 let worktree = this.read_with(&cx, |this, cx| {
4872 this.worktree_for_entry(entry_id, cx)
4873 .ok_or_else(|| anyhow!("worktree not found"))
4874 })?;
4875 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4876 let entry = worktree
4877 .update(&mut cx, |worktree, cx| {
4878 let new_path = PathBuf::from(OsString::from_vec(envelope.payload.new_path));
4879 worktree
4880 .as_local_mut()
4881 .unwrap()
4882 .rename_entry(entry_id, new_path, cx)
4883 .ok_or_else(|| anyhow!("invalid entry"))
4884 })?
4885 .await?;
4886 Ok(proto::ProjectEntryResponse {
4887 entry: Some((&entry).into()),
4888 worktree_scan_id: worktree_scan_id as u64,
4889 })
4890 }
4891
4892 async fn handle_copy_project_entry(
4893 this: ModelHandle<Self>,
4894 envelope: TypedEnvelope<proto::CopyProjectEntry>,
4895 _: Arc<Client>,
4896 mut cx: AsyncAppContext,
4897 ) -> Result<proto::ProjectEntryResponse> {
4898 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4899 let worktree = this.read_with(&cx, |this, cx| {
4900 this.worktree_for_entry(entry_id, cx)
4901 .ok_or_else(|| anyhow!("worktree not found"))
4902 })?;
4903 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4904 let entry = worktree
4905 .update(&mut cx, |worktree, cx| {
4906 let new_path = PathBuf::from(OsString::from_vec(envelope.payload.new_path));
4907 worktree
4908 .as_local_mut()
4909 .unwrap()
4910 .copy_entry(entry_id, new_path, cx)
4911 .ok_or_else(|| anyhow!("invalid entry"))
4912 })?
4913 .await?;
4914 Ok(proto::ProjectEntryResponse {
4915 entry: Some((&entry).into()),
4916 worktree_scan_id: worktree_scan_id as u64,
4917 })
4918 }
4919
4920 async fn handle_delete_project_entry(
4921 this: ModelHandle<Self>,
4922 envelope: TypedEnvelope<proto::DeleteProjectEntry>,
4923 _: Arc<Client>,
4924 mut cx: AsyncAppContext,
4925 ) -> Result<proto::ProjectEntryResponse> {
4926 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
4927 let worktree = this.read_with(&cx, |this, cx| {
4928 this.worktree_for_entry(entry_id, cx)
4929 .ok_or_else(|| anyhow!("worktree not found"))
4930 })?;
4931 let worktree_scan_id = worktree.read_with(&cx, |worktree, _| worktree.scan_id());
4932 worktree
4933 .update(&mut cx, |worktree, cx| {
4934 worktree
4935 .as_local_mut()
4936 .unwrap()
4937 .delete_entry(entry_id, cx)
4938 .ok_or_else(|| anyhow!("invalid entry"))
4939 })?
4940 .await?;
4941 Ok(proto::ProjectEntryResponse {
4942 entry: None,
4943 worktree_scan_id: worktree_scan_id as u64,
4944 })
4945 }
4946
4947 async fn handle_update_diagnostic_summary(
4948 this: ModelHandle<Self>,
4949 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
4950 _: Arc<Client>,
4951 mut cx: AsyncAppContext,
4952 ) -> Result<()> {
4953 this.update(&mut cx, |this, cx| {
4954 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
4955 if let Some(worktree) = this.worktree_for_id(worktree_id, cx) {
4956 if let Some(summary) = envelope.payload.summary {
4957 let project_path = ProjectPath {
4958 worktree_id,
4959 path: Path::new(&summary.path).into(),
4960 };
4961 worktree.update(cx, |worktree, _| {
4962 worktree
4963 .as_remote_mut()
4964 .unwrap()
4965 .update_diagnostic_summary(project_path.path.clone(), &summary);
4966 });
4967 cx.emit(Event::DiagnosticsUpdated {
4968 language_server_id: summary.language_server_id as usize,
4969 path: project_path,
4970 });
4971 }
4972 }
4973 Ok(())
4974 })
4975 }
4976
4977 async fn handle_start_language_server(
4978 this: ModelHandle<Self>,
4979 envelope: TypedEnvelope<proto::StartLanguageServer>,
4980 _: Arc<Client>,
4981 mut cx: AsyncAppContext,
4982 ) -> Result<()> {
4983 let server = envelope
4984 .payload
4985 .server
4986 .ok_or_else(|| anyhow!("invalid server"))?;
4987 this.update(&mut cx, |this, cx| {
4988 this.language_server_statuses.insert(
4989 server.id as usize,
4990 LanguageServerStatus {
4991 name: server.name,
4992 pending_work: Default::default(),
4993 has_pending_diagnostic_updates: false,
4994 progress_tokens: Default::default(),
4995 },
4996 );
4997 cx.notify();
4998 });
4999 Ok(())
5000 }
5001
5002 async fn handle_update_language_server(
5003 this: ModelHandle<Self>,
5004 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
5005 _: Arc<Client>,
5006 mut cx: AsyncAppContext,
5007 ) -> Result<()> {
5008 let language_server_id = envelope.payload.language_server_id as usize;
5009 match envelope
5010 .payload
5011 .variant
5012 .ok_or_else(|| anyhow!("invalid variant"))?
5013 {
5014 proto::update_language_server::Variant::WorkStart(payload) => {
5015 this.update(&mut cx, |this, cx| {
5016 this.on_lsp_work_start(
5017 language_server_id,
5018 payload.token,
5019 LanguageServerProgress {
5020 message: payload.message,
5021 percentage: payload.percentage.map(|p| p as usize),
5022 last_update_at: Instant::now(),
5023 },
5024 cx,
5025 );
5026 })
5027 }
5028 proto::update_language_server::Variant::WorkProgress(payload) => {
5029 this.update(&mut cx, |this, cx| {
5030 this.on_lsp_work_progress(
5031 language_server_id,
5032 payload.token,
5033 LanguageServerProgress {
5034 message: payload.message,
5035 percentage: payload.percentage.map(|p| p as usize),
5036 last_update_at: Instant::now(),
5037 },
5038 cx,
5039 );
5040 })
5041 }
5042 proto::update_language_server::Variant::WorkEnd(payload) => {
5043 this.update(&mut cx, |this, cx| {
5044 this.on_lsp_work_end(language_server_id, payload.token, cx);
5045 })
5046 }
5047 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
5048 this.update(&mut cx, |this, cx| {
5049 this.disk_based_diagnostics_started(language_server_id, cx);
5050 })
5051 }
5052 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
5053 this.update(&mut cx, |this, cx| {
5054 this.disk_based_diagnostics_finished(language_server_id, cx)
5055 });
5056 }
5057 }
5058
5059 Ok(())
5060 }
5061
5062 async fn handle_update_buffer(
5063 this: ModelHandle<Self>,
5064 envelope: TypedEnvelope<proto::UpdateBuffer>,
5065 _: Arc<Client>,
5066 mut cx: AsyncAppContext,
5067 ) -> Result<()> {
5068 this.update(&mut cx, |this, cx| {
5069 let payload = envelope.payload.clone();
5070 let buffer_id = payload.buffer_id;
5071 let ops = payload
5072 .operations
5073 .into_iter()
5074 .map(|op| language::proto::deserialize_operation(op))
5075 .collect::<Result<Vec<_>, _>>()?;
5076 let is_remote = this.is_remote();
5077 match this.opened_buffers.entry(buffer_id) {
5078 hash_map::Entry::Occupied(mut e) => match e.get_mut() {
5079 OpenBuffer::Strong(buffer) => {
5080 buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
5081 }
5082 OpenBuffer::Loading(operations) => operations.extend_from_slice(&ops),
5083 OpenBuffer::Weak(_) => {}
5084 },
5085 hash_map::Entry::Vacant(e) => {
5086 assert!(
5087 is_remote,
5088 "received buffer update from {:?}",
5089 envelope.original_sender_id
5090 );
5091 e.insert(OpenBuffer::Loading(ops));
5092 }
5093 }
5094 Ok(())
5095 })
5096 }
5097
5098 async fn handle_update_buffer_file(
5099 this: ModelHandle<Self>,
5100 envelope: TypedEnvelope<proto::UpdateBufferFile>,
5101 _: Arc<Client>,
5102 mut cx: AsyncAppContext,
5103 ) -> Result<()> {
5104 this.update(&mut cx, |this, cx| {
5105 let payload = envelope.payload.clone();
5106 let buffer_id = payload.buffer_id;
5107 let file = payload.file.ok_or_else(|| anyhow!("invalid file"))?;
5108 let worktree = this
5109 .worktree_for_id(WorktreeId::from_proto(file.worktree_id), cx)
5110 .ok_or_else(|| anyhow!("no such worktree"))?;
5111 let file = File::from_proto(file, worktree.clone(), cx)?;
5112 let buffer = this
5113 .opened_buffers
5114 .get_mut(&buffer_id)
5115 .and_then(|b| b.upgrade(cx))
5116 .ok_or_else(|| anyhow!("no such buffer"))?;
5117 buffer.update(cx, |buffer, cx| {
5118 buffer.file_updated(Arc::new(file), cx).detach();
5119 });
5120 Ok(())
5121 })
5122 }
5123
5124 async fn handle_save_buffer(
5125 this: ModelHandle<Self>,
5126 envelope: TypedEnvelope<proto::SaveBuffer>,
5127 _: Arc<Client>,
5128 mut cx: AsyncAppContext,
5129 ) -> Result<proto::BufferSaved> {
5130 let buffer_id = envelope.payload.buffer_id;
5131 let requested_version = deserialize_version(envelope.payload.version);
5132
5133 let (project_id, buffer) = this.update(&mut cx, |this, cx| {
5134 let project_id = this.remote_id().ok_or_else(|| anyhow!("not connected"))?;
5135 let buffer = this
5136 .opened_buffers
5137 .get(&buffer_id)
5138 .and_then(|buffer| buffer.upgrade(cx))
5139 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?;
5140 Ok::<_, anyhow::Error>((project_id, buffer))
5141 })?;
5142 buffer
5143 .update(&mut cx, |buffer, _| {
5144 buffer.wait_for_version(requested_version)
5145 })
5146 .await;
5147
5148 let (saved_version, fingerprint, mtime) =
5149 buffer.update(&mut cx, |buffer, cx| buffer.save(cx)).await?;
5150 Ok(proto::BufferSaved {
5151 project_id,
5152 buffer_id,
5153 version: serialize_version(&saved_version),
5154 mtime: Some(mtime.into()),
5155 fingerprint,
5156 })
5157 }
5158
5159 async fn handle_reload_buffers(
5160 this: ModelHandle<Self>,
5161 envelope: TypedEnvelope<proto::ReloadBuffers>,
5162 _: Arc<Client>,
5163 mut cx: AsyncAppContext,
5164 ) -> Result<proto::ReloadBuffersResponse> {
5165 let sender_id = envelope.original_sender_id()?;
5166 let reload = this.update(&mut cx, |this, cx| {
5167 let mut buffers = HashSet::default();
5168 for buffer_id in &envelope.payload.buffer_ids {
5169 buffers.insert(
5170 this.opened_buffers
5171 .get(buffer_id)
5172 .and_then(|buffer| buffer.upgrade(cx))
5173 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
5174 );
5175 }
5176 Ok::<_, anyhow::Error>(this.reload_buffers(buffers, false, cx))
5177 })?;
5178
5179 let project_transaction = reload.await?;
5180 let project_transaction = this.update(&mut cx, |this, cx| {
5181 this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5182 });
5183 Ok(proto::ReloadBuffersResponse {
5184 transaction: Some(project_transaction),
5185 })
5186 }
5187
5188 async fn handle_format_buffers(
5189 this: ModelHandle<Self>,
5190 envelope: TypedEnvelope<proto::FormatBuffers>,
5191 _: Arc<Client>,
5192 mut cx: AsyncAppContext,
5193 ) -> Result<proto::FormatBuffersResponse> {
5194 let sender_id = envelope.original_sender_id()?;
5195 let format = this.update(&mut cx, |this, cx| {
5196 let mut buffers = HashSet::default();
5197 for buffer_id in &envelope.payload.buffer_ids {
5198 buffers.insert(
5199 this.opened_buffers
5200 .get(buffer_id)
5201 .and_then(|buffer| buffer.upgrade(cx))
5202 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))?,
5203 );
5204 }
5205 Ok::<_, anyhow::Error>(this.format(buffers, false, cx))
5206 })?;
5207
5208 let project_transaction = format.await?;
5209 let project_transaction = this.update(&mut cx, |this, cx| {
5210 this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5211 });
5212 Ok(proto::FormatBuffersResponse {
5213 transaction: Some(project_transaction),
5214 })
5215 }
5216
5217 async fn handle_get_completions(
5218 this: ModelHandle<Self>,
5219 envelope: TypedEnvelope<proto::GetCompletions>,
5220 _: Arc<Client>,
5221 mut cx: AsyncAppContext,
5222 ) -> Result<proto::GetCompletionsResponse> {
5223 let position = envelope
5224 .payload
5225 .position
5226 .and_then(language::proto::deserialize_anchor)
5227 .ok_or_else(|| anyhow!("invalid position"))?;
5228 let version = deserialize_version(envelope.payload.version);
5229 let buffer = this.read_with(&cx, |this, cx| {
5230 this.opened_buffers
5231 .get(&envelope.payload.buffer_id)
5232 .and_then(|buffer| buffer.upgrade(cx))
5233 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
5234 })?;
5235 buffer
5236 .update(&mut cx, |buffer, _| buffer.wait_for_version(version))
5237 .await;
5238 let version = buffer.read_with(&cx, |buffer, _| buffer.version());
5239 let completions = this
5240 .update(&mut cx, |this, cx| this.completions(&buffer, position, cx))
5241 .await?;
5242
5243 Ok(proto::GetCompletionsResponse {
5244 completions: completions
5245 .iter()
5246 .map(language::proto::serialize_completion)
5247 .collect(),
5248 version: serialize_version(&version),
5249 })
5250 }
5251
5252 async fn handle_apply_additional_edits_for_completion(
5253 this: ModelHandle<Self>,
5254 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
5255 _: Arc<Client>,
5256 mut cx: AsyncAppContext,
5257 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
5258 let (buffer, completion) = this.update(&mut cx, |this, cx| {
5259 let buffer = this
5260 .opened_buffers
5261 .get(&envelope.payload.buffer_id)
5262 .and_then(|buffer| buffer.upgrade(cx))
5263 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
5264 let language = buffer.read(cx).language();
5265 let completion = language::proto::deserialize_completion(
5266 envelope
5267 .payload
5268 .completion
5269 .ok_or_else(|| anyhow!("invalid completion"))?,
5270 language.cloned(),
5271 );
5272 Ok::<_, anyhow::Error>((buffer, completion))
5273 })?;
5274
5275 let completion = completion.await?;
5276
5277 let apply_additional_edits = this.update(&mut cx, |this, cx| {
5278 this.apply_additional_edits_for_completion(buffer, completion, false, cx)
5279 });
5280
5281 Ok(proto::ApplyCompletionAdditionalEditsResponse {
5282 transaction: apply_additional_edits
5283 .await?
5284 .as_ref()
5285 .map(language::proto::serialize_transaction),
5286 })
5287 }
5288
5289 async fn handle_get_code_actions(
5290 this: ModelHandle<Self>,
5291 envelope: TypedEnvelope<proto::GetCodeActions>,
5292 _: Arc<Client>,
5293 mut cx: AsyncAppContext,
5294 ) -> Result<proto::GetCodeActionsResponse> {
5295 let start = envelope
5296 .payload
5297 .start
5298 .and_then(language::proto::deserialize_anchor)
5299 .ok_or_else(|| anyhow!("invalid start"))?;
5300 let end = envelope
5301 .payload
5302 .end
5303 .and_then(language::proto::deserialize_anchor)
5304 .ok_or_else(|| anyhow!("invalid end"))?;
5305 let buffer = this.update(&mut cx, |this, cx| {
5306 this.opened_buffers
5307 .get(&envelope.payload.buffer_id)
5308 .and_then(|buffer| buffer.upgrade(cx))
5309 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))
5310 })?;
5311 buffer
5312 .update(&mut cx, |buffer, _| {
5313 buffer.wait_for_version(deserialize_version(envelope.payload.version))
5314 })
5315 .await;
5316
5317 let version = buffer.read_with(&cx, |buffer, _| buffer.version());
5318 let code_actions = this.update(&mut cx, |this, cx| {
5319 Ok::<_, anyhow::Error>(this.code_actions(&buffer, start..end, cx))
5320 })?;
5321
5322 Ok(proto::GetCodeActionsResponse {
5323 actions: code_actions
5324 .await?
5325 .iter()
5326 .map(language::proto::serialize_code_action)
5327 .collect(),
5328 version: serialize_version(&version),
5329 })
5330 }
5331
5332 async fn handle_apply_code_action(
5333 this: ModelHandle<Self>,
5334 envelope: TypedEnvelope<proto::ApplyCodeAction>,
5335 _: Arc<Client>,
5336 mut cx: AsyncAppContext,
5337 ) -> Result<proto::ApplyCodeActionResponse> {
5338 let sender_id = envelope.original_sender_id()?;
5339 let action = language::proto::deserialize_code_action(
5340 envelope
5341 .payload
5342 .action
5343 .ok_or_else(|| anyhow!("invalid action"))?,
5344 )?;
5345 let apply_code_action = this.update(&mut cx, |this, cx| {
5346 let buffer = this
5347 .opened_buffers
5348 .get(&envelope.payload.buffer_id)
5349 .and_then(|buffer| buffer.upgrade(cx))
5350 .ok_or_else(|| anyhow!("unknown buffer id {}", envelope.payload.buffer_id))?;
5351 Ok::<_, anyhow::Error>(this.apply_code_action(buffer, action, false, cx))
5352 })?;
5353
5354 let project_transaction = apply_code_action.await?;
5355 let project_transaction = this.update(&mut cx, |this, cx| {
5356 this.serialize_project_transaction_for_peer(project_transaction, sender_id, cx)
5357 });
5358 Ok(proto::ApplyCodeActionResponse {
5359 transaction: Some(project_transaction),
5360 })
5361 }
5362
5363 async fn handle_lsp_command<T: LspCommand>(
5364 this: ModelHandle<Self>,
5365 envelope: TypedEnvelope<T::ProtoRequest>,
5366 _: Arc<Client>,
5367 mut cx: AsyncAppContext,
5368 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
5369 where
5370 <T::LspRequest as lsp::request::Request>::Result: Send,
5371 {
5372 let sender_id = envelope.original_sender_id()?;
5373 let buffer_id = T::buffer_id_from_proto(&envelope.payload);
5374 let buffer_handle = this.read_with(&cx, |this, _| {
5375 this.opened_buffers
5376 .get(&buffer_id)
5377 .and_then(|buffer| buffer.upgrade(&cx))
5378 .ok_or_else(|| anyhow!("unknown buffer id {}", buffer_id))
5379 })?;
5380 let request = T::from_proto(
5381 envelope.payload,
5382 this.clone(),
5383 buffer_handle.clone(),
5384 cx.clone(),
5385 )
5386 .await?;
5387 let buffer_version = buffer_handle.read_with(&cx, |buffer, _| buffer.version());
5388 let response = this
5389 .update(&mut cx, |this, cx| {
5390 this.request_lsp(buffer_handle, request, cx)
5391 })
5392 .await?;
5393 this.update(&mut cx, |this, cx| {
5394 Ok(T::response_to_proto(
5395 response,
5396 this,
5397 sender_id,
5398 &buffer_version,
5399 cx,
5400 ))
5401 })
5402 }
5403
5404 async fn handle_get_project_symbols(
5405 this: ModelHandle<Self>,
5406 envelope: TypedEnvelope<proto::GetProjectSymbols>,
5407 _: Arc<Client>,
5408 mut cx: AsyncAppContext,
5409 ) -> Result<proto::GetProjectSymbolsResponse> {
5410 let symbols = this
5411 .update(&mut cx, |this, cx| {
5412 this.symbols(&envelope.payload.query, cx)
5413 })
5414 .await?;
5415
5416 Ok(proto::GetProjectSymbolsResponse {
5417 symbols: symbols.iter().map(serialize_symbol).collect(),
5418 })
5419 }
5420
5421 async fn handle_search_project(
5422 this: ModelHandle<Self>,
5423 envelope: TypedEnvelope<proto::SearchProject>,
5424 _: Arc<Client>,
5425 mut cx: AsyncAppContext,
5426 ) -> Result<proto::SearchProjectResponse> {
5427 let peer_id = envelope.original_sender_id()?;
5428 let query = SearchQuery::from_proto(envelope.payload)?;
5429 let result = this
5430 .update(&mut cx, |this, cx| this.search(query, cx))
5431 .await?;
5432
5433 this.update(&mut cx, |this, cx| {
5434 let mut locations = Vec::new();
5435 for (buffer, ranges) in result {
5436 for range in ranges {
5437 let start = serialize_anchor(&range.start);
5438 let end = serialize_anchor(&range.end);
5439 let buffer = this.serialize_buffer_for_peer(&buffer, peer_id, cx);
5440 locations.push(proto::Location {
5441 buffer: Some(buffer),
5442 start: Some(start),
5443 end: Some(end),
5444 });
5445 }
5446 }
5447 Ok(proto::SearchProjectResponse { locations })
5448 })
5449 }
5450
5451 async fn handle_open_buffer_for_symbol(
5452 this: ModelHandle<Self>,
5453 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
5454 _: Arc<Client>,
5455 mut cx: AsyncAppContext,
5456 ) -> Result<proto::OpenBufferForSymbolResponse> {
5457 let peer_id = envelope.original_sender_id()?;
5458 let symbol = envelope
5459 .payload
5460 .symbol
5461 .ok_or_else(|| anyhow!("invalid symbol"))?;
5462 let symbol = this
5463 .read_with(&cx, |this, _| this.deserialize_symbol(symbol))
5464 .await?;
5465 let symbol = this.read_with(&cx, |this, _| {
5466 let signature = this.symbol_signature(symbol.worktree_id, &symbol.path);
5467 if signature == symbol.signature {
5468 Ok(symbol)
5469 } else {
5470 Err(anyhow!("invalid symbol signature"))
5471 }
5472 })?;
5473 let buffer = this
5474 .update(&mut cx, |this, cx| this.open_buffer_for_symbol(&symbol, cx))
5475 .await?;
5476
5477 Ok(proto::OpenBufferForSymbolResponse {
5478 buffer: Some(this.update(&mut cx, |this, cx| {
5479 this.serialize_buffer_for_peer(&buffer, peer_id, cx)
5480 })),
5481 })
5482 }
5483
5484 fn symbol_signature(&self, worktree_id: WorktreeId, path: &Path) -> [u8; 32] {
5485 let mut hasher = Sha256::new();
5486 hasher.update(worktree_id.to_proto().to_be_bytes());
5487 hasher.update(path.to_string_lossy().as_bytes());
5488 hasher.update(self.nonce.to_be_bytes());
5489 hasher.finalize().as_slice().try_into().unwrap()
5490 }
5491
5492 async fn handle_open_buffer_by_id(
5493 this: ModelHandle<Self>,
5494 envelope: TypedEnvelope<proto::OpenBufferById>,
5495 _: Arc<Client>,
5496 mut cx: AsyncAppContext,
5497 ) -> Result<proto::OpenBufferResponse> {
5498 let peer_id = envelope.original_sender_id()?;
5499 let buffer = this
5500 .update(&mut cx, |this, cx| {
5501 this.open_buffer_by_id(envelope.payload.id, cx)
5502 })
5503 .await?;
5504 this.update(&mut cx, |this, cx| {
5505 Ok(proto::OpenBufferResponse {
5506 buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
5507 })
5508 })
5509 }
5510
5511 async fn handle_open_buffer_by_path(
5512 this: ModelHandle<Self>,
5513 envelope: TypedEnvelope<proto::OpenBufferByPath>,
5514 _: Arc<Client>,
5515 mut cx: AsyncAppContext,
5516 ) -> Result<proto::OpenBufferResponse> {
5517 let peer_id = envelope.original_sender_id()?;
5518 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
5519 let open_buffer = this.update(&mut cx, |this, cx| {
5520 this.open_buffer(
5521 ProjectPath {
5522 worktree_id,
5523 path: PathBuf::from(envelope.payload.path).into(),
5524 },
5525 cx,
5526 )
5527 });
5528
5529 let buffer = open_buffer.await?;
5530 this.update(&mut cx, |this, cx| {
5531 Ok(proto::OpenBufferResponse {
5532 buffer: Some(this.serialize_buffer_for_peer(&buffer, peer_id, cx)),
5533 })
5534 })
5535 }
5536
5537 fn serialize_project_transaction_for_peer(
5538 &mut self,
5539 project_transaction: ProjectTransaction,
5540 peer_id: PeerId,
5541 cx: &AppContext,
5542 ) -> proto::ProjectTransaction {
5543 let mut serialized_transaction = proto::ProjectTransaction {
5544 buffers: Default::default(),
5545 transactions: Default::default(),
5546 };
5547 for (buffer, transaction) in project_transaction.0 {
5548 serialized_transaction
5549 .buffers
5550 .push(self.serialize_buffer_for_peer(&buffer, peer_id, cx));
5551 serialized_transaction
5552 .transactions
5553 .push(language::proto::serialize_transaction(&transaction));
5554 }
5555 serialized_transaction
5556 }
5557
5558 fn deserialize_project_transaction(
5559 &mut self,
5560 message: proto::ProjectTransaction,
5561 push_to_history: bool,
5562 cx: &mut ModelContext<Self>,
5563 ) -> Task<Result<ProjectTransaction>> {
5564 cx.spawn(|this, mut cx| async move {
5565 let mut project_transaction = ProjectTransaction::default();
5566 for (buffer, transaction) in message.buffers.into_iter().zip(message.transactions) {
5567 let buffer = this
5568 .update(&mut cx, |this, cx| this.deserialize_buffer(buffer, cx))
5569 .await?;
5570 let transaction = language::proto::deserialize_transaction(transaction)?;
5571 project_transaction.0.insert(buffer, transaction);
5572 }
5573
5574 for (buffer, transaction) in &project_transaction.0 {
5575 buffer
5576 .update(&mut cx, |buffer, _| {
5577 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
5578 })
5579 .await;
5580
5581 if push_to_history {
5582 buffer.update(&mut cx, |buffer, _| {
5583 buffer.push_transaction(transaction.clone(), Instant::now());
5584 });
5585 }
5586 }
5587
5588 Ok(project_transaction)
5589 })
5590 }
5591
5592 fn serialize_buffer_for_peer(
5593 &mut self,
5594 buffer: &ModelHandle<Buffer>,
5595 peer_id: PeerId,
5596 cx: &AppContext,
5597 ) -> proto::Buffer {
5598 let buffer_id = buffer.read(cx).remote_id();
5599 let shared_buffers = self.shared_buffers.entry(peer_id).or_default();
5600 if shared_buffers.insert(buffer_id) {
5601 proto::Buffer {
5602 variant: Some(proto::buffer::Variant::State(buffer.read(cx).to_proto())),
5603 }
5604 } else {
5605 proto::Buffer {
5606 variant: Some(proto::buffer::Variant::Id(buffer_id)),
5607 }
5608 }
5609 }
5610
5611 fn deserialize_buffer(
5612 &mut self,
5613 buffer: proto::Buffer,
5614 cx: &mut ModelContext<Self>,
5615 ) -> Task<Result<ModelHandle<Buffer>>> {
5616 let replica_id = self.replica_id();
5617
5618 let opened_buffer_tx = self.opened_buffer.0.clone();
5619 let mut opened_buffer_rx = self.opened_buffer.1.clone();
5620 cx.spawn(|this, mut cx| async move {
5621 match buffer.variant.ok_or_else(|| anyhow!("missing buffer"))? {
5622 proto::buffer::Variant::Id(id) => {
5623 let buffer = loop {
5624 let buffer = this.read_with(&cx, |this, cx| {
5625 this.opened_buffers
5626 .get(&id)
5627 .and_then(|buffer| buffer.upgrade(cx))
5628 });
5629 if let Some(buffer) = buffer {
5630 break buffer;
5631 }
5632 opened_buffer_rx
5633 .next()
5634 .await
5635 .ok_or_else(|| anyhow!("project dropped while waiting for buffer"))?;
5636 };
5637 Ok(buffer)
5638 }
5639 proto::buffer::Variant::State(mut buffer) => {
5640 let mut buffer_worktree = None;
5641 let mut buffer_file = None;
5642 if let Some(file) = buffer.file.take() {
5643 this.read_with(&cx, |this, cx| {
5644 let worktree_id = WorktreeId::from_proto(file.worktree_id);
5645 let worktree =
5646 this.worktree_for_id(worktree_id, cx).ok_or_else(|| {
5647 anyhow!("no worktree found for id {}", file.worktree_id)
5648 })?;
5649 buffer_file =
5650 Some(Arc::new(File::from_proto(file, worktree.clone(), cx)?)
5651 as Arc<dyn language::File>);
5652 buffer_worktree = Some(worktree);
5653 Ok::<_, anyhow::Error>(())
5654 })?;
5655 }
5656
5657 let buffer = cx.add_model(|cx| {
5658 Buffer::from_proto(replica_id, buffer, buffer_file, cx).unwrap()
5659 });
5660
5661 this.update(&mut cx, |this, cx| this.register_buffer(&buffer, cx))?;
5662
5663 *opened_buffer_tx.borrow_mut().borrow_mut() = ();
5664 Ok(buffer)
5665 }
5666 }
5667 })
5668 }
5669
5670 fn deserialize_symbol(
5671 &self,
5672 serialized_symbol: proto::Symbol,
5673 ) -> impl Future<Output = Result<Symbol>> {
5674 let languages = self.languages.clone();
5675 async move {
5676 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
5677 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
5678 let start = serialized_symbol
5679 .start
5680 .ok_or_else(|| anyhow!("invalid start"))?;
5681 let end = serialized_symbol
5682 .end
5683 .ok_or_else(|| anyhow!("invalid end"))?;
5684 let kind = unsafe { mem::transmute(serialized_symbol.kind) };
5685 let path = PathBuf::from(serialized_symbol.path);
5686 let language = languages.select_language(&path);
5687 Ok(Symbol {
5688 source_worktree_id,
5689 worktree_id,
5690 language_server_name: LanguageServerName(
5691 serialized_symbol.language_server_name.into(),
5692 ),
5693 label: {
5694 match language {
5695 Some(language) => {
5696 language
5697 .label_for_symbol(&serialized_symbol.name, kind)
5698 .await
5699 }
5700 None => None,
5701 }
5702 .unwrap_or_else(|| CodeLabel::plain(serialized_symbol.name.clone(), None))
5703 },
5704
5705 name: serialized_symbol.name,
5706 path,
5707 range: PointUtf16::new(start.row, start.column)
5708 ..PointUtf16::new(end.row, end.column),
5709 kind,
5710 signature: serialized_symbol
5711 .signature
5712 .try_into()
5713 .map_err(|_| anyhow!("invalid signature"))?,
5714 })
5715 }
5716 }
5717
5718 async fn handle_buffer_saved(
5719 this: ModelHandle<Self>,
5720 envelope: TypedEnvelope<proto::BufferSaved>,
5721 _: Arc<Client>,
5722 mut cx: AsyncAppContext,
5723 ) -> Result<()> {
5724 let version = deserialize_version(envelope.payload.version);
5725 let mtime = envelope
5726 .payload
5727 .mtime
5728 .ok_or_else(|| anyhow!("missing mtime"))?
5729 .into();
5730
5731 this.update(&mut cx, |this, cx| {
5732 let buffer = this
5733 .opened_buffers
5734 .get(&envelope.payload.buffer_id)
5735 .and_then(|buffer| buffer.upgrade(cx));
5736 if let Some(buffer) = buffer {
5737 buffer.update(cx, |buffer, cx| {
5738 buffer.did_save(version, envelope.payload.fingerprint, mtime, None, cx);
5739 });
5740 }
5741 Ok(())
5742 })
5743 }
5744
5745 async fn handle_buffer_reloaded(
5746 this: ModelHandle<Self>,
5747 envelope: TypedEnvelope<proto::BufferReloaded>,
5748 _: Arc<Client>,
5749 mut cx: AsyncAppContext,
5750 ) -> Result<()> {
5751 let payload = envelope.payload;
5752 let version = deserialize_version(payload.version);
5753 let line_ending = deserialize_line_ending(
5754 proto::LineEnding::from_i32(payload.line_ending)
5755 .ok_or_else(|| anyhow!("missing line ending"))?,
5756 );
5757 let mtime = payload
5758 .mtime
5759 .ok_or_else(|| anyhow!("missing mtime"))?
5760 .into();
5761 this.update(&mut cx, |this, cx| {
5762 let buffer = this
5763 .opened_buffers
5764 .get(&payload.buffer_id)
5765 .and_then(|buffer| buffer.upgrade(cx));
5766 if let Some(buffer) = buffer {
5767 buffer.update(cx, |buffer, cx| {
5768 buffer.did_reload(version, payload.fingerprint, line_ending, mtime, cx);
5769 });
5770 }
5771 Ok(())
5772 })
5773 }
5774
5775 pub fn match_paths<'a>(
5776 &self,
5777 query: &'a str,
5778 include_ignored: bool,
5779 smart_case: bool,
5780 max_results: usize,
5781 cancel_flag: &'a AtomicBool,
5782 cx: &AppContext,
5783 ) -> impl 'a + Future<Output = Vec<PathMatch>> {
5784 let worktrees = self
5785 .worktrees(cx)
5786 .filter(|worktree| worktree.read(cx).is_visible())
5787 .collect::<Vec<_>>();
5788 let include_root_name = worktrees.len() > 1;
5789 let candidate_sets = worktrees
5790 .into_iter()
5791 .map(|worktree| CandidateSet {
5792 snapshot: worktree.read(cx).snapshot(),
5793 include_ignored,
5794 include_root_name,
5795 })
5796 .collect::<Vec<_>>();
5797
5798 let background = cx.background().clone();
5799 async move {
5800 fuzzy::match_paths(
5801 candidate_sets.as_slice(),
5802 query,
5803 smart_case,
5804 max_results,
5805 cancel_flag,
5806 background,
5807 )
5808 .await
5809 }
5810 }
5811
5812 fn edits_from_lsp(
5813 &mut self,
5814 buffer: &ModelHandle<Buffer>,
5815 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
5816 version: Option<i32>,
5817 cx: &mut ModelContext<Self>,
5818 ) -> Task<Result<Vec<(Range<Anchor>, String)>>> {
5819 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, version, cx);
5820 cx.background().spawn(async move {
5821 let snapshot = snapshot?;
5822 let mut lsp_edits = lsp_edits
5823 .into_iter()
5824 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
5825 .collect::<Vec<_>>();
5826 lsp_edits.sort_by_key(|(range, _)| range.start);
5827
5828 let mut lsp_edits = lsp_edits.into_iter().peekable();
5829 let mut edits = Vec::new();
5830 while let Some((mut range, mut new_text)) = lsp_edits.next() {
5831 // Combine any LSP edits that are adjacent.
5832 //
5833 // Also, combine LSP edits that are separated from each other by only
5834 // a newline. This is important because for some code actions,
5835 // Rust-analyzer rewrites the entire buffer via a series of edits that
5836 // are separated by unchanged newline characters.
5837 //
5838 // In order for the diffing logic below to work properly, any edits that
5839 // cancel each other out must be combined into one.
5840 while let Some((next_range, next_text)) = lsp_edits.peek() {
5841 if next_range.start > range.end {
5842 if next_range.start.row > range.end.row + 1
5843 || next_range.start.column > 0
5844 || snapshot.clip_point_utf16(
5845 PointUtf16::new(range.end.row, u32::MAX),
5846 Bias::Left,
5847 ) > range.end
5848 {
5849 break;
5850 }
5851 new_text.push('\n');
5852 }
5853 range.end = next_range.end;
5854 new_text.push_str(&next_text);
5855 lsp_edits.next();
5856 }
5857
5858 if snapshot.clip_point_utf16(range.start, Bias::Left) != range.start
5859 || snapshot.clip_point_utf16(range.end, Bias::Left) != range.end
5860 {
5861 return Err(anyhow!("invalid edits received from language server"));
5862 }
5863
5864 // For multiline edits, perform a diff of the old and new text so that
5865 // we can identify the changes more precisely, preserving the locations
5866 // of any anchors positioned in the unchanged regions.
5867 if range.end.row > range.start.row {
5868 let mut offset = range.start.to_offset(&snapshot);
5869 let old_text = snapshot.text_for_range(range).collect::<String>();
5870
5871 let diff = TextDiff::from_lines(old_text.as_str(), &new_text);
5872 let mut moved_since_edit = true;
5873 for change in diff.iter_all_changes() {
5874 let tag = change.tag();
5875 let value = change.value();
5876 match tag {
5877 ChangeTag::Equal => {
5878 offset += value.len();
5879 moved_since_edit = true;
5880 }
5881 ChangeTag::Delete => {
5882 let start = snapshot.anchor_after(offset);
5883 let end = snapshot.anchor_before(offset + value.len());
5884 if moved_since_edit {
5885 edits.push((start..end, String::new()));
5886 } else {
5887 edits.last_mut().unwrap().0.end = end;
5888 }
5889 offset += value.len();
5890 moved_since_edit = false;
5891 }
5892 ChangeTag::Insert => {
5893 if moved_since_edit {
5894 let anchor = snapshot.anchor_after(offset);
5895 edits.push((anchor.clone()..anchor, value.to_string()));
5896 } else {
5897 edits.last_mut().unwrap().1.push_str(value);
5898 }
5899 moved_since_edit = false;
5900 }
5901 }
5902 }
5903 } else if range.end == range.start {
5904 let anchor = snapshot.anchor_after(range.start);
5905 edits.push((anchor.clone()..anchor, new_text));
5906 } else {
5907 let edit_start = snapshot.anchor_after(range.start);
5908 let edit_end = snapshot.anchor_before(range.end);
5909 edits.push((edit_start..edit_end, new_text));
5910 }
5911 }
5912
5913 Ok(edits)
5914 })
5915 }
5916
5917 fn buffer_snapshot_for_lsp_version(
5918 &mut self,
5919 buffer: &ModelHandle<Buffer>,
5920 version: Option<i32>,
5921 cx: &AppContext,
5922 ) -> Result<TextBufferSnapshot> {
5923 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
5924
5925 if let Some(version) = version {
5926 let buffer_id = buffer.read(cx).remote_id();
5927 let snapshots = self
5928 .buffer_snapshots
5929 .get_mut(&buffer_id)
5930 .ok_or_else(|| anyhow!("no snapshot found for buffer {}", buffer_id))?;
5931 let mut found_snapshot = None;
5932 snapshots.retain(|(snapshot_version, snapshot)| {
5933 if snapshot_version + OLD_VERSIONS_TO_RETAIN < version {
5934 false
5935 } else {
5936 if *snapshot_version == version {
5937 found_snapshot = Some(snapshot.clone());
5938 }
5939 true
5940 }
5941 });
5942
5943 found_snapshot.ok_or_else(|| {
5944 anyhow!(
5945 "snapshot not found for buffer {} at version {}",
5946 buffer_id,
5947 version
5948 )
5949 })
5950 } else {
5951 Ok((buffer.read(cx)).text_snapshot())
5952 }
5953 }
5954
5955 fn language_server_for_buffer(
5956 &self,
5957 buffer: &Buffer,
5958 cx: &AppContext,
5959 ) -> Option<(&Arc<LspAdapter>, &Arc<LanguageServer>)> {
5960 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
5961 let name = language.lsp_adapter()?.name.clone();
5962 let worktree_id = file.worktree_id(cx);
5963 let key = (worktree_id, name);
5964
5965 if let Some(server_id) = self.language_server_ids.get(&key) {
5966 if let Some(LanguageServerState::Running { adapter, server }) =
5967 self.language_servers.get(&server_id)
5968 {
5969 return Some((adapter, server));
5970 }
5971 }
5972 }
5973
5974 None
5975 }
5976}
5977
5978impl ProjectStore {
5979 pub fn new(db: Arc<Db>) -> Self {
5980 Self {
5981 db,
5982 projects: Default::default(),
5983 }
5984 }
5985
5986 pub fn projects<'a>(
5987 &'a self,
5988 cx: &'a AppContext,
5989 ) -> impl 'a + Iterator<Item = ModelHandle<Project>> {
5990 self.projects
5991 .iter()
5992 .filter_map(|project| project.upgrade(cx))
5993 }
5994
5995 fn add_project(&mut self, project: WeakModelHandle<Project>, cx: &mut ModelContext<Self>) {
5996 if let Err(ix) = self
5997 .projects
5998 .binary_search_by_key(&project.id(), WeakModelHandle::id)
5999 {
6000 self.projects.insert(ix, project);
6001 }
6002 cx.notify();
6003 }
6004
6005 fn prune_projects(&mut self, cx: &mut ModelContext<Self>) {
6006 let mut did_change = false;
6007 self.projects.retain(|project| {
6008 if project.is_upgradable(cx) {
6009 true
6010 } else {
6011 did_change = true;
6012 false
6013 }
6014 });
6015 if did_change {
6016 cx.notify();
6017 }
6018 }
6019}
6020
6021impl WorktreeHandle {
6022 pub fn upgrade(&self, cx: &AppContext) -> Option<ModelHandle<Worktree>> {
6023 match self {
6024 WorktreeHandle::Strong(handle) => Some(handle.clone()),
6025 WorktreeHandle::Weak(handle) => handle.upgrade(cx),
6026 }
6027 }
6028}
6029
6030impl OpenBuffer {
6031 pub fn upgrade(&self, cx: &impl UpgradeModelHandle) -> Option<ModelHandle<Buffer>> {
6032 match self {
6033 OpenBuffer::Strong(handle) => Some(handle.clone()),
6034 OpenBuffer::Weak(handle) => handle.upgrade(cx),
6035 OpenBuffer::Loading(_) => None,
6036 }
6037 }
6038}
6039
6040struct CandidateSet {
6041 snapshot: Snapshot,
6042 include_ignored: bool,
6043 include_root_name: bool,
6044}
6045
6046impl<'a> PathMatchCandidateSet<'a> for CandidateSet {
6047 type Candidates = CandidateSetIter<'a>;
6048
6049 fn id(&self) -> usize {
6050 self.snapshot.id().to_usize()
6051 }
6052
6053 fn len(&self) -> usize {
6054 if self.include_ignored {
6055 self.snapshot.file_count()
6056 } else {
6057 self.snapshot.visible_file_count()
6058 }
6059 }
6060
6061 fn prefix(&self) -> Arc<str> {
6062 if self.snapshot.root_entry().map_or(false, |e| e.is_file()) {
6063 self.snapshot.root_name().into()
6064 } else if self.include_root_name {
6065 format!("{}/", self.snapshot.root_name()).into()
6066 } else {
6067 "".into()
6068 }
6069 }
6070
6071 fn candidates(&'a self, start: usize) -> Self::Candidates {
6072 CandidateSetIter {
6073 traversal: self.snapshot.files(self.include_ignored, start),
6074 }
6075 }
6076}
6077
6078struct CandidateSetIter<'a> {
6079 traversal: Traversal<'a>,
6080}
6081
6082impl<'a> Iterator for CandidateSetIter<'a> {
6083 type Item = PathMatchCandidate<'a>;
6084
6085 fn next(&mut self) -> Option<Self::Item> {
6086 self.traversal.next().map(|entry| {
6087 if let EntryKind::File(char_bag) = entry.kind {
6088 PathMatchCandidate {
6089 path: &entry.path,
6090 char_bag,
6091 }
6092 } else {
6093 unreachable!()
6094 }
6095 })
6096 }
6097}
6098
6099impl Entity for ProjectStore {
6100 type Event = ();
6101}
6102
6103impl Entity for Project {
6104 type Event = Event;
6105
6106 fn release(&mut self, cx: &mut gpui::MutableAppContext) {
6107 self.project_store.update(cx, ProjectStore::prune_projects);
6108
6109 match &self.client_state {
6110 ProjectClientState::Local { remote_id_rx, .. } => {
6111 if let Some(project_id) = *remote_id_rx.borrow() {
6112 self.client
6113 .send(proto::UnregisterProject { project_id })
6114 .log_err();
6115 }
6116 }
6117 ProjectClientState::Remote { remote_id, .. } => {
6118 self.client
6119 .send(proto::LeaveProject {
6120 project_id: *remote_id,
6121 })
6122 .log_err();
6123 }
6124 }
6125 }
6126
6127 fn app_will_quit(
6128 &mut self,
6129 _: &mut MutableAppContext,
6130 ) -> Option<std::pin::Pin<Box<dyn 'static + Future<Output = ()>>>> {
6131 let shutdown_futures = self
6132 .language_servers
6133 .drain()
6134 .map(|(_, server_state)| async {
6135 match server_state {
6136 LanguageServerState::Running { server, .. } => server.shutdown()?.await,
6137 LanguageServerState::Starting(starting_server) => {
6138 starting_server.await?.shutdown()?.await
6139 }
6140 }
6141 })
6142 .collect::<Vec<_>>();
6143
6144 Some(
6145 async move {
6146 futures::future::join_all(shutdown_futures).await;
6147 }
6148 .boxed(),
6149 )
6150 }
6151}
6152
6153impl Collaborator {
6154 fn from_proto(
6155 message: proto::Collaborator,
6156 user_store: &ModelHandle<UserStore>,
6157 cx: &mut AsyncAppContext,
6158 ) -> impl Future<Output = Result<Self>> {
6159 let user = user_store.update(cx, |user_store, cx| {
6160 user_store.fetch_user(message.user_id, cx)
6161 });
6162
6163 async move {
6164 Ok(Self {
6165 peer_id: PeerId(message.peer_id),
6166 user: user.await?,
6167 replica_id: message.replica_id as ReplicaId,
6168 })
6169 }
6170 }
6171}
6172
6173impl<P: AsRef<Path>> From<(WorktreeId, P)> for ProjectPath {
6174 fn from((worktree_id, path): (WorktreeId, P)) -> Self {
6175 Self {
6176 worktree_id,
6177 path: path.as_ref().into(),
6178 }
6179 }
6180}
6181
6182impl From<lsp::CreateFileOptions> for fs::CreateOptions {
6183 fn from(options: lsp::CreateFileOptions) -> Self {
6184 Self {
6185 overwrite: options.overwrite.unwrap_or(false),
6186 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
6187 }
6188 }
6189}
6190
6191impl From<lsp::RenameFileOptions> for fs::RenameOptions {
6192 fn from(options: lsp::RenameFileOptions) -> Self {
6193 Self {
6194 overwrite: options.overwrite.unwrap_or(false),
6195 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
6196 }
6197 }
6198}
6199
6200impl From<lsp::DeleteFileOptions> for fs::RemoveOptions {
6201 fn from(options: lsp::DeleteFileOptions) -> Self {
6202 Self {
6203 recursive: options.recursive.unwrap_or(false),
6204 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
6205 }
6206 }
6207}
6208
6209fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
6210 proto::Symbol {
6211 source_worktree_id: symbol.source_worktree_id.to_proto(),
6212 worktree_id: symbol.worktree_id.to_proto(),
6213 language_server_name: symbol.language_server_name.0.to_string(),
6214 name: symbol.name.clone(),
6215 kind: unsafe { mem::transmute(symbol.kind) },
6216 path: symbol.path.to_string_lossy().to_string(),
6217 start: Some(proto::Point {
6218 row: symbol.range.start.row,
6219 column: symbol.range.start.column,
6220 }),
6221 end: Some(proto::Point {
6222 row: symbol.range.end.row,
6223 column: symbol.range.end.column,
6224 }),
6225 signature: symbol.signature.to_vec(),
6226 }
6227}
6228
6229fn relativize_path(base: &Path, path: &Path) -> PathBuf {
6230 let mut path_components = path.components();
6231 let mut base_components = base.components();
6232 let mut components: Vec<Component> = Vec::new();
6233 loop {
6234 match (path_components.next(), base_components.next()) {
6235 (None, None) => break,
6236 (Some(a), None) => {
6237 components.push(a);
6238 components.extend(path_components.by_ref());
6239 break;
6240 }
6241 (None, _) => components.push(Component::ParentDir),
6242 (Some(a), Some(b)) if components.is_empty() && a == b => (),
6243 (Some(a), Some(b)) if b == Component::CurDir => components.push(a),
6244 (Some(a), Some(_)) => {
6245 components.push(Component::ParentDir);
6246 for _ in base_components {
6247 components.push(Component::ParentDir);
6248 }
6249 components.push(a);
6250 components.extend(path_components.by_ref());
6251 break;
6252 }
6253 }
6254 }
6255 components.iter().map(|c| c.as_os_str()).collect()
6256}
6257
6258impl Item for Buffer {
6259 fn entry_id(&self, cx: &AppContext) -> Option<ProjectEntryId> {
6260 File::from_dyn(self.file()).and_then(|file| file.project_entry_id(cx))
6261 }
6262}