Skip to main content

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}