Skip to content

Commit

Permalink
Git integration (#822)
Browse files Browse the repository at this point in the history
  • Loading branch information
hpwxf committed Apr 30, 2023
1 parent 6840c01 commit 2fe3fcd
Show file tree
Hide file tree
Showing 26 changed files with 1,056 additions and 38 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]
### Added
- Add [Git integration](https://github.com/Peltoche/lsd/issues/7) from [hpwxf](https://github.com/hpwxf)
- In keeping with the coreutils change, add quotes and escapes for necessary filenames from [merelymyself](https://github.com/merelymyself)
- Add support for icon theme from [zwpaper](https://github.com/zwpaper)
- Add icon for kt and kts from [LeeWeeder](https://github.com/LeeWeeder)
Expand Down
62 changes: 62 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ clap_complete = "4.1"
version_check = "0.9.*"

[dependencies]
crossterm = { version = "0.24.0", features = ["serde"]}
crossterm = { version = "0.24.0", features = ["serde"] }
dirs = "3.0.*"
libc = "0.2.*"
human-sort = "0.2.2"
Expand All @@ -42,6 +42,10 @@ serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.8"
url = "2.1.*"

[target."cfg(not(all(windows, target_arch = \"x86\", target_env = \"gnu\")))".dependencies]
# if ssl feature is enabled compilation will fail on arm-unknown-linux-gnueabihf and i686-pc-windows-gnu
git2 = { version = "0.16", optional = true, default-features = false }

[target.'cfg(unix)'.dependencies]
users = "0.11.*"
xattr = "0.2.*"
Expand All @@ -61,7 +65,9 @@ tempfile = "3"
serial_test = "0.5"

[features]
default = ["git2"]
sudo = []
no-git = [] # force disabling git even if available by default

[profile.release]
lto = true
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ classic: false
# == Blocks ==
# This specifies the columns and their order when using the long and the tree
# layout.
# Possible values: permission, user, group, context, size, date, name, inode, links
# Possible values: permission, user, group, context, size, date, name, inode, links, git
blocks:
- permission
- user
Expand Down
11 changes: 11 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,15 @@ fn main() {
generate_to(Zsh, &mut app, bin_name, &outdir).expect("Failed to generate Zsh completions");
generate_to(PowerShell, &mut app, bin_name, &outdir)
.expect("Failed to generate PowerShell completions");

// Disable git feature for these target where git2 is not well supported
if !std::env::var("CARGO_FEATURE_GIT2")
.map(|flag| flag == "1")
.unwrap_or(false)
|| std::env::var("TARGET")
.map(|target| target == "i686-pc-windows-gnu")
.unwrap_or(false)
{
println!(r#"cargo:rustc-cfg=feature="no-git""#);
}
}
2 changes: 1 addition & 1 deletion ci/before_deploy.bash
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
set -ex

build() {
cargo build --target "$TARGET" --release --verbose
cargo build --target "$TARGET" --features="$FEATURES" --release --verbose
}

pack() {
Expand Down
7 changes: 5 additions & 2 deletions doc/lsd.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ lsd is a ls command with a lot of pretty colours and some other stuff to enrich
`-X`, `--extensionsort`
: Sort by file extension

`--git`
: Display git status. Directory git status is a reduction of included file statuses (recursively).

`--help`
: Prints help information

Expand Down Expand Up @@ -90,7 +93,7 @@ lsd is a ls command with a lot of pretty colours and some other stuff to enrich
: Natural sort of (version) numbers within text

`--blocks <blocks>...`
: Specify the blocks that will be displayed and in what order [possible values: permission, user, group, size, date, name, inode]
: Specify the blocks that will be displayed and in what order [possible values: permission, user, group, size, date, name, inode, git]

`--color <color>...`
: When to use terminal colours [default: auto] [possible values: always, auto, never]
Expand Down Expand Up @@ -126,7 +129,7 @@ lsd is a ls command with a lot of pretty colours and some other stuff to enrich
: How to display size [default: default] [possible values: default, short, bytes]

`--sort <WORD>...`
: Sort by WORD instead of name [possible values: size, time, version, extension]
: Sort by WORD instead of name [possible values: size, time, version, extension, git]

`-U`, `--no-sort`
: Do not sort. List entries in directory order
Expand Down
49 changes: 37 additions & 12 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ pub struct Cli {
#[arg(short = 'X', long)]
pub extensionsort: bool,

/// Sort by git status
#[arg(short = 'G', long)]
pub gitsort: bool,

/// Natural sort of (version) numbers within text
#[arg(short = 'v', long)]
pub versionsort: bool,
Expand All @@ -104,13 +108,13 @@ pub struct Cli {
#[arg(
long,
value_name = "TYPE",
value_parser = ["size", "time", "version", "extension", "none"],
overrides_with_all = ["timesort", "sizesort", "extensionsort", "versionsort", "no_sort"]
value_parser = ["size", "time", "version", "extension", "git", "none"],
overrides_with_all = ["timesort", "sizesort", "extensionsort", "versionsort", "gitsort", "no_sort"]
)]
pub sort: Option<String>,

/// Do not sort. List entries in directory order
#[arg(short = 'U', long, overrides_with_all = ["timesort", "sizesort", "extensionsort", "versionsort", "sort"])]
#[arg(short = 'U', long, overrides_with_all = ["timesort", "sizesort", "extensionsort", "versionsort", "gitsort", "sort"])]
pub no_sort: bool,

/// Reverse the order of the sort
Expand All @@ -127,9 +131,9 @@ pub struct Cli {

/// Specify the blocks that will be displayed and in what order
#[arg(
long,
value_delimiter = ',',
value_parser = ["permission", "user", "group", "context", "size", "date", "name", "inode", "links"],
long,
value_delimiter = ',',
value_parser = ["permission", "user", "group", "context", "size", "date", "name", "inode", "links", "git"],
)]
pub blocks: Vec<String>,

Expand All @@ -150,6 +154,11 @@ pub struct Cli {
#[arg(short, long)]
pub inode: bool,

/// Show git status on file and directory"
/// Only when used with --long option
#[arg(short, long)]
pub git: bool,

/// When showing file information for a symbolic link,
/// show information for the file the link references rather than for the link itself
#[arg(short = 'L', long)]
Expand Down Expand Up @@ -196,23 +205,23 @@ pub fn validate_time_format(formatter: &str) -> Result<String, String> {
Some('f') => (),
Some(n @ ('3' | '6' | '9')) => match chars.next() {
Some('f') => (),
Some(c) => return Err(format!("invalid format specifier: %.{}{}", n, c)),
Some(c) => return Err(format!("invalid format specifier: %.{n}{c}")),
None => return Err("missing format specifier".to_owned()),
},
Some(c) => return Err(format!("invalid format specifier: %.{}", c)),
Some(c) => return Err(format!("invalid format specifier: %.{c}")),
None => return Err("missing format specifier".to_owned()),
},
Some(n @ (':' | '#')) => match chars.next() {
Some('z') => (),
Some(c) => return Err(format!("invalid format specifier: %{}{}", n, c)),
Some(c) => return Err(format!("invalid format specifier: %{n}{c}")),
None => return Err("missing format specifier".to_owned()),
},
Some(n @ ('-' | '_' | '0')) => match chars.next() {
Some(
'C' | 'd' | 'e' | 'f' | 'G' | 'g' | 'H' | 'I' | 'j' | 'k' | 'l' | 'M' | 'm'
| 'S' | 's' | 'U' | 'u' | 'V' | 'W' | 'w' | 'Y' | 'y',
) => (),
Some(c) => return Err(format!("invalid format specifier: %{}{}", n, c)),
Some(c) => return Err(format!("invalid format specifier: %{n}{c}")),
None => return Err("missing format specifier".to_owned()),
},
Some(
Expand All @@ -223,10 +232,10 @@ pub fn validate_time_format(formatter: &str) -> Result<String, String> {
) => (),
Some(n @ ('3' | '6' | '9')) => match chars.next() {
Some('f') => (),
Some(c) => return Err(format!("invalid format specifier: %{}{}", n, c)),
Some(c) => return Err(format!("invalid format specifier: %{n}{c}")),
None => return Err("missing format specifier".to_owned()),
},
Some(c) => return Err(format!("invalid format specifier: %{}", c)),
Some(c) => return Err(format!("invalid format specifier: %{c}")),
None => return Err("missing format specifier".to_owned()),
},
None => break,
Expand All @@ -235,3 +244,19 @@ pub fn validate_time_format(formatter: &str) -> Result<String, String> {
}
Ok(formatter.to_owned())
}

// Wrapper for value_parser to simply remove non supported option (mainly git flag)
// required since value_parser requires impl Into<ValueParser> that Vec do not support
// should be located here, since this file is included by build.rs
struct LabelFilter<Filter: Fn(&'static str) -> bool, const C: usize>([&'static str; C], Filter);

impl<Filter: Fn(&'static str) -> bool, const C: usize> From<LabelFilter<Filter, C>>
for clap::builder::ValueParser
{
fn from(label_filter: LabelFilter<Filter, C>) -> Self {
let filter = label_filter.1;
let values = label_filter.0.into_iter().filter(|x| filter(x));
let inner = clap::builder::PossibleValuesParser::from(values);
Self::from(inner)
}
}
7 changes: 7 additions & 0 deletions src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use lscolors::{Indicator, LsColors};
use std::path::Path;

pub use crate::flags::color::ThemeOption;
use crate::git::GitStatus;
use crate::theme::{color::ColorTheme, Theme};

#[allow(dead_code)]
Expand Down Expand Up @@ -61,6 +62,10 @@ pub enum Elem {
},

TreeEdge,

GitStatus {
status: GitStatus,
},
}

impl Elem {
Expand Down Expand Up @@ -121,6 +126,7 @@ impl Elem {
Elem::TreeEdge => theme.tree_edge,
Elem::Links { valid: false } => theme.links.invalid,
Elem::Links { valid: true } => theme.links.valid,
Elem::GitStatus { .. } => theme.git_status.default,
}
}
}
Expand Down Expand Up @@ -389,6 +395,7 @@ mod elem {
invalid: Color::AnsiValue(245), // Grey
},
tree_edge: Color::AnsiValue(245), // Grey
git_status: Default::default(),
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/config_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ classic: false
# == Blocks ==
# This specifies the columns and their order when using the long and the tree
# layout.
# Possible values: permission, user, group, context, size, date, name, inode
# Possible values: permission, user, group, context, size, date, name, inode, git
blocks:
- permission
- user
Expand Down Expand Up @@ -388,7 +388,7 @@ mod tests {
total_size: Some(false),
symlink_arrow: Some("⇒".into()),
hyperlink: Some(HyperlinkOption::Never),
header: None
header: None,
},
c
);
Expand Down
Loading

0 comments on commit 2fe3fcd

Please sign in to comment.