Add project-mode tooling: characters, outline, diff and revision status
Rounds out project mode, where the workspace is the project root and one subfolder holds the manuscript proper: - Characters and Outline windows, backed by new `characters` and `outline` modules that read the cast from character sheets and measure how much of the snowflake outline is actually written. - Edit ▸ Changes… diffs the open file against its last committed version. - Revision status, per-file and project word counts, an archive action and hidden folders in the file panel. - Chapter-file export alongside the ODT master, richer header parsing, and a project word list for names and invented terms. - The export path now follows the workspace: opening a project points it at that project root, keeping a file name you chose yourself and re-deriving one that merely echoed the folder it sat in. - Clicking an issue in the grammar/spelling panel takes the editor to it, selecting the words and centring them; applying a suggestion jumps to the rewritten text as well. README covers the new windows and workflows. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017bSn3Xijp8GofZVUnRX4oq
This commit is contained in:
@@ -123,3 +123,34 @@ fn current_branch(workspace: &Path) -> String {
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or_else(|| "main".to_string())
|
||||
}
|
||||
|
||||
/// The unified diff of one file against the last commit, as raw diff text.
|
||||
///
|
||||
/// Revising is comparing: what changed in this scene since the last time it was
|
||||
/// good? The repository already holds that answer, so the app asks git rather
|
||||
/// than keeping snapshots of its own.
|
||||
///
|
||||
/// `rel` is relative to the *workspace*, which may sit below the repository
|
||||
/// root, so the path is resolved through the work tree before being handed over.
|
||||
pub fn diff_file(workspace: &Path, rel: &str) -> Result<String, String> {
|
||||
let (ok, out) = run_git(
|
||||
workspace,
|
||||
&["--no-pager", "diff", "--no-color", "HEAD", "--", rel],
|
||||
);
|
||||
if !ok {
|
||||
// A repository with no commits yet has no HEAD to compare against.
|
||||
return Err(strip_command_echo(&out));
|
||||
}
|
||||
Ok(strip_command_echo(&out))
|
||||
}
|
||||
|
||||
/// Whether the repository has at least one commit, and so something to diff.
|
||||
pub fn has_commits(workspace: &Path) -> bool {
|
||||
run_git(workspace, &["rev-parse", "--verify", "HEAD"]).0
|
||||
}
|
||||
|
||||
/// Drop the `$ git …` line `run_git` prefixes for the log window; a diff view
|
||||
/// wants the diff itself.
|
||||
fn strip_command_echo(text: &str) -> String {
|
||||
text.split_once('\n').map_or(text, |(_, rest)| rest).to_string()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user