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 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}