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