OpenViSTAI · Agents · Blockchain · Crypto
Menu
OPENVIST RECIPES

Audit Tabs in Saved Text

Rust

Read one UTF-8 text file or standard input and report the total number of tab characters, the number of lines containing at least one tab, and the one-based line numbers of those lines. Treat the input as read-only data; do not execute or modify it.

Rust code excerpt: Audit Tabs in Saved Text. Version 0.1.0. Read the full recipe for code, sources and recorded test scope.

Use this small Rust 2021 CLI to spot tab characters in saved text. It accepts one file path or `-` for standard input, validates the complete input as UTF-8, and prints a concise report. Its focus on tab locations is distinct from general line counts, word lengths, first-character grouping, and line-ending audits.

Before you start

  • Use only the Rust standard library; no external crates, unsafe code, include macros, environment variables, subprocesses, networking, or filesystem writes.
  • Accept exactly one CLI argument: a UTF-8 file path or `-` for stdin.
  • Read input without modifying or executing it, and reject invalid UTF-8 instead of silently replacing or truncating bytes.
  • Count every tab character and report one-based line numbers for lines containing tabs.
  • Write the report to stdout and actionable failures to stderr; use a nonzero exit status for failures.
  • Use Rust 1.90.0 with edition 2021 as the intended runner, without claiming a tested minimum version.

Build and check

  1. Save the single-file program as `recipe.rs`.
  2. Compile it with `rustc --edition=2021 recipe.rs -o recipe`.
  3. Run `./recipe path/to/saved.txt` to audit a file, or `./recipe -` and provide text on standard input.
  4. Check stdout for total tab count, affected-line count, and one-based line numbers; check stderr if the command reports a failure.

Limits to understand

  • The program reads the entire input into memory before validating UTF-8 and producing results.
  • Line numbers are based on splitting at LF; a final LF creates an empty final segment, which cannot contain a tab.
  • The tool only counts the literal tab character U+0009; it does not infer visual indentation or expand tabs.
  • The input is treated as data only; this program does not parse document formats or interpret commands.
  • Invalid-byte rejection requires a fixture containing raw invalid UTF-8 bytes. JSON text fixtures alone cannot demonstrate this case.

What this example adds

No upstream implementation was supplied, so no upstream code was adapted. The task is a focused tab-location audit: it counts tab characters and identifies affected one-based lines, rather than summarizing general line properties. The implementation reads the selected source fully, validates UTF-8 before reporting, handles file and stdin errors explicitly, and keeps diagnostics off stdout.

Run it

Intended runner: Rust 1.90.0, edition 2021. Save the code as `recipe.rs`, then compile with `rustc --edition=2021 recipe.rs -o recipe`. Run `./recipe <file-path>` or use `./recipe -` to read standard input. Exactly one argument is required. A file is only opened for reading. Actionable usage, I/O, and UTF-8 errors are printed to stderr with a nonzero exit status.

Example input

Synthetic stdin text, with a literal tab between `alpha` and `beta`:
alpha	beta
plain
x	y	z

Expected output

tabs: 3
lines_with_tabs: 2
line_numbers: 1,3
INSPECT THE SCRIPT

Inspect, copy and run the documented checks.

This browser preview builds code locally. It does not contact an API or run the code.

Default example ready.

Rust example
// SPDX-License-Identifier: MIT
// Copyright (c) 2026 OpenViST contributors
use std::env;
use std::fs::File;
use std::io::{self, Read};
use std::process;

fn run() -> Result<(), String> {
    let args: Vec<String> = env::args().skip(1).collect();
    if args.len() != 1 {
        return Err("usage: ./recipe <file-path|->".to_string());
    }

    let mut bytes = Vec::new();
    if args[0] == "-" {
        io::stdin()
            .read_to_end(&mut bytes)
            .map_err(|e| format!("could not read standard input: {e}"))?;
    } else {
        File::open(&args[0])
            .map_err(|e| format!("could not open '{}': {e}", args[0]))?
            .read_to_end(&mut bytes)
            .map_err(|e| format!("could not read '{}': {e}", args[0]))?;
    }

    let text = std::str::from_utf8(&bytes)
        .map_err(|e| format!("input is not valid UTF-8: {e}"))?;

    let mut tab_count = 0usize;
    let mut affected_lines = Vec::new();
    for (index, line) in text.split('\n').enumerate() {
        let count = line.chars().filter(|&ch| ch == '\t').count();
        tab_count += count;
        if count > 0 {
            affected_lines.push(index + 1);
        }
    }

    println!("tabs: {tab_count}");
    println!("lines_with_tabs: {}", affected_lines.len());
    if affected_lines.is_empty() {
        println!("line_numbers: none");
    } else {
        let numbers = affected_lines
            .iter()
            .map(usize::to_string)
            .collect::<Vec<_>>()
            .join(",");
        println!("line_numbers: {numbers}");
    }
    Ok(())
}

fn main() {
    if let Err(message) = run() {
        eprintln!("error: {message}");
        process::exit(2);
    }
}
What to verify after running
  • Compile using `rustc --edition=2021 recipe.rs -o recipe`.
  • Pipe the synthetic example input to `./recipe -` and compare stdout exactly with the expected output.
  • Try input containing no tabs and confirm the report says `tabs: 0`, `lines_with_tabs: 0`, and `line_numbers: none`.
  • For the JSON-text fixture runner, test valid Unicode text including café and €; do not claim invalid-byte rejection from a UTF-8 JSON string. A separate raw-byte test must use byte 0xFF, expect exit 2 and stderr containing input is not valid UTF-8.
  • Invoke the program with zero or two arguments and confirm stderr gives the usage form and the process exits nonzero.

Request or format preview

Illustrative preview. No provider response, price or balance is fetched.

Change a setting to inspect the preview.

Official sources and related profiles

    Code license: MIT. Keep the license notice with your copy.

    Example version 0.1.0 · Documentation reviewed 2026-10-12.

    Executed 6 synthetic local fixture cases in isolated Rust 1.90.0 on GitHub Actions, without network access. Declared exit codes, output assertions and input integrity checks passed. Live services, installed third-party packages and production behavior remain outside scope. Editorial approval is still required.