feat(editor): rename :sync to :gp

Pairs with :gl as the push half of the git pair. Same behavior
(fmt → save → commit → push); notices, logs, and current READMEs
follow, historical docs keep :sync as a record of their time.
This commit is contained in:
Julien Calixte
2026-07-14 09:42:30 +02:00
parent e161b1eae7
commit cdfeabc152
8 changed files with 63 additions and 63 deletions

View File

@@ -86,7 +86,7 @@ pub enum Mode {
/// are locked out.
View,
/// `:` command line — keys accumulate a command shown in the status strip;
/// Enter runs it, Esc cancels. Handles `:fmt` (in-core) plus `:w`/`:sync`
/// Enter runs it, Esc cancels. Handles `:fmt` (in-core) plus `:w`/`:gp`
/// (which ask the host to persist/publish via an [`Effect`]).
Command,
/// File palette (`Cmd-P`) — a modal transient panel over the writing column.
@@ -98,8 +98,8 @@ pub enum Mode {
/// Which of the two file scopes ([`CONTEXT.md`]) a buffer belongs to. Fixed at
/// creation — there is no move-between-scopes operation. **Tracked** files live
/// under [`REPO_DIR`] and can be Published (`:sync`); **Local** files live under
/// [`LOCAL_DIR`] and never leave the device, so `:sync` is refused in-core.
/// under [`REPO_DIR`] and can be Published (`:gp`); **Local** files live under
/// [`LOCAL_DIR`] and never leave the device, so `:gp` is refused in-core.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Scope {
Tracked,
@@ -128,13 +128,13 @@ pub enum Effect {
/// [`Editor::install_loaded`]. Queued when switching to a file that is not
/// resident in memory (`:e`, palette pick).
Load { path: String, scope: Scope },
/// `:sync` — publish the Tracked working copy (git push). Preceded by a
/// `:gp` — publish the Tracked working copy (git push). Preceded by a
/// [`Save`](Effect::Save) of the current buffer in the same batch. Never
/// queued from a Local buffer (blocked in-core).
Publish,
/// `:gl` — pull from the remote: fetch, then **fast-forward only**. The host
/// refuses (and surfaces) a divergence rather than merging, and never
/// touches local commits. Complements `:sync` (push) as the download half.
/// touches local commits. Complements `:gp` (push) as the download half.
Pull,
/// `:delete` — unlink `path` from the card. For a **Tracked** file the removal
/// lands in the git working copy, so the next [`Publish`](Effect::Publish)'s
@@ -157,7 +157,7 @@ pub const REPO_DIR: &str = "/sd/repo";
pub const LOCAL_DIR: &str = "/sd/local";
/// The git-tracked preferences file. Read at boot and rewritten when a palette
/// `>` command changes a pref, so the setting survives a reboot and rides the
/// next `:sync` to every device that clones the repo. Deliberately **distinct**
/// next `:gp` to every device that clones the repo. Deliberately **distinct**
/// from the gitignored `/sd/typoena.conf` device secrets (Wi-Fi / PAT / remote /
/// author, never committed — see v0.1): behaviour is shared, secrets are not.
pub const PREFS_PATH: &str = "/sd/repo/.typoena.toml";
@@ -171,12 +171,12 @@ pub const PREFS_PATH: &str = "/sd/repo/.typoena.toml";
pub struct Prefs {
/// Auto-save the active buffer on the idle typing-pause, so `:w` becomes
/// optional. The idle save is **unformatted** — a safety net against power
/// loss, not a formatting pass; `:fmt` only runs on an explicit `:w`/`:sync`
/// loss, not a formatting pass; `:fmt` only runs on an explicit `:w`/`:gp`
/// (see [`format_on_save`](Prefs::format_on_save)) so text is never reflowed
/// mid-session. Honoured by the host loop, not the core.
pub save_on_idle: bool,
/// Run `:fmt` (table alignment, blank-line collapse, trailing-whitespace
/// strip) on the buffer before an explicit `:w`/`:sync` persist.
/// strip) on the buffer before an explicit `:w`/`:gp` persist.
pub format_on_save: bool,
/// Show the absolute line-number gutter (built always-on in v0.2). Off
/// reclaims the gutter's columns for text — applied live by [`gutter_cols`].
@@ -701,7 +701,7 @@ pub struct Editor {
/// command mode can toggle them live; the host reads the file at boot and
/// applies it via [`set_prefs`](Self::set_prefs), and reads it back for the
/// keys it honours (`save_on_idle`). `format_on_save` and `line_numbers` are
/// consulted in-core (`:w`/`:sync` and the gutter).
/// consulted in-core (`:w`/`:gp` and the gutter).
prefs: Prefs,
/// The unnamed register: the last yanked or deleted text, replayed by
/// `p`/`P`. `y`, `d`, `c`, and `x` all fill it (vim's unnamed register), so
@@ -735,7 +735,7 @@ pub struct Editor {
/// `/sd/repo/notes.md`). Empty for an unnamed scratch buffer (the boot-message
/// layout use); `:w` on an empty path posts "no file name" rather than saving.
path: String,
/// The active buffer's scope. Gates Publish — `:sync` is refused in Local.
/// The active buffer's scope. Gates Publish — `:gp` is refused in Local.
scope: Scope,
/// Whether the active buffer has unsaved edits. Set at each change-group
/// ([`checkpoint`](Self::checkpoint)) and cleared when the host confirms a
@@ -903,7 +903,7 @@ impl Editor {
/// Seed a fresh editor from a named file's saved text — the boot-load and
/// file-open path. Same boot posture as [`with_text`](Self::with_text)
/// (Normal mode, caret on the last character) but records the file's `path`
/// and `scope` so `:w` knows where to persist and `:sync` knows whether
/// and `scope` so `:w` knows where to persist and `:gp` knows whether
/// Publish is offered.
pub fn with_file(path: String, scope: Scope, text: String) -> Self {
let mut ed = Editor { text, path, scope, ..Editor::new() };
@@ -918,7 +918,7 @@ impl Editor {
self.mode
}
/// The full buffer contents, for the host to persist on `:w`/`:sync`.
/// The full buffer contents, for the host to persist on `:w`/`:gp`.
pub fn text(&self) -> &str {
&self.text
}
@@ -1554,7 +1554,7 @@ impl Editor {
self.request_save_active();
}
// fmt → save → push, shared with the `>` publish command.
"sync" => self.run_publish(),
"gp" => self.run_publish(),
"gl" => self.requests.push(Effect::Pull),
_ => {}
}
@@ -2237,7 +2237,7 @@ impl Editor {
self.palette_sel = 0;
}
/// The publish path shared by `:sync` and the `>` `publish` command: format on
/// The publish path shared by `:gp` and the `>` `publish` command: format on
/// save (if enabled), queue the buffer save, then the git push — the host
/// services them in order. Tracked-only: a Local buffer never reaches the
/// remote, so it is a no-op with a notice.
@@ -2260,7 +2260,7 @@ impl Editor {
/// string ([`Theme`](PaletteCmd::Theme), [`AutoSync`](PaletteCmd::AutoSync))
/// rotates to its next option and wraps — so from the palette every setting
/// is "press Enter to change". The queued `SavePrefs` is what makes the
/// change durable and lets it ride the next `:sync` to other devices.
/// change durable and lets it ride the next `:gp` to other devices.
fn cycle_pref(&mut self, cmd: PaletteCmd) {
match cmd {
PaletteCmd::SaveOnIdle => self.prefs.save_on_idle = !self.prefs.save_on_idle,
@@ -3345,7 +3345,7 @@ impl Editor {
/// [`draw`](Self::draw) into a caller-owned frame, reusing its allocation.
/// Firmware keeps two boot-time frames and round-trips them through here so
/// a repaint never allocates: the editor must stay drawable even when a
/// background `:sync` push has taken the heap to the floor — a failed
/// background `:gp` push has taken the heap to the floor — a failed
/// framebuffer alloc aborts the whole app (the 2026-07-13 OOM).
pub fn draw_into(&mut self, out: &mut Frame, cursor_on: bool) {
let lay = self.layout();
@@ -4347,9 +4347,9 @@ mod tests {
}
#[test]
fn sync_command_saves_then_publishes() {
// `:sync` queues a save of the current buffer, then the git publish.
assert_eq!(kinds(&command("sync").1), vec![Kind::Save, Kind::Publish]);
fn gp_command_saves_then_publishes() {
// `:gp` queues a save of the current buffer, then the git publish.
assert_eq!(kinds(&command("gp").1), vec![Kind::Save, Kind::Publish]);
}
#[test]
@@ -4358,15 +4358,15 @@ mod tests {
}
#[test]
fn sync_formats_the_buffer_before_publishing() {
// fmt → save → commit → push: `:sync` runs :fmt in-core first (default on).
fn gp_formats_the_buffer_before_publishing() {
// fmt → save → commit → push: `:gp` runs :fmt in-core first (default on).
let mut e = Editor::with_file(
"/sd/repo/notes.md".into(),
Scope::Tracked,
"hello \nworld".to_string(), // trailing spaces
);
e.handle(Key::Char(':'));
for c in "sync".chars() {
for c in "gp".chars() {
e.handle(Key::Char(c));
}
e.handle(Key::Enter);
@@ -4375,15 +4375,15 @@ mod tests {
}
#[test]
fn sync_is_refused_in_a_local_buffer() {
// Publish is Tracked-only; `:sync` in Local queues nothing and warns.
fn gp_is_refused_in_a_local_buffer() {
// Publish is Tracked-only; `:gp` in Local queues nothing and warns.
let mut e = Editor::with_file(
"/sd/local/journal.md".into(),
Scope::Local,
"dear diary".to_string(),
);
e.handle(Key::Char(':'));
for c in "sync".chars() {
for c in "gp".chars() {
e.handle(Key::Char(c));
}
e.handle(Key::Enter);