Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Git integration #822

Merged
merged 4 commits into from
Apr 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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