Something went wrong. Try again.
atproto git client
Something went wrong. Try again.
Rust
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788//! `--json`: one JSON value on stdout, everything else on stderr.//!//! The flag started on the OAuth log, then on `pr list` and `pr view`, each//! spelling its own rules out in its own module. Those rules are the same//! everywhere and are now written down once, here, because the value of//! machine-readable output is that a caller can learn it from one command//! and rely on it from the next://!//! 1. **Stdout carries exactly one JSON value**, pretty-printed, with a//! trailing newline. Not a stream of objects, not a value with a status//! line above it — a listing that finds nothing prints `[]` rather than//! prose, so a script never has to tell "nothing to report" apart from//! "the process died before printing". The `logs` readers are the//! documented exception — `--follow` is an unbounded stream and cannot be//! one value — and print JSON Lines instead; see `docs/output.md` and//! [`crate::cmd::logs::render`].//! 2. **Everything else goes to stderr** — and does so on every flag, not//! only this one. The notes these commands print beside their output —//! index-lag warnings, `acting as …`, "give the firehose a moment" — are//! commentary rather than payload, so they travel through//! [`crate::term::say`], which puts them on stderr whether or not anybody//! asked for JSON. Nothing here has to move them: by the time a command//! reaches its `--json` branch, they are already on the other stream.//! 3. **Decoration is off, unconditionally** — colour, OSC 8 hyperlinks,//! ellipsizing, column padding. All of it is display logic for a person//! at a terminal, all of it would have to be undone by a caller parsing//! the output back, and none of it runs regardless of whether stdout//! happens to be a pipe.//! 4. **Errors are not JSON.** A failure prints the same human-readable//! message to stderr and exits non-zero that it always has; nothing here//! wraps it in an envelope. Stderr and the exit code are atgc's error//! channel on every other flag too, and keeping it that way is what lets//! a caller distinguish an empty result from a failed command without//! inspecting anything.//!//! ## What the shapes hold//!//! Read commands emit the *derived* view rather than the record underneath://! a pull's state and number are in no record at all, and the resolving is//! the reason to run the command (see [`crate::docs::architecture`]).//!//! Unresolved is `null`, never `"?"` or an empty string: `?` is a display//! convention for a terminal column, and JSON has its own way to say a//! lookup did not answer.//!//! [`init`] records the mode for output sites that have no arguments of//! their own to consult — the shared printers a command calls from//! underneath its own `args`. A process-global is how `say` and `noinput`//! already answer that same question.
use anyhow::Result;use std::sync::atomic::{AtomicBool, Ordering};
static ACTIVE: AtomicBool = AtomicBool::new(false);
/// Declare this invocation's stdout to be a JSON document.////// Called at the top of every command that takes `--json`, before anything/// is printed. The decisions downstream of it are all about stdout — the/// shape of the payload, and whether a formatter runs at all; what a/// command says *beside* its answer is [`crate::term::say`]'s business and does/// not consult this flag.pub fn init(flag: bool) { ACTIVE.store(flag, Ordering::Relaxed);}
/// Whether stdout is reserved for a JSON document.////// For the shared printers that have no arguments of their own to consult —/// [`crate::term::hyperlink::stdout_escapes_wanted`], the one gate every colour/// and OSC 8 decision in the tool goes through, is the first of them. A/// command with `args.json` in hand should branch on that instead: same/// answer, in front of the reader of that command.pub fn active() -> bool { ACTIVE.load(Ordering::Relaxed)}
/// Print the one JSON value this invocation has to say, and a newline.////// Pretty-printed rather than compact: `jq` does not care, a person reading/// a captured file does, and the size difference is nothing next to the/// patches these records carry.pub fn emit(value: &impl serde::Serialize) -> Result<()> { serde_json::to_writer_pretty(std::io::stdout(), value)?; println!(); Ok(())}