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