Full Code of scullionw/dirstat-rs for AI

master 41d46b7bd347 cached
8 files
18.0 KB
5.0k tokens
28 symbols
1 requests
Download .txt
Repository: scullionw/dirstat-rs
Branch: master
Commit: 41d46b7bd347
Files: 8
Total size: 18.0 KB

Directory structure:
gitextract_khj5dz01/

├── .github/
│   └── workflows/
│       └── release.yaml
├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
└── src/
    ├── bin/
    │   └── main.rs
    ├── ffi.rs
    └── lib.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/release.yaml
================================================
name: Release

on:
  push:
    tags:
      - "v*"

jobs:
  release:
    runs-on: macos-11

    steps:
      - uses: actions/checkout@v2

      - name: Get version
        id: get_version
        run: echo ::set-output name=version::${GITHUB_REF/refs\/tags\//}

      - uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          target: aarch64-apple-darwin

      - uses: actions-rs/cargo@v1
        with:
          command: build
          args: --release --target=x86_64-apple-darwin

      - uses: actions-rs/cargo@v1
        with:
          command: build
          args: --release --target=aarch64-apple-darwin

      - uses: actions-rs/cargo@v1
        with:
          command: publish
          args: --token=${{ secrets.CRATES_TOKEN }}

      - name: Universal binary
        run: |
          mkdir -p target/universal-apple-darwin/release
          lipo -create -output target/universal-apple-darwin/release/ds target/aarch64-apple-darwin/release/ds target/x86_64-apple-darwin/release/ds

      - name: Create tar
        run: |
          tar -C ./target/universal-apple-darwin/release/ -czf dirstat-rs-${{ steps.get_version.outputs.version }}-universal-apple-darwin.tar.gz ./ds

      - name: Set SHA
        id: shasum
        run: |
          echo ::set-output name=sha::"$(shasum -a 256 ./dirstat-rs-${{ steps.get_version.outputs.version }}-universal-apple-darwin.tar.gz | awk '{printf $1}')"

      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          draft: false
          prerelease: false

      - name: Upload Release Asset
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: dirstat-rs-${{ steps.get_version.outputs.version }}-universal-apple-darwin.tar.gz
          asset_name: dirstat-rs-${{ steps.get_version.outputs.version }}-universal-apple-darwin.tar.gz
          asset_content_type: application/gzip

      - uses: mislav/bump-homebrew-formula-action@v1
        if: "!contains(github.ref, '-')"
        with:
          formula-name: dirstat-rs
          formula-path: Formula/dirstat-rs.rb
          homebrew-tap: scullionw/homebrew-tap
          base-branch: main
          download-url: https://github.com/scullionw/dirstat-rs/releases/download/${{ steps.get_version.outputs.version }}/dirstat-rs-${{ steps.get_version.outputs.version }}-universal-apple-darwin.tar.gz
          download-sha256: ${{ steps.shasum.outputs.sha }}
          commit-message: |
            {{formulaName}} {{version}}
        env:
          COMMITTER_TOKEN: ${{ secrets.BREW_TOKEN }}


================================================
FILE: .gitignore
================================================
/target
**/*.rs.bk



# Created by https://www.gitignore.io/api/linux,macos,windows
# Edit at https://www.gitignore.io/?templates=linux,macos,windows

### Linux ###
*~

# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*

# KDE directory preferences
.directory

# Linux trash folder which might appear on any partition or disk
.Trash-*

# .nfs files are created when an open file is removed but is still being accessed
.nfs*

### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### Windows ###
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk

# End of https://www.gitignore.io/api/linux,macos,windows

================================================
FILE: Cargo.toml
================================================
[package]
name = "dirstat-rs"
version = "0.3.8"
authors = ["scullionw <scuw1801@usherbrooke.ca>"]
edition = "2018"
license = "MIT"
readme = "README.md"
description = "A disk usage cli similar to windirstat"
repository = "https://github.com/scullionw/dirstat-rs"
keywords = ["cli", "disk", "usage", "tree", "windirstat"]
categories = ["command-line-utilities"]

[dependencies]
structopt = "0.2.18"
rayon = "1.5.1"
pretty-bytes = "0.2.2"
termcolor = "1.1.2"
atty = "0.2.14"
serde = { version = "1.0.131", features = ["derive"] }
serde_json = "1.0.73"

[target.'cfg(windows)'.dependencies]
winapi-util = "0.1.2"

[target.'cfg(windows)'.dependencies.winapi]
version = "0.3.7"
features = ["winerror"]

[profile.release]
lto = 'fat'
codegen-units = 1
incremental = false

[[bin]]
bench = false
path = "src/bin/main.rs"
name = "ds"


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 William Scullion

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# dirstat-rs

Fast, cross-platform disk usage CLI

[![Crates.io](https://img.shields.io/crates/v/dirstat-rs.svg)](https://crates.io/crates/dirstat-rs)
[![Docs.rs](https://docs.rs/dirstat-rs/badge.svg)](https://docs.rs/dirstat-rs/)
![Language](https://img.shields.io/badge/language-rust-orange)
![Platforms](https://img.shields.io/badge/platforms-Windows%2C%20macOS%20and%20Linux-blue)
![License](https://img.shields.io/github/license/scullionw/dirstat-rs)

![](demo/ds_demo.gif)

2X faster than du

4X faster than ncdu, dutree, dua, du-dust

6X faster than windirstat

(On 4-core hyperthreaded cpu)
        
# Installation

## Homebrew (macOS only)

    brew tap scullionw/tap
    brew install dirstat-rs

## Or if you prefer compiling yourself

### from crates.io:

        cargo install dirstat-rs
        
### or latest from git:

        cargo install --git "https://github.com/scullionw/dirstat-rs"
        
### or from source:

        cargo build --release
        sudo chmod +x /target/release/ds
        sudo cp /target/release/ds /usr/local/bin/

# Usage

### Current directory
    
        $ ds
    
### Specific path
 
        $ ds PATH

### Choose depth
 
        $ ds -d 3

### Show apparent file size

        $ ds -a PATH

### Override minimum size threshold

        $ ds -m 0.2 PATH



    
    
    
    


================================================
FILE: src/bin/main.rs
================================================
use atty::Stream;
use dirstat_rs::{DiskItem, FileInfo};
use pretty_bytes::converter::convert as pretty_bytes;
use std::env;
use std::error::Error;
use std::io;
use std::io::Write;
use std::path::PathBuf;
use structopt::StructOpt;
use termcolor::{Buffer, BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};

const INDENT_COLOR: Option<Color> = Some(Color::Rgb(75, 75, 75));

mod shape {
    pub const INDENT: &str = "│";
    pub const _LAST_WITH_CHILDREN: &str = "└─┬";
    pub const LAST: &str = "└──";
    pub const ITEM: &str = "├──";
    pub const _ITEM_WITH_CHILDREN: &str = "├─┬";
    pub const SPACING: &str = "──";
}

fn main() -> Result<(), Box<dyn Error>> {
    let config = Config::from_args();
    let current_dir = env::current_dir()?;
    let target_dir = config.target_dir.as_ref().unwrap_or(&current_dir);
    let file_info = FileInfo::from_path(&target_dir, config.apparent)?;

    let color_choice = if atty::is(Stream::Stdout) {
        ColorChoice::Auto
    } else {
        ColorChoice::Never
    };

    let stdout = BufferWriter::stdout(color_choice);
    let mut buffer = stdout.buffer();

    if !config.json {
        println!("\nAnalyzing: {}\n", target_dir.display())
    };

    let analysed = match file_info {
        FileInfo::Directory { volume_id } => {
            DiskItem::from_analyze(&target_dir, config.apparent, volume_id)?
        }
        _ => return Err(format!("{} is not a directory!", target_dir.display()).into()),
    };

    if config.json {
        let serialized = serde_json::to_string(&analysed)?;
        writeln!(&mut buffer, "{}", serialized)?;
    } else {
        show(&analysed, &config, &DisplayInfo::new(), &mut buffer)?;
    }

    stdout.print(&buffer)?;
    Ok(())
}

fn show(item: &DiskItem, conf: &Config, info: &DisplayInfo, buffer: &mut Buffer) -> io::Result<()> {
    // Show self
    show_item(item, &info, buffer)?;
    // Recursively show children
    if info.level < conf.max_depth {
        if let Some(children) = &item.children {
            let children = children
                .iter()
                .map(|child| (child, size_fraction(child, item)))
                .filter(|&(_, fraction)| fraction > conf.min_percent)
                .collect::<Vec<_>>();

            if let Some((last_child, children)) = children.split_last() {
                for &(child, fraction) in children.iter() {
                    show(child, conf, &info.add_item(fraction), buffer)?;
                }
                let &(child, fraction) = last_child;
                show(child, conf, &info.add_last(fraction), buffer)?;
            }
        }
    }
    Ok(())
}

fn show_item(item: &DiskItem, info: &DisplayInfo, buffer: &mut Buffer) -> io::Result<()> {
    // Indentation
    buffer.set_color(ColorSpec::new().set_fg(INDENT_COLOR))?;
    write!(buffer, "{}{}", info.indents, info.prefix())?;
    // Percentage
    buffer.set_color(ColorSpec::new().set_fg(info.color()))?;
    write!(buffer, " {} ", format!("{:.2}%", info.fraction))?;
    // Disk size
    buffer.reset()?;
    write!(buffer, "[{}]", pretty_bytes(item.disk_size as f64),)?;
    // Arrow
    buffer.set_color(ColorSpec::new().set_fg(INDENT_COLOR))?;
    write!(buffer, " {} ", shape::SPACING)?;
    // Name
    buffer.reset()?;
    writeln!(buffer, "{}", item.name)?;
    Ok(())
}

fn size_fraction(child: &DiskItem, parent: &DiskItem) -> f64 {
    100.0 * (child.disk_size as f64 / parent.disk_size as f64)
}

#[derive(Debug, Clone)]
struct DisplayInfo {
    fraction: f64,
    level: usize,
    last: bool,
    indents: String,
}

impl DisplayInfo {
    fn new() -> Self {
        Self {
            fraction: 100.0,
            level: 0,
            last: true,
            indents: String::new(),
        }
    }
    // TODO: Consume or mut instead of cloning
    fn add_item(&self, fraction: f64) -> Self {
        Self {
            fraction,
            level: self.level + 1,
            last: false,
            indents: self.indents.clone() + self.indent() + "  ",
        }
    }

    fn add_last(&self, fraction: f64) -> Self {
        Self {
            fraction,
            level: self.level + 1,
            last: true,
            indents: self.indents.clone() + self.indent() + "  ",
        }
    }

    fn indent(&self) -> &'static str {
        if self.last {
            " "
        } else {
            shape::INDENT
        }
    }

    fn prefix(&self) -> &'static str {
        if self.last {
            shape::LAST
        } else {
            shape::ITEM
        }
    }

    fn color(&self) -> Option<Color> {
        if self.level == 0 {
            Some(Color::Green)
        } else if self.fraction > 20.0 {
            Some(Color::Red)
        } else {
            Some(Color::Cyan)
        }
    }
}

#[derive(StructOpt)]
struct Config {
    #[structopt(short = "d", default_value = "1")]
    /// Maximum recursion depth in directory.
    max_depth: usize,

    #[structopt(
        short = "m",
        default_value = "0.1",
        parse(try_from_str = "parse_percent")
    )]
    /// Threshold that determines if entry is worth
    /// being shown. Between 0-100 % of dir size.
    min_percent: f64,

    #[structopt(parse(from_os_str))]
    target_dir: Option<PathBuf>,

    #[structopt(short = "a")]
    /// Show apparent file size.
    ///
    /// This reports logical file length instead of allocated size on disk.
    apparent: bool,

    #[structopt(short = "j")]
    /// Output sorted json.
    json: bool,
}

fn parse_percent(src: &str) -> Result<f64, Box<dyn Error>> {
    let num = src.parse::<f64>()?;
    if num >= 0.0 && num <= 100.0 {
        Ok(num)
    } else {
        Err("Percentage must be in range [0, 100].".into())
    }
}


================================================
FILE: src/ffi.rs
================================================
#![cfg(windows)]

use std::error::Error;
use std::io;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::path::Path;
use winapi::shared::winerror::NO_ERROR;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::fileapi::GetCompressedFileSizeW;
use winapi::um::fileapi::INVALID_FILE_SIZE;

pub fn compressed_size(path: &Path) -> Result<u64, Box<dyn Error>> {
    let wide: Vec<u16> = path.as_os_str().encode_wide().chain(once(0)).collect();
    let mut high: u32 = 0;

    // TODO: Deal with max path size
    let low = unsafe { GetCompressedFileSizeW(wide.as_ptr(), &mut high) };

    if low == INVALID_FILE_SIZE {
        let err = get_last_error();
        if err != NO_ERROR {
            return Err(io::Error::last_os_error().into());
        }
    }

    Ok(u64::from(high) << 32 | u64::from(low))
}

fn get_last_error() -> u32 {
    unsafe { GetLastError() }
}


================================================
FILE: src/lib.rs
================================================
use rayon::prelude::*;
use serde::Serialize;
use std::error::Error;
use std::ffi::OsStr;
use std::fs;
use std::path::Path;

mod ffi;

#[derive(Serialize)]
pub struct DiskItem {
    pub name: String,
    pub disk_size: u64,
    pub children: Option<Vec<DiskItem>>,
}

impl DiskItem {
    pub fn from_analyze(
        path: &Path,
        apparent: bool,
        root_dev: u64,
    ) -> Result<Self, Box<dyn Error>> {
        let name = path
            .file_name()
            .unwrap_or(&OsStr::new("."))
            .to_string_lossy()
            .to_string();

        let file_info = FileInfo::from_path(path, apparent)?;

        match file_info {
            FileInfo::Directory { volume_id } => {
                if volume_id != root_dev {
                    return Err("Filesystem boundary crossed".into());
                }

                let sub_entries = fs::read_dir(path)?
                    .filter_map(Result::ok)
                    .collect::<Vec<_>>();

                let mut sub_items = sub_entries
                    .par_iter()
                    .filter_map(|entry| {
                        DiskItem::from_analyze(&entry.path(), apparent, root_dev).ok()
                    })
                    .collect::<Vec<_>>();

                sub_items.sort_unstable_by(|a, b| a.disk_size.cmp(&b.disk_size).reverse());

                Ok(DiskItem {
                    name,
                    disk_size: sub_items.iter().map(|di| di.disk_size).sum(),
                    children: Some(sub_items),
                })
            }
            FileInfo::File { size, .. } => Ok(DiskItem {
                name,
                disk_size: size,
                children: None,
            }),
        }
    }
}

pub enum FileInfo {
    File { size: u64, volume_id: u64 },
    Directory { volume_id: u64 },
}

impl FileInfo {
    #[cfg(unix)]
    pub fn from_path(path: &Path, apparent: bool) -> Result<Self, Box<dyn Error>> {
        use std::os::unix::fs::MetadataExt;

        let md = path.symlink_metadata()?;
        if md.is_dir() {
            Ok(FileInfo::Directory {
                volume_id: md.dev(),
            })
        } else {
            let size = if apparent {
                md.len()
            } else {
                md.blocks() * 512
            };
            Ok(FileInfo::File {
                size,
                volume_id: md.dev(),
            })
        }
    }

    #[cfg(windows)]
    pub fn from_path(path: &Path, apparent: bool) -> Result<Self, Box<dyn Error>> {
        use winapi_util::{file, Handle};
        const FILE_ATTRIBUTE_DIRECTORY: u64 = 0x10;

        let h = Handle::from_path_any(path)?;
        let md = file::information(h)?;

        if md.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 {
            Ok(FileInfo::Directory {
                volume_id: md.volume_serial_number(),
            })
        } else {
            let size = if apparent {
                md.file_size()
            } else {
                ffi::compressed_size(path)?
            };
            Ok(FileInfo::File {
                size,
                volume_id: md.volume_serial_number(),
            })
        }
    }
}

#[cfg(all(test, unix))]
mod tests {
    use super::FileInfo;
    use std::error::Error;
    use std::fs::{self, File};
    use std::time::{SystemTime, UNIX_EPOCH};

    #[test]
    fn apparent_size_uses_logical_file_length() -> Result<(), Box<dyn Error>> {
        let dir = std::env::temp_dir().join(format!(
            "dirstat-rs-{}",
            SystemTime::now().duration_since(UNIX_EPOCH)?.as_nanos()
        ));
        fs::create_dir(&dir)?;
        let path = dir.join("sparse.bin");
        let file = File::create(&path)?;
        let sparse_len = 1024 * 1024;
        file.set_len(sparse_len)?;
        drop(file);

        let apparent_size = match FileInfo::from_path(&path, true)? {
            FileInfo::File { size, .. } => size,
            FileInfo::Directory { .. } => panic!("test path should be a file"),
        };
        let disk_size = match FileInfo::from_path(&path, false)? {
            FileInfo::File { size, .. } => size,
            FileInfo::Directory { .. } => panic!("test path should be a file"),
        };

        fs::remove_file(&path)?;
        fs::remove_dir(&dir)?;

        assert_eq!(apparent_size, sparse_len);
        assert!(disk_size <= apparent_size);
        Ok(())
    }
}
Download .txt
gitextract_khj5dz01/

├── .github/
│   └── workflows/
│       └── release.yaml
├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
└── src/
    ├── bin/
    │   └── main.rs
    ├── ffi.rs
    └── lib.rs
Download .txt
SYMBOL INDEX (28 symbols across 3 files)

FILE: src/bin/main.rs
  constant INDENT_COLOR (line 12) | const INDENT_COLOR: Option<Color> = Some(Color::Rgb(75, 75, 75));
  constant INDENT (line 15) | pub const INDENT: &str = "│";
  constant _LAST_WITH_CHILDREN (line 16) | pub const _LAST_WITH_CHILDREN: &str = "└─┬";
  constant LAST (line 17) | pub const LAST: &str = "└──";
  constant ITEM (line 18) | pub const ITEM: &str = "├──";
  constant _ITEM_WITH_CHILDREN (line 19) | pub const _ITEM_WITH_CHILDREN: &str = "├─┬";
  constant SPACING (line 20) | pub const SPACING: &str = "──";
  function main (line 23) | fn main() -> Result<(), Box<dyn Error>> {
  function show (line 60) | fn show(item: &DiskItem, conf: &Config, info: &DisplayInfo, buffer: &mut...
  function show_item (line 84) | fn show_item(item: &DiskItem, info: &DisplayInfo, buffer: &mut Buffer) -...
  function size_fraction (line 103) | fn size_fraction(child: &DiskItem, parent: &DiskItem) -> f64 {
  type DisplayInfo (line 108) | struct DisplayInfo {
    method new (line 116) | fn new() -> Self {
    method add_item (line 125) | fn add_item(&self, fraction: f64) -> Self {
    method add_last (line 134) | fn add_last(&self, fraction: f64) -> Self {
    method indent (line 143) | fn indent(&self) -> &'static str {
    method prefix (line 151) | fn prefix(&self) -> &'static str {
    method color (line 159) | fn color(&self) -> Option<Color> {
  type Config (line 171) | struct Config {
  function parse_percent (line 199) | fn parse_percent(src: &str) -> Result<f64, Box<dyn Error>> {

FILE: src/ffi.rs
  function compressed_size (line 13) | pub fn compressed_size(path: &Path) -> Result<u64, Box<dyn Error>> {
  function get_last_error (line 30) | fn get_last_error() -> u32 {

FILE: src/lib.rs
  type DiskItem (line 11) | pub struct DiskItem {
    method from_analyze (line 18) | pub fn from_analyze(
  type FileInfo (line 65) | pub enum FileInfo {
    method from_path (line 72) | pub fn from_path(path: &Path, apparent: bool) -> Result<Self, Box<dyn ...
    method from_path (line 94) | pub fn from_path(path: &Path, apparent: bool) -> Result<Self, Box<dyn ...
  function apparent_size_uses_logical_file_length (line 127) | fn apparent_size_uses_logical_file_length() -> Result<(), Box<dyn Error>> {
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (20K chars).
[
  {
    "path": ".github/workflows/release.yaml",
    "chars": 2892,
    "preview": "name: Release\n\non:\n  push:\n    tags:\n      - \"v*\"\n\njobs:\n  release:\n    runs-on: macos-11\n\n    steps:\n      - uses: acti"
  },
  {
    "path": ".gitignore",
    "chars": 1239,
    "preview": "/target\n**/*.rs.bk\n\n\n\n# Created by https://www.gitignore.io/api/linux,macos,windows\n# Edit at https://www.gitignore.io/?"
  },
  {
    "path": "Cargo.toml",
    "chars": 825,
    "preview": "[package]\nname = \"dirstat-rs\"\nversion = \"0.3.8\"\nauthors = [\"scullionw <scuw1801@usherbrooke.ca>\"]\nedition = \"2018\"\nlicen"
  },
  {
    "path": "LICENSE",
    "chars": 1073,
    "preview": "MIT License\n\nCopyright (c) 2019 William Scullion\n\nPermission is hereby granted, free of charge, to any person obtaining "
  },
  {
    "path": "README.md",
    "chars": 1324,
    "preview": "# dirstat-rs\n\nFast, cross-platform disk usage CLI\n\n[![Crates.io](https://img.shields.io/crates/v/dirstat-rs.svg)](https:"
  },
  {
    "path": "src/bin/main.rs",
    "chars": 5729,
    "preview": "use atty::Stream;\nuse dirstat_rs::{DiskItem, FileInfo};\nuse pretty_bytes::converter::convert as pretty_bytes;\nuse std::e"
  },
  {
    "path": "src/ffi.rs",
    "chars": 891,
    "preview": "#![cfg(windows)]\n\nuse std::error::Error;\nuse std::io;\nuse std::iter::once;\nuse std::os::windows::ffi::OsStrExt;\nuse std:"
  },
  {
    "path": "src/lib.rs",
    "chars": 4417,
    "preview": "use rayon::prelude::*;\nuse serde::Serialize;\nuse std::error::Error;\nuse std::ffi::OsStr;\nuse std::fs;\nuse std::path::Pat"
  }
]

About this extraction

This page contains the full source code of the scullionw/dirstat-rs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (18.0 KB), approximately 5.0k tokens, and a symbol index with 28 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!