strop_engine/editor/document/surfaces.rs
1//! The document's source identity (0021 §4): what a document IS drives
2//! readonly-ness and save behavior — not conventions on three fields.
3//! Git-memory surfaces carry their typed payload here; the editor's
4//! surface bookkeeping reads one place.
5
6use super::JumpRecord;
7use crate::editor::git_memory::{CommitFiles, HunkOrigin};
8use strop_git::memory::LogRow;
9use strop_git::Hunk;
10
11/// What backs a document. Derived facts (readonly, save refusal) come
12/// from this, not from fields callers must keep in sync.
13#[derive(Debug, Clone)]
14pub enum DocumentSource {
15 /// A file on disk (`Buffer.path` is Some).
16 File,
17 /// The [No Name] scratch buffer.
18 Scratch,
19 /// An in-memory SSH document; write authority is explicit and never local.
20 Remote(Box<super::RemoteDocument>),
21 /// A remote directory's real, read-only listing buffer.
22 RemoteDirectory(Box<super::RemoteDirectory>),
23 /// A file inside a container: readonly (DC1b refuses writes); the
24 /// path names the container's filesystem — never a local path.
25 Container {
26 container: strop_workspace::ContainerId,
27 path: std::path::PathBuf,
28 },
29 /// A git-memory surface: job-owned content, readonly.
30 Surface(Box<GitSurface>),
31 /// `:!cmd` output / help: named virtual content, readonly. The
32 /// return point is where `:q` hands the view back (0051 §7 R07) —
33 /// temporary surfaces restore their origin, not the MRU's line 1.
34 Output { return_to: Option<JumpRecord> },
35}
36
37#[derive(Debug, Clone)]
38pub struct GitSurface {
39 pub context: strop_git::GitContext,
40 pub content: Surface,
41}
42
43#[derive(Debug, Clone)]
44pub enum Surface {
45 CommitLog {
46 rows: Vec<LogRow>,
47 /// Sha to land the cursor on once rows arrive (the blame dive
48 /// opens the browser *at* a commit, 0011 §3).
49 focus: Option<String>,
50 return_to: Option<JumpRecord>,
51 },
52 ChangedFiles {
53 sha: String,
54 files: crate::editor::git_memory::PreparedFiles,
55 return_to: Option<JumpRecord>,
56 },
57 /// A diff as a readonly buffer (0010 §2): the file's delta at a
58 /// commit, or the `Space g p` hunk preview. The buffer's rows mirror
59 /// the rendered layout — a stats row, then per hunk a `@@` header
60 /// row and unprefixed content rows — so motions, `/` and yank see
61 /// exactly what's on screen. `origin` names the working buffer a
62 /// hunk preview belongs to, so `Space g u`/`g s` act on the file;
63 /// `commit` carries the commit's other files when this delta came
64 /// from the dive chain (the sidebar + `]f`/`[f`, 0011 §4).
65 Diff {
66 /// Worker-prepared immutable content and its display/source projection.
67 hunks: crate::editor::git_memory::PreparedDiff,
68 origin: Option<HunkOrigin>,
69 commit: Option<CommitFiles>,
70 /// tuicr-style: Tab moves focus between the file sidebar and
71 /// the diff content (j/k step files when the sidebar has focus).
72 sidebar_focus: bool,
73 return_to: Option<JumpRecord>,
74 },
75}
76
77/// One canonical row projection shared by rendering and source navigation.
78pub enum DiffRow<'a> {
79 Stats,
80 HunkHeader(&'a Hunk),
81 Line(&'a strop_git::DiffLine),
82}
83
84impl Surface {
85 pub fn diff_row(&self, row: usize) -> Option<DiffRow<'_>> {
86 let Surface::Diff { hunks, .. } = self else {
87 return None;
88 };
89 hunks.row(row)
90 }
91
92 pub(crate) fn set_return_point(&mut self, ret: JumpRecord) {
93 *self.return_slot() = Some(ret);
94 }
95
96 pub(crate) fn return_point(&self) -> Option<&JumpRecord> {
97 match self {
98 Surface::CommitLog { return_to, .. }
99 | Surface::ChangedFiles { return_to, .. }
100 | Surface::Diff { return_to, .. } => return_to.as_ref(),
101 }
102 }
103
104 pub(crate) fn return_slot(&mut self) -> &mut Option<JumpRecord> {
105 match self {
106 Surface::CommitLog { return_to, .. }
107 | Surface::ChangedFiles { return_to, .. }
108 | Surface::Diff { return_to, .. } => return_to,
109 }
110 }
111}