git_policy_cli/rule_status_hints.rs
1//! What:
2//! The pure decision of the status-hints transform:
3//! insert
4//! `-c advice.statusHints=false` before `git status` unless the caller set that key.
5//! Why:
6//! Git's stock status hints suggest `git add <file>...` and `git commit -a`,
7//! forms the
8//! wrapper's policies reject;
9//! the wrapper prints accurate guidance instead.
10//!
11//! In TS you'd write (pseudocode):
12//! ```ts
13//! // statusHintsOff(['status']) => ['-c', 'advice.statusHints=false', 'status']
14//! ```
15
16/// What:
17/// Bring the override reading,
18/// the global-option boundary and the rewrite helpers
19/// into this file.
20/// Why:
21/// The decision combines them;
22/// it owns no parsing of its own.
23///
24/// In TS you'd write (pseudocode):
25/// ```ts
26/// import { parseStatusPreRegion } from '../parser/status.ts';
27/// import { parseGlobalOptions } from '../parse-global-options.ts';
28/// ```
29use super::command_status::has_status_hints_override;
30use super::global_arguments::{GlobalLayout, GlobalOutcome, global_layout};
31use super::rule_argument_rewrite::{ArgumentRewrite, insert_tokens};
32/// `OsString` is owned operating-system text of raw bytes (sibling `String` must be UTF-8).
33use std::ffi::OsString;
34
35/// Tokens inserted before `status` so Git itself does not print its stock hints.
36pub const QUIET_INJECTION: &[&str] = &["-c", "advice.statusHints=false"];
37
38/// What:
39/// Whether the caller configured `advice.statusHints` before the subcommand,
40/// whatever the subcommand is.
41/// `&[OsString]` borrows the full argument list.
42/// Why:
43/// The entry point also asks this to decide whether to print its own note,
44/// and it
45/// asks about the raw arguments,
46/// before any transform ran.
47///
48/// In TS you'd write (pseudocode):
49/// ```ts
50/// function hasExplicitStatusHintsOverride(args: readonly string[]): boolean;
51/// ```
52pub fn has_explicit_status_hints_override(arguments: &[OsString]) -> bool {
53 let layout: GlobalLayout = global_layout(arguments);
54 // `&arguments[..n]` borrows the first `n` tokens: the completed global options.
55 return has_status_hints_override(&arguments[..layout.prefix_len]);
56}
57
58/// What:
59/// Decide the transform for one command line.
60/// Why:
61/// The tokens go immediately before `status`,
62/// after every caller-supplied global
63/// option,
64/// so those survive and Git still reads the inserted pair as global.
65///
66/// In TS you'd write (pseudocode):
67/// ```ts
68/// function statusHintsOff(args: readonly string[]): readonly string[];
69/// ```
70pub fn status_hints_off(arguments: &[OsString]) -> ArgumentRewrite {
71 let layout: GlobalLayout = global_layout(arguments);
72 if layout.outcome != GlobalOutcome::Command
73 || arguments[layout.prefix_len].as_encoded_bytes() != b"status"
74 {
75 return ArgumentRewrite::Unchanged;
76 }
77 if has_status_hints_override(&arguments[..layout.prefix_len]) {
78 return ArgumentRewrite::Unchanged;
79 }
80 return ArgumentRewrite::Rewritten(insert_tokens(
81 arguments,
82 layout.prefix_len,
83 QUIET_INJECTION,
84 ));
85}
86
87/// Every `status-hints-off.unit.test.ts` case and a real-Git control of the injection.
88#[cfg(test)]
89#[path = "rule_status_hints_tests.rs"]
90mod tests;