lscolors

repository·master·Indexed 43 days ago

https://github.com/sharkdp/lscolors

A cross-platform Rust library and CLI tool that colorizes file paths according to the LS_COLORS environment variable, mimicking the behavior of the ls command. Version 0.21.0 provides integration with terminal styling crates such as ansi_term, nu-ansi-term, gnu_legacy, and crossterm.

Tokens
4K
Snippets
15
Records
16
Agent score
55%

What's inside lscolors

  1. Install the lscolors CLI

    master

    The lscolors command-line tool can be used to colorize the output of other commands by piping them into lscolors.

    To install the CLI via Cargo:

    cargo install lscolors

    Alternatively, you can download prebuilt binaries from the GitHub releases page or build from source using:

    cargo build --release --features=nu-ansi-term --locked
    # Example usage of the CLI
    find . -maxdepth 2 | lscolors
    
    rg foo -l | lscolors
  2. Use lscolors as a Rust library

    master

    To colorize file paths in your Rust application using the LS_COLORS environment variable, use the LsColors struct. You can initialize it from the environment using LsColors::from_env() and then determine the style for a specific path using style_for_path(path).

    The library provides conversion methods to integrate with popular terminal styling crates like ansi_term, nu-ansi-term, gnu_legacy, and crossterm.

    use lscolors::{LsColors, Style};
    
    let lscolors = LsColors::from_env().unwrap_or_default();
    let path = "some/folder/test.tar.gz";
    let style = lscolors.style_for_path(path);
    
    // Example: Using crossterm
    let crossterm_style = style.map(Style::to_crossterm_style)
                          .unwrap_or_default();
    println!("{}", crossterm_style.apply(path));
  3. Configure lscolors features in Cargo.toml

    master

    Depending on which terminal styling crate you want to use, you must enable the corresponding feature in your Cargo.toml dependencies:

    • ansi_term: For ansi_term coloring.
    • crossterm: For crossterm coloring.
    • nu_ansi_term: For nu-ansi-term (a fork of ansi_term) coloring.
    • gnu_legacy: For nu-ansi-term coloring in GNU legacy mode with double-digit styles.
    # use ansi-term coloring
    lscolors = { version = "0.21", features = ["ansi_term"] }
    
    # use crossterm coloring
    lscolors = { version = "0.21", features = ["crossterm"] }
    
    # use nu-ansi-term coloring
    lscolors = { version = "0.21", features = ["nu-ansi-term"] }
    
    # use nu-ansi-term coloring in gnu legacy mode with double digit styles
    lscolors = { version = "0.21", features = ["gnu_legacy"] }
  4. How suffix styling and LS_COLORS work

    master

    The project implements suffix-based styling similar to GNU ls. It uses the LS_COLORS environment variable to map file extensions (suffixes) to specific text styles.

    Key Behaviors:

    • Overriding: Later suffixes in the configuration override earlier ones. For example, if you define both *.gz and *.tar.gz, the order determines which rule wins for a file ending in .tar.gz.
    • Case Sensitivity: Matching is ASCII case-insensitive by default. However, if you provide different styles for different capitalizations of the same suffix (e.g., *README vs *readme), the matching becomes case-sensitive for those specific suffixes.

    Example Configuration:

    # archive.tar.gz will be bold red, music.mp3 will be cyan
    export LS_COLORS="*.gz=01;31:*.mp3=00;36:"
    
    # Different styles for different capitalizations triggers case-sensitivity
    export LS_COLORS="*README=01:*readme=00:"
    export LS_COLORS="*.gz=01;31:*.mp3=00:"
  5. Integrate with ANSI term libraries

    master

    The Style returned by lscolors is a generic representation. To actually print colors to a terminal, you must map it to a specific ANSI library. The library provides helper methods if the corresponding features are enabled.

    • If features = "nu-ansi-term" is enabled: use style.map(Style::to_nu_ansi_term_style).
    • If features = "ansi_term" is enabled: use style.map(Style::to_ansi_term_style).
    // Example using nu-ansi-term feature
    # #[cfg(features = "nu-ansi-term")]
    {
        use lscolors::{LsColors, Style};
        let lscolors = LsColors::from_env().unwrap_or_default();
        let path = "some/folder/archive.zip";
        let style = lscolors.style_for_path(path);
    
        let ansi_style = style.map(Style::to_nu_ansi_term_style).unwrap_or_default();
        println!("{}", ansi_style.paint(path));
    }
  6. Initialize LsColors from environment or string

    master

    To use lscolors, you first need to create an LsColors instance. You can create one using the default settings, from the LS_COLORS environment variable, or by parsing a custom string.

    • LsColors::default(): Uses default styles (similar to dircolors).
    • LsColors::from_env(): Parses the LS_COLORS environment variable if it exists.
    • LsColors::from_string(input: &str): Parses a custom LS_COLORS formatted string.
    • LsColors::empty(): Creates an instance with no styles.
    use lscolors::LsColors;
    
    // From environment variable
    let lscolors = LsColors::from_env().unwrap_or_default();
    
    // From a custom string
    let lscolors = LsColors::from_string("*.wav=00;36:di=01;34");
  7. Configure lscolors via LS_COLORS environment variable

    master
    The lscolors CLI tool initializes its styling rules using LsColors::from_env(). This means it respects the standard LS_COLORS environment variable used by many terminal utilities. If the environment variable is not set or is invalid, the tool falls back to default styling.
  8. Build a SuffixMap using SuffixMapBuilder

    master

    To programmatically map file suffixes to styles, use the SuffixMapBuilder. This allows you to incrementally add suffixes and their associated Style objects before compiling them into an efficient SuffixMap for lookups.

    API Methods:

    • push(suffix: impl AsRef<[u8]>, style: Option<Style>): Adds a new suffix and its optional style to the builder. The suffix is treated as a pattern (e.g., *.ext).
    • build() -> SuffixMap: Consumes the builder and returns a SuffixMap optimized for fast matching using Aho-Corasick.
    let mut builder = SuffixMapBuilder::default();
    builder.push("*.gz", Some(style_red));
    builder.push("*.mp3", Some(style_cyan));
    let suffix_map = builder.build();
  9. Retrieve a style from a SuffixMap

    master

    Once a SuffixMap is built, you can use the get method to find the style associated with a filename. The method performs efficient suffix matching and respects the overriding and case-sensitivity rules defined during construction.

    API Method:

    • get(&self, name: impl AsRef<[u8]>) -> Option<&Style>: Returns the Style associated with the longest matching suffix of the provided filename, or None if no match is found.
    if let Some(style) = suffix_map.get("archive.tar.gz") {
        // Apply the style to the filename
    }
  10. Get ANSI style for a path

    master

    You can retrieve the Style for a given path. The library will automatically determine the file type (directory, symlink, etc.) and check for suffix matches (e.g., *.txt).

    Note: style_for_path calls Path::symlink_metadata internally. If you have already acquired the Metadata, use style_for_path_with_metadata to avoid redundant system calls.

    use lscolors::LsColors;
    
    let lscolors = LsColors::default();
    let path = "some/folder/archive.zip";
    let style = lscolors.style_for_path(path);
    
    if let Some(s) = style {
        // Use the style with an ANSI term library
    }
  11. Configure font-style attributes

    master

    The FontStyle struct manages text decorations like bold, italic, and underline. You can create specific styles using builder-like methods or by constructing the struct directly.

    Available Attributes:

    • bold
    • dimmed (faint)
    • italic
    • underline
    • slow_blink / rapid_blink
    • reverse (inverse video)
    • hidden (conceal)
    • strikethrough (crossed-out)

    Conversion:

    • to_crossterm_attributes(): Converts to crossterm::style::Attributes (requires crossterm feature).
    use lscolors::FontStyle;
    
    let style = FontStyle::bold();
    let italic_underline = FontStyle {
        italic: true,
        underline: true,
        ..Default::default()
    };
  12. Manage full text styles and parse ANSI sequences

    master

    The Style struct combines foreground color, background color, font styles, and underline color into a single object. It can be used to generate styles for various terminal libraries or parsed directly from raw ANSI escape sequences.

    Key Methods:

    • from_ansi_sequence(&str): Parses a semicolon-separated ANSI escape code string (e.g., "31;1" for bold red) into a Style object. Returns None if the sequence is invalid or empty.
    • to_ansi_term_style(): Converts to ansi_term::Style (requires ansi_term feature).
    • to_nu_ansi_term_style(): Converts to nu_ansi_term::Style (requires nu-ansi-term or gnu_legacy feature).
    • to_crossterm_style(): Converts to crossterm::style::ContentStyle (requires crossterm feature).
    • to_owo_colors_style(): Converts to owo_colors::Style (requires owo-colors feature).
    use lscolors::{Color, FontStyle, Style};
    
    // Create a style manually
    let style = Style {
        font_style: FontStyle::bold(),
        foreground: Some(Color::Blue),
        ..Default::default()
    };
    
    // Parse a style from an ANSI sequence
    let parsed_style = Style::from_ansi_sequence("31;1").unwrap(); // Bold Red
    
    // Example: Convert to nu-ansi-term
    #[cfg(feature = "nu-ansi-term")]
    let nu_ansi = style.to_nu_ansi_term_style();