Merge branch 'master' into chesterliu/dev/win-support

This commit is contained in:
Chester Liu 2021-10-29 15:50:54 +08:00
commit 99d653b7fa
23 changed files with 195 additions and 89 deletions

54
.github/workflows/unit-tests.yml vendored Normal file
View File

@ -0,0 +1,54 @@
name: Unit tests
on:
push:
branches: [ master ]
paths:
- '.github/workflows/*'
- 'src/**'
- 'Cargo.*'
- build.rs
pull_request:
branches: [ master ]
paths:
- '.github/workflows/*'
- 'src/**'
- 'Cargo.*'
- build.rs
env:
CARGO_TERM_COLOR: always
jobs:
unit-tests:
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.rust == 'nightly' }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust: [1.48.0, stable, beta, nightly]
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Install Rust toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
- name: Install cargo-hack
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-hack
- name: Run unit tests
uses: actions-rs/cargo@v1
with:
command: hack
args: test --feature-powerset

View File

@ -1,19 +0,0 @@
language: rust
rust:
- 1.45.2
- stable
- beta
- nightly
jobs:
fast_finish: true
allow_failures:
- rust: nightly
include:
- name: 'Rust: test with all features'
rust: stable
install:
- cargo install cargo-hack
script:
- cargo hack test --feature-powerset

10
Cargo.lock generated
View File

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.12.1" version = "0.12.1"
@ -90,9 +92,9 @@ dependencies = [
[[package]] [[package]]
name = "git2" name = "git2"
version = "0.13.18" version = "0.13.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b483c6c2145421099df1b4efd50e0f6205479a072199460eff852fa15e5603c7" checksum = "d9831e983241f8c5591ed53f17d874833e2fa82cac2625f3888c50cbfe136cba"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"libc", "libc",
@ -151,9 +153,9 @@ checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
[[package]] [[package]]
name = "libgit2-sys" name = "libgit2-sys"
version = "0.12.19+1.1.0" version = "0.12.21+1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f322155d574c8b9ebe991a04f6908bb49e68a79463338d24a43d6274cb6443e6" checksum = "86271bacd72b2b9e854c3dcfb82efd538f15f870e4c11af66900effb462f6825"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",

View File

@ -1,11 +1,11 @@
[package] [package]
name = "exa" name = "exa"
description = "A modern replacement for ls" description = "A modern replacement for ls"
authors = ["Benjamin Sago <ogham@bsago.me>"] authors = ["Benjamin Sago <ogham@bsago.me>"]
categories = ["command-line-utilities"] categories = ["command-line-utilities"]
edition = "2018" edition = "2018"
exclude = ["/devtools/*", "/Justfile", "/Vagrantfile", "/screenshots.png"] exclude = ["/devtools/*", "/Justfile", "/Vagrantfile", "/screenshots.png"]
readme = "README.md"
homepage = "https://the.exa.website/" homepage = "https://the.exa.website/"
license = "MIT" license = "MIT"
repository = "https://github.com/ogham/exa" repository = "https://github.com/ogham/exa"
@ -65,7 +65,7 @@ lto = true
[package.metadata.deb] [package.metadata.deb]
license-file = [ "LICENCE" ] license-file = [ "LICENCE", "4" ]
depends = "$auto" depends = "$auto"
extended-description = """ extended-description = """
exa is a replacement for ls written in Rust. exa is a replacement for ls written in Rust.
@ -74,6 +74,9 @@ section = "utils"
priority = "optional" priority = "optional"
assets = [ assets = [
[ "target/release/exa", "/usr/bin/exa", "0755" ], [ "target/release/exa", "/usr/bin/exa", "0755" ],
[ "contrib/man/exa.1", "/usr/share/man/man1/exa.1", "0644" ], [ "target/release/../man/exa.1", "/usr/share/man/man1/exa.1", "0644" ],
[ "contrib/completions.bash", "/etc/bash_completion.d/exa", "0644" ], [ "target/release/../man/exa_colors.5", "/usr/share/man/man5/exa_colors.5", "0644" ],
[ "completions/bash/exa", "/usr/share/bash-completion/completions/exa", "0644" ],
[ "completions/zsh/_exa", "/usr/share/zsh/site-functions/_exa", "0644" ],
[ "completions/fish/exa.fish", "/usr/share/fish/vendor_completions.d/exa.fish", "0644" ],
] ]

View File

@ -1,17 +1,13 @@
<div align="center"> <div align="center">
<h1>exa</h1>
# exa
[exa](https://the.exa.website/) is a modern replacement for _ls_. [exa](https://the.exa.website/) is a modern replacement for _ls_.
**README Sections:** [Options](#options) — [Installation](#installation) — [Development](#development) **README Sections:** [Options](#options) — [Installation](#installation) — [Development](#development)
<a href="https://travis-ci.org/github/ogham/exa"> [![Unit tests](https://github.com/ogham/exa/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/ogham/exa/actions/workflows/unit-tests.yml)
<img src="https://travis-ci.org/ogham/exa.svg?branch=master" alt="Build status" /> [![Say thanks!](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/ogham%40bsago.me)
</a>
<a href="https://saythanks.io/to/ogham%40bsago.me">
<img src="https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg" alt="Say thanks!" />
</a>
</div> </div>
![Screenshots of exa](screenshots.png) ![Screenshots of exa](screenshots.png)

View File

@ -38,9 +38,10 @@ fn main() -> io::Result<()> {
// We need to create these files in the Cargo output directory. // We need to create these files in the Cargo output directory.
let out = PathBuf::from(env::var("OUT_DIR").unwrap()); let out = PathBuf::from(env::var("OUT_DIR").unwrap());
let path = &out.join("version_string.txt");
// Bland version text // Bland version text
let mut f = File::create(&out.join("version_string.txt"))?; let mut f = File::create(path).expect(&path.to_string_lossy());
writeln!(f, "{}", strip_codes(&ver))?; writeln!(f, "{}", strip_codes(&ver))?;
Ok(()) Ok(())

View File

@ -8,6 +8,11 @@ _exa()
return return
;; ;;
--colour)
COMPREPLY=( $( compgen -W 'always auto never' -- "$cur" ) )
return
;;
-L|--level) -L|--level)
COMPREPLY=( $( compgen -W '{0..9}' -- "$cur" ) ) COMPREPLY=( $( compgen -W '{0..9}' -- "$cur" ) )
return return
@ -19,19 +24,28 @@ _exa()
;; ;;
-t|--time) -t|--time)
COMPREPLY=( $( compgen -W 'modified changed accessed created --' -- $cur ) ) COMPREPLY=( $( compgen -W 'modified changed accessed created --' -- "$cur" ) )
return return
;; ;;
--time-style) --time-style)
COMPREPLY=( $( compgen -W 'default iso long-iso full-iso --' -- $cur ) ) COMPREPLY=( $( compgen -W 'default iso long-iso full-iso --' -- "$cur" ) )
return return
;; ;;
esac esac
case "$cur" in case "$cur" in
# _parse_help doesnt pick up short options when they are on the same line than long options
--*)
# colo[u]r isnt parsed correctly so we filter these options out and add them by hand
parse_help=$( exa --help | grep -oE ' (\-\-[[:alnum:]@-]+)' | tr -d ' ' | grep -v '\-\-colo' )
completions=$( echo '--color --colour --color-scale --colour-scale' $parse_help )
COMPREPLY=( $( compgen -W "$completions" -- "$cur" ) )
;;
-*) -*)
COMPREPLY=( $( compgen -W '$( _parse_help "$1" )' -- "$cur" ) ) completions=$( exa --help | grep -oE ' (\-[[:alnum:]@])' | tr -d ' ' )
COMPREPLY=( $( compgen -W "$completions" -- "$cur" ) )
;; ;;
*) *)

View File

@ -10,10 +10,14 @@ complete -c exa -s 'x' -l 'across' -d "Sort the grid across, rather than d
complete -c exa -s 'R' -l 'recurse' -d "Recurse into directories" complete -c exa -s 'R' -l 'recurse' -d "Recurse into directories"
complete -c exa -s 'T' -l 'tree' -d "Recurse into directories as a tree" complete -c exa -s 'T' -l 'tree' -d "Recurse into directories as a tree"
complete -c exa -s 'F' -l 'classify' -d "Display type indicator by file names" complete -c exa -s 'F' -l 'classify' -d "Display type indicator by file names"
complete -c exa -l 'color' -d "When to use terminal colours" complete -c exa -l 'color' \
complete -c exa -l 'colour' -d "When to use terminal colours" -l 'colour' -d "When to use terminal colours" -x -a "
complete -c exa -l 'color-scale' -d "Highlight levels of file sizes distinctly" always\t'Always use colour'
complete -c exa -l 'colour-scale' -d "Highlight levels of file sizes distinctly" auto\t'Use colour if standard output is a terminal'
never\t'Never use colour'
"
complete -c exa -l 'color-scale' \
-l 'colour-scale' -d "Highlight levels of file sizes distinctly"
complete -c exa -l 'icons' -d "Display icons" complete -c exa -l 'icons' -d "Display icons"
complete -c exa -l 'no-icons' -d "Don't display icons" complete -c exa -l 'no-icons' -d "Don't display icons"
@ -22,9 +26,9 @@ complete -c exa -l 'group-directories-first' -d "Sort directories before other f
complete -c exa -l 'git-ignore' -d "Ignore files mentioned in '.gitignore'" complete -c exa -l 'git-ignore' -d "Ignore files mentioned in '.gitignore'"
complete -c exa -s 'a' -l 'all' -d "Show hidden and 'dot' files" complete -c exa -s 'a' -l 'all' -d "Show hidden and 'dot' files"
complete -c exa -s 'd' -l 'list-dirs' -d "List directories like regular files" complete -c exa -s 'd' -l 'list-dirs' -d "List directories like regular files"
complete -c exa -s 'L' -l 'level' -d "Limit the depth of recursion" -a "1 2 3 4 5 6 7 8 9" complete -c exa -s 'L' -l 'level' -d "Limit the depth of recursion" -x -a "1 2 3 4 5 6 7 8 9"
complete -c exa -s 'r' -l 'reverse' -d "Reverse the sort order" complete -c exa -s 'r' -l 'reverse' -d "Reverse the sort order"
complete -c exa -s 's' -l 'sort' -x -d "Which field to sort by" -a " complete -c exa -s 's' -l 'sort' -d "Which field to sort by" -x -a "
accessed\t'Sort by file accessed time' accessed\t'Sort by file accessed time'
age\t'Sort by file modified time (newest first)' age\t'Sort by file modified time (newest first)'
changed\t'Sort by changed time' changed\t'Sort by changed time'
@ -56,10 +60,10 @@ complete -c exa -s 'b' -l 'binary' -d "List file sizes with binary prefixes"
complete -c exa -s 'B' -l 'bytes' -d "List file sizes in bytes, without any prefixes" complete -c exa -s 'B' -l 'bytes' -d "List file sizes in bytes, without any prefixes"
complete -c exa -s 'g' -l 'group' -d "List each file's group" complete -c exa -s 'g' -l 'group' -d "List each file's group"
complete -c exa -s 'h' -l 'header' -d "Add a header row to each column" complete -c exa -s 'h' -l 'header' -d "Add a header row to each column"
complete -c exa -s 'h' -l 'links' -d "List each file's number of hard links" complete -c exa -s 'H' -l 'links' -d "List each file's number of hard links"
complete -c exa -s 'g' -l 'group' -d "List each file's inode number" complete -c exa -s 'g' -l 'group' -d "List each file's inode number"
complete -c exa -s 'S' -l 'blocks' -d "List each file's number of filesystem blocks" complete -c exa -s 'S' -l 'blocks' -d "List each file's number of filesystem blocks"
complete -c exa -s 't' -l 'time' -x -d "Which timestamp field to list" -a " complete -c exa -s 't' -l 'time' -d "Which timestamp field to list" -x -a "
modified\t'Display modified time' modified\t'Display modified time'
changed\t'Display changed time' changed\t'Display changed time'
accessed\t'Display accessed time' accessed\t'Display accessed time'
@ -70,7 +74,7 @@ complete -c exa -s 'n' -l 'numeric' -d "List numeric user and group IDs."
complete -c exa -l 'changed' -d "Use the changed timestamp field" complete -c exa -l 'changed' -d "Use the changed timestamp field"
complete -c exa -s 'u' -l 'accessed' -d "Use the accessed timestamp field" complete -c exa -s 'u' -l 'accessed' -d "Use the accessed timestamp field"
complete -c exa -s 'U' -l 'created' -d "Use the created timestamp field" complete -c exa -s 'U' -l 'created' -d "Use the created timestamp field"
complete -c exa -l 'time-style' -x -d "How to format timestamps" -a " complete -c exa -l 'time-style' -d "How to format timestamps" -x -a "
default\t'Use the default time style' default\t'Use the default time style'
iso\t'Display brief ISO timestamps' iso\t'Display brief ISO timestamps'
long-iso\t'Display longer ISO timestaps, up to the minute' long-iso\t'Display longer ISO timestaps, up to the minute'

View File

@ -1,7 +1,7 @@
#compdef exa #compdef exa
# Save this file as _exa in /usr/local/share/zsh/site-functions or in any # Save this file as _exa in /usr/local/share/zsh/site-functions or in any
# other folder in $fpath. E. g. save it in a folder called ~/.zfunc and add a # other folder in $fpath. E.g. save it in a folder called ~/.zfunc and add a
# line containing `fpath=(~/.zfunc $fpath)` somewhere before `compinit` in your # line containing `fpath=(~/.zfunc $fpath)` somewhere before `compinit` in your
# ~/.zshrc. # ~/.zshrc.
@ -19,7 +19,7 @@ __exa() {
{-R,--recurse}"[Recurse into directories]" \ {-R,--recurse}"[Recurse into directories]" \
{-T,--tree}"[Recurse into directories as a tree]" \ {-T,--tree}"[Recurse into directories as a tree]" \
{-F,--classify}"[Display type indicator by file names]" \ {-F,--classify}"[Display type indicator by file names]" \
--colo{,u}r"[When to use terminal colours]" \ --colo{,u}r="[When to use terminal colours]:(when):(always auto never)" \
--colo{,u}r-scale"[Highlight levels of file sizes distinctly]" \ --colo{,u}r-scale"[Highlight levels of file sizes distinctly]" \
--icons"[Display icons]" \ --icons"[Display icons]" \
--no-icons"[Hide icons]" \ --no-icons"[Hide icons]" \

View File

@ -11,17 +11,17 @@ bash /vagrant/devtools/dev-versions.sh
# Configure the Cool Prompt™ (not actually trademarked). # Configure the Cool Prompt™ (not actually trademarked).
# The Cool Prompt tells you whether youre in debug or strict mode, whether # The Cool Prompt tells you whether youre in debug or strict mode, whether
# you have colours configured, and whether your last command failed. # you have colours configured, and whether your last command failed.
function nonzero_return() { RETVAL=$?; [ $RETVAL -ne 0 ] && echo "$RETVAL "; } nonzero_return() { RETVAL=$?; [ "$RETVAL" -ne 0 ] && echo "$RETVAL "; }
function debug_mode() { [ "$EXA_DEBUG" == "trace" ] && echo -n "trace-"; [ -n "$EXA_DEBUG" ] && echo "debug "; } debug_mode() { [ "$EXA_DEBUG" == "trace" ] && echo -n "trace-"; [ -n "$EXA_DEBUG" ] && echo "debug "; }
function strict_mode() { [ -n "$EXA_STRICT" ] && echo "strict "; } strict_mode() { [ -n "$EXA_STRICT" ] && echo "strict "; }
function lsc_mode() { [ -n "$LS_COLORS" ] && echo "lsc "; } lsc_mode() { [ -n "$LS_COLORS" ] && echo "lsc "; }
function exac_mode() { [ -n "$EXA_COLORS" ] && echo "exac "; } exac_mode() { [ -n "$EXA_COLORS" ] && echo "exac "; }
export PS1="\[\e[1;36m\]\h \[\e[32m\]\w \[\e[31m\]\`nonzero_return\`\[\e[35m\]\`debug_mode\`\[\e[32m\]\`lsc_mode\`\[\e[1;32m\]\`exac_mode\`\[\e[33m\]\`strict_mode\`\[\e[36m\]\\$\[\e[0m\] " export PS1="\[\e[1;36m\]\h \[\e[32m\]\w \[\e[31m\]\`nonzero_return\`\[\e[35m\]\`debug_mode\`\[\e[32m\]\`lsc_mode\`\[\e[1;32m\]\`exac_mode\`\[\e[33m\]\`strict_mode\`\[\e[36m\]\\$\[\e[0m\] "
# The debug function lets you switch debug mode on and off. # The debug function lets you switch debug mode on and off.
# Turn it on if you need to see exas debugging logs. # Turn it on if you need to see exas debugging logs.
function debug () { debug() {
case "$1" in case "$1" in
""|"on") export EXA_DEBUG=1 ;; ""|"on") export EXA_DEBUG=1 ;;
"off") export EXA_DEBUG= ;; "off") export EXA_DEBUG= ;;
@ -33,11 +33,12 @@ function debug () {
# The strict function lets you switch strict mode on and off. # The strict function lets you switch strict mode on and off.
# Turn it on if youd like exas command-line arguments checked. # Turn it on if youd like exas command-line arguments checked.
function strict () { strict() {
case "$1" in "on") export EXA_STRICT=1 ;; case "$1" in
"on") export EXA_STRICT=1 ;;
"off") export EXA_STRICT= ;; "off") export EXA_STRICT= ;;
"") [ -n "$EXA_STRICT" ] && echo "strict on" || echo "strict off" ;; "") [ -n "$EXA_STRICT" ] && echo "strict on" || echo "strict off" ;;
*) echo "Usage: strict on|off"; return 1 ;; *) echo "Usage: strict on|off"; return 1 ;;
esac; esac;
} }
@ -45,7 +46,7 @@ function strict () {
# environment variables. Theres also a hacker theme which turns everything # environment variables. Theres also a hacker theme which turns everything
# green, which is usually used for checking that all colour codes work, and # green, which is usually used for checking that all colour codes work, and
# for looking cool while you phreak some mainframes or whatever. # for looking cool while you phreak some mainframes or whatever.
function colors () { colors() {
case "$1" in case "$1" in
"ls") "ls")
export LS_COLORS="di=34:ln=35:so=32:pi=33:ex=31:bd=34;46:cd=34;43:su=30;41:sg=30;46:tw=30;42:ow=30;43" export LS_COLORS="di=34:ln=35:so=32:pi=33:ex=31:bd=34;46:cd=34;43:su=30;41:sg=30;46:tw=30;42:ow=30;43"

View File

@ -252,7 +252,7 @@ sudo chown $FIXED_USER:$FIXED_USER -R "$TEST_ROOT/attributes"
# A sample Git repository # A sample Git repository
# This uses cd because it's easier than telling Git where to go each time # This uses cd because it's easier than telling Git where to go each time
echo -e "\033[1m[10/13]\033[0m Creating Git testcases (1/3)" echo -e "\033[1m[10/13]\033[0m Creating Git testcases (1/4)"
mkdir "$TEST_ROOT/git" mkdir "$TEST_ROOT/git"
cd "$TEST_ROOT/git" cd "$TEST_ROOT/git"
git init >/dev/null git init >/dev/null
@ -281,7 +281,7 @@ sudo chown $FIXED_USER:$FIXED_USER -R "$TEST_ROOT/git"
# A second Git repository # A second Git repository
# for testing two at once # for testing two at once
echo -e "\033[1m[11/13]\033[0m Creating Git testcases (2/3)" echo -e "\033[1m[11/13]\033[0m Creating Git testcases (2/4)"
mkdir -p "$TEST_ROOT/git2/deeply/nested/directory" mkdir -p "$TEST_ROOT/git2/deeply/nested/directory"
cd "$TEST_ROOT/git2" cd "$TEST_ROOT/git2"
git init >/dev/null git init >/dev/null
@ -321,7 +321,7 @@ sudo chown $FIXED_USER:$FIXED_USER -R "$TEST_ROOT/git2"
# A third Git repository # A third Git repository
# Regression test for https://github.com/ogham/exa/issues/526 # Regression test for https://github.com/ogham/exa/issues/526
echo -e "\033[1m[12/13]\033[0m Creating Git testcases (3/3)" echo -e "\033[1m[12/13]\033[0m Creating Git testcases (3/4)"
mkdir -p "$TEST_ROOT/git3" mkdir -p "$TEST_ROOT/git3"
cd "$TEST_ROOT/git3" cd "$TEST_ROOT/git3"
git init >/dev/null git init >/dev/null
@ -334,6 +334,20 @@ find "$TEST_ROOT/git3" -exec touch {} -h -t $FIXED_DATE \;
sudo chown $FIXED_USER:$FIXED_USER -R "$TEST_ROOT/git3" sudo chown $FIXED_USER:$FIXED_USER -R "$TEST_ROOT/git3"
# A fourth Git repository
# Regression test for https://github.com/ogham/exa/issues/698
echo -e "\033[1m[12/13]\033[0m Creating Git testcases (4/4)"
mkdir -p "$TEST_ROOT/git4"
cd "$TEST_ROOT/git4"
git init >/dev/null
# Create a non UTF-8 file
touch 'P'$'\b\211''UUU'
find "$TEST_ROOT/git4" -exec touch {} -h -t $FIXED_DATE \;
sudo chown $FIXED_USER:$FIXED_USER -R "$TEST_ROOT/git4"
# Hidden and dot file testcases. # Hidden and dot file testcases.
# We need to set the permissions of `.` and `..` because they actually # We need to set the permissions of `.` and `..` because they actually
# get displayed in the output here, so this has to come last. # get displayed in the output here, so this has to come last.

View File

@ -9,7 +9,7 @@ set -e
# Linux check! # Linux check!
uname=`uname -s` uname=$(uname -s)
if [[ "$uname" != "Linux" ]]; then if [[ "$uname" != "Linux" ]]; then
echo "Gotta be on Linux to run this (detected '$uname')!" echo "Gotta be on Linux to run this (detected '$uname')!"
exit 1 exit 1
@ -29,8 +29,8 @@ fi
# Weekly builds have a bit more information in their version number (see build.rs). # Weekly builds have a bit more information in their version number (see build.rs).
if [[ "$1" == "--weekly" ]]; then if [[ "$1" == "--weekly" ]]; then
git_hash=`GIT_DIR=/vagrant/.git git rev-parse --short --verify HEAD` git_hash=$(GIT_DIR=/vagrant/.git git rev-parse --short --verify HEAD)
date=`date +"%Y-%m-%d"` date=$(date +"%Y-%m-%d")
echo "Building exa weekly v$exa_version, date $date, Git hash $git_hash" echo "Building exa weekly v$exa_version, date $date, Git hash $git_hash"
else else
echo "Building exa v$exa_version" echo "Building exa v$exa_version"
@ -57,9 +57,10 @@ strip -v "$exa_linux_binary"
# the binaries can have consistent names, and its still possible to tell # the binaries can have consistent names, and its still possible to tell
# different *downloads* apart. # different *downloads* apart.
echo -e "\n\033[4mZipping binary...\033[0m" echo -e "\n\033[4mZipping binary...\033[0m"
if [[ "$1" == "--weekly" ]] if [[ "$1" == "--weekly" ]]; then
then exa_linux_zip="/vagrant/exa-linux-x86_64-${exa_version}-${date}-${git_hash}.zip" exa_linux_zip="/vagrant/exa-linux-x86_64-${exa_version}-${date}-${git_hash}.zip"
else exa_linux_zip="/vagrant/exa-linux-x86_64.zip" else
exa_linux_zip="/vagrant/exa-linux-x86_64.zip"
fi fi
rm -vf "$exa_linux_zip" rm -vf "$exa_linux_zip"
zip -j "$exa_linux_zip" "$exa_linux_binary" zip -j "$exa_linux_zip" "$exa_linux_binary"

View File

@ -11,7 +11,7 @@ set -e
# Virtualising macOS is a legal minefield, so this script is local instead # Virtualising macOS is a legal minefield, so this script is local instead
# of dev: I run it from my actual machine, rather than from a VM. # of dev: I run it from my actual machine, rather than from a VM.
uname=`uname -s` uname=$(uname -s)
if [[ "$uname" != "Darwin" ]]; then if [[ "$uname" != "Darwin" ]]; then
echo "Gotta be on Darwin to run this (detected '$uname')!" echo "Gotta be on Darwin to run this (detected '$uname')!"
exit 1 exit 1
@ -36,8 +36,8 @@ fi
# Weekly builds have a bit more information in their version number (see build.rs). # Weekly builds have a bit more information in their version number (see build.rs).
if [[ "$1" == "--weekly" ]]; then if [[ "$1" == "--weekly" ]]; then
git_hash=`GIT_DIR=$exa_root/.git git rev-parse --short --verify HEAD` git_hash=$(GIT_DIR=$exa_root/.git git rev-parse --short --verify HEAD)
date=`date +"%Y-%m-%d"` date=$(date +"%Y-%m-%d")
echo "Building exa weekly v$exa_version, date $date, Git hash $git_hash" echo "Building exa weekly v$exa_version, date $date, Git hash $git_hash"
else else
echo "Building exa v$exa_version" echo "Building exa v$exa_version"
@ -65,9 +65,10 @@ echo "strip $exa_macos_binary"
# the binaries can have consistent names, and its still possible to tell # the binaries can have consistent names, and its still possible to tell
# different *downloads* apart. # different *downloads* apart.
echo -e "\n\033[4mZipping binary...\033[0m" echo -e "\n\033[4mZipping binary...\033[0m"
if [[ "$1" == "--weekly" ]] if [[ "$1" == "--weekly" ]]; then
then exa_macos_zip="$exa_root/exa-macos-x86_64-${exa_version}-${date}-${git_hash}.zip" exa_macos_zip="$exa_root/exa-macos-x86_64-${exa_version}-${date}-${git_hash}.zip"
else exa_macos_zip="$exa_root/exa-macos-x86_64-${exa_version}.zip" else
exa_macos_zip="$exa_root/exa-macos-x86_64-${exa_version}.zip"
fi fi
rm -vf "$exa_macos_zip" | sed 's/^/removing /' rm -vf "$exa_macos_zip" | sed 's/^/removing /'
zip -j "$exa_macos_zip" "$exa_macos_binary" zip -j "$exa_macos_zip" "$exa_macos_binary"

View File

@ -51,7 +51,7 @@ impl DirAction {
match self { match self {
Self::AsFile => true, Self::AsFile => true,
Self::Recurse(o) => o.tree, Self::Recurse(o) => o.tree,
_ => false, Self::List => false,
} }
} }
} }

View File

@ -1,5 +1,8 @@
//! Getting the Git status of files and directories. //! Getting the Git status of files and directories.
use std::ffi::OsStr;
#[cfg(target_family = "unix")]
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Mutex; use std::sync::Mutex;
@ -205,6 +208,11 @@ fn repo_to_statuses(repo: &git2::Repository, workdir: &Path) -> Git {
match repo.statuses(None) { match repo.statuses(None) {
Ok(es) => { Ok(es) => {
for e in es.iter() { for e in es.iter() {
#[cfg(target_family = "unix")]
let path = workdir.join(Path::new(OsStr::from_bytes(e.path_bytes())));
// TODO: handle non Unix systems better:
// https://github.com/ogham/exa/issues/698
#[cfg(not(target_family = "unix"))]
let path = workdir.join(Path::new(e.path().unwrap())); let path = workdir.join(Path::new(e.path().unwrap()));
let elem = (path, e.status()); let elem = (path, e.status());
statuses.push(elem); statuses.push(elem);

View File

@ -26,7 +26,7 @@ impl FileExtensions {
file.name_is_one_of( &[ file.name_is_one_of( &[
"Makefile", "Cargo.toml", "SConstruct", "CMakeLists.txt", "Makefile", "Cargo.toml", "SConstruct", "CMakeLists.txt",
"build.gradle", "pom.xml", "Rakefile", "package.json", "Gruntfile.js", "build.gradle", "pom.xml", "Rakefile", "package.json", "Gruntfile.js",
"Gruntfile.coffee", "BUILD", "BUILD.bazel", "WORKSPACE", "build.xml", "Gruntfile.coffee", "BUILD", "BUILD.bazel", "WORKSPACE", "build.xml", "Podfile",
"webpack.config.js", "meson.build", "composer.json", "RoboFile.php", "PKGBUILD", "webpack.config.js", "meson.build", "composer.json", "RoboFile.php", "PKGBUILD",
"Justfile", "Procfile", "Dockerfile", "Containerfile", "Vagrantfile", "Brewfile", "Justfile", "Procfile", "Dockerfile", "Containerfile", "Vagrantfile", "Brewfile",
"Gemfile", "Pipfile", "build.sbt", "mix.exs", "bsconfig.json", "tsconfig.json", "Gemfile", "Pipfile", "build.sbt", "mix.exs", "bsconfig.json", "tsconfig.json",
@ -35,10 +35,10 @@ impl FileExtensions {
fn is_image(&self, file: &File<'_>) -> bool { fn is_image(&self, file: &File<'_>) -> bool {
file.extension_is_one_of( &[ file.extension_is_one_of( &[
"png", "jpeg", "jpg", "gif", "bmp", "tiff", "tif", "png", "jfi", "jfif", "jif", "jpe", "jpeg", "jpg", "gif", "bmp",
"ppm", "pgm", "pbm", "pnm", "webp", "raw", "arw", "tiff", "tif", "ppm", "pgm", "pbm", "pnm", "webp", "raw", "arw",
"svg", "stl", "eps", "dvi", "ps", "cbr", "jpf", "svg", "stl", "eps", "dvi", "ps", "cbr", "jpf", "cbz", "xpm",
"cbz", "xpm", "ico", "cr2", "orf", "nef", "heif", "ico", "cr2", "orf", "nef", "heif", "avif", "jxl",
]) ])
} }
@ -80,14 +80,14 @@ impl FileExtensions {
file.extension_is_one_of( &[ file.extension_is_one_of( &[
"zip", "tar", "Z", "z", "gz", "bz2", "a", "ar", "7z", "zip", "tar", "Z", "z", "gz", "bz2", "a", "ar", "7z",
"iso", "dmg", "tc", "rar", "par", "tgz", "xz", "txz", "iso", "dmg", "tc", "rar", "par", "tgz", "xz", "txz",
"lz", "tlz", "lzma", "deb", "rpm", "zst", "lz", "tlz", "lzma", "deb", "rpm", "zst", "lz4",
]) ])
} }
fn is_temp(&self, file: &File<'_>) -> bool { fn is_temp(&self, file: &File<'_>) -> bool {
file.name.ends_with('~') file.name.ends_with('~')
|| (file.name.starts_with('#') && file.name.ends_with('#')) || (file.name.starts_with('#') && file.name.ends_with('#'))
|| file.extension_is_one_of( &[ "tmp", "swp", "swo", "swn", "bak", "bk" ]) || file.extension_is_one_of( &[ "tmp", "swp", "swo", "swn", "bak", "bkp", "bk" ])
} }
fn is_compiled(&self, file: &File<'_>) -> bool { fn is_compiled(&self, file: &File<'_>) -> bool {

View File

@ -18,6 +18,7 @@
#![allow(clippy::non_ascii_literal)] #![allow(clippy::non_ascii_literal)]
#![allow(clippy::option_if_let_else)] #![allow(clippy::option_if_let_else)]
#![allow(clippy::too_many_lines)] #![allow(clippy::too_many_lines)]
#![allow(clippy::unnested_or_patterns)] // TODO: remove this when we support Rust 1.53.0
#![allow(clippy::unused_self)] #![allow(clippy::unused_self)]
#![allow(clippy::upper_case_acronyms)] #![allow(clippy::upper_case_acronyms)]
#![allow(clippy::wildcard_imports)] #![allow(clippy::wildcard_imports)]

View File

@ -430,7 +430,7 @@ impl<'a> MatchedFlags<'a> {
.filter(|tuple| tuple.1.is_some() && predicate(&tuple.0)) .filter(|tuple| tuple.1.is_some() && predicate(&tuple.0))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if those.len() < 2 { Ok(those.first().cloned().map(|t| t.1.unwrap())) } if those.len() < 2 { Ok(those.first().copied().map(|t| t.1.unwrap())) }
else { Err(OptionsError::Duplicate(those[0].0, those[1].0)) } else { Err(OptionsError::Duplicate(those[0].0, those[1].0)) }
} }
else { else {

View File

@ -80,7 +80,7 @@ lazy_static! {
m.insert("include", '\u{e5fc}'); //  m.insert("include", '\u{e5fc}'); // 
m.insert("lib", '\u{f121}'); //  m.insert("lib", '\u{f121}'); // 
m.insert("localized", '\u{f179}'); //  m.insert("localized", '\u{f179}'); // 
m.insert("Makefile", '\u{e779}'); //  m.insert("Makefile", '\u{f489}'); // 
m.insert("node_modules", '\u{e718}'); //  m.insert("node_modules", '\u{e718}'); // 
m.insert("npmignore", '\u{e71e}'); //  m.insert("npmignore", '\u{e71e}'); // 
m.insert("rubydoc", '\u{e73b}'); //  m.insert("rubydoc", '\u{e73b}'); // 
@ -110,6 +110,7 @@ pub fn icon_for_file(file: &File<'_>) -> char {
"apk" => '\u{e70e}', //  "apk" => '\u{e70e}', // 
"apple" => '\u{f179}', //  "apple" => '\u{f179}', // 
"avi" => '\u{f03d}', //  "avi" => '\u{f03d}', // 
"avif" => '\u{f1c5}', // 
"avro" => '\u{e60b}', //  "avro" => '\u{e60b}', // 
"awk" => '\u{f489}', //  "awk" => '\u{f489}', // 
"bash" => '\u{f489}', //  "bash" => '\u{f489}', // 
@ -206,11 +207,16 @@ pub fn icon_for_file(file: &File<'_>) -> char {
"jad" => '\u{e256}', //  "jad" => '\u{e256}', // 
"jar" => '\u{e204}', //  "jar" => '\u{e204}', // 
"java" => '\u{e204}', //  "java" => '\u{e204}', // 
"jfi" => '\u{f1c5}', // 
"jfif" => '\u{f1c5}', // 
"jif" => '\u{f1c5}', // 
"jpe" => '\u{f1c5}', // 
"jpeg" => '\u{f1c5}', //  "jpeg" => '\u{f1c5}', // 
"jpg" => '\u{f1c5}', //  "jpg" => '\u{f1c5}', // 
"js" => '\u{e74e}', //  "js" => '\u{e74e}', // 
"json" => '\u{e60b}', //  "json" => '\u{e60b}', // 
"jsx" => '\u{e7ba}', //  "jsx" => '\u{e7ba}', // 
"jxl" => '\u{f1c5}', // 
"ksh" => '\u{f489}', //  "ksh" => '\u{f489}', // 
"latex" => '\u{f034}', //  "latex" => '\u{f034}', // 
"less" => '\u{e758}', //  "less" => '\u{e758}', // 
@ -221,6 +227,7 @@ pub fn icon_for_file(file: &File<'_>) -> char {
"log" => '\u{f18d}', //  "log" => '\u{f18d}', // 
"lua" => '\u{e620}', //  "lua" => '\u{e620}', // 
"lz" => '\u{f410}', //  "lz" => '\u{f410}', // 
"lz4" => '\u{f410}', // 
"lzh" => '\u{f410}', //  "lzh" => '\u{f410}', // 
"lzma" => '\u{f410}', //  "lzma" => '\u{f410}', // 
"lzo" => '\u{f410}', //  "lzo" => '\u{f410}', // 
@ -230,6 +237,7 @@ pub fn icon_for_file(file: &File<'_>) -> char {
"markdown" => '\u{f48a}', //  "markdown" => '\u{f48a}', // 
"md" => '\u{f48a}', //  "md" => '\u{f48a}', // 
"mjs" => '\u{e74e}', //  "mjs" => '\u{e74e}', // 
"mk" => '\u{f489}', // 
"mkd" => '\u{f48a}', //  "mkd" => '\u{f48a}', // 
"mkv" => '\u{f03d}', //  "mkv" => '\u{f03d}', // 
"mobi" => '\u{e28b}', //  "mobi" => '\u{e28b}', // 
@ -292,6 +300,7 @@ pub fn icon_for_file(file: &File<'_>) -> char {
"so" => '\u{f17c}', //  "so" => '\u{f17c}', // 
"sql" => '\u{f1c0}', //  "sql" => '\u{f1c0}', // 
"sqlite3" => '\u{e7c4}', //  "sqlite3" => '\u{e7c4}', // 
"sty" => '\u{f034}', // 
"styl" => '\u{e600}', //  "styl" => '\u{e600}', // 
"stylus" => '\u{e600}', //  "stylus" => '\u{e600}', // 
"svg" => '\u{f1c5}', //  "svg" => '\u{f1c5}', // 
@ -301,7 +310,9 @@ pub fn icon_for_file(file: &File<'_>) -> char {
"tbz" => '\u{f410}', //  "tbz" => '\u{f410}', // 
"tbz2" => '\u{f410}', //  "tbz2" => '\u{f410}', // 
"tex" => '\u{f034}', //  "tex" => '\u{f034}', // 
"tgz" => '\u{f410}', // 
"tiff" => '\u{f1c5}', //  "tiff" => '\u{f1c5}', // 
"tlz" => '\u{f410}', // 
"toml" => '\u{e615}', //  "toml" => '\u{e615}', // 
"ts" => '\u{e628}', //  "ts" => '\u{e628}', // 
"tsv" => '\u{f1c3}', //  "tsv" => '\u{f1c3}', // 
@ -309,6 +320,7 @@ pub fn icon_for_file(file: &File<'_>) -> char {
"ttf" => '\u{f031}', //  "ttf" => '\u{f031}', // 
"twig" => '\u{e61c}', //  "twig" => '\u{e61c}', // 
"txt" => '\u{f15c}', //  "txt" => '\u{f15c}', // 
"txz" => '\u{f410}', // 
"tz" => '\u{f410}', //  "tz" => '\u{f410}', // 
"tzo" => '\u{f410}', //  "tzo" => '\u{f410}', // 
"video" => '\u{f03d}', //  "video" => '\u{f03d}', // 

View File

@ -144,6 +144,18 @@ status = 0
tags = [ 'long', 'git' ] tags = [ 'long', 'git' ]
# The forth Git repo: non UTF-8 file
[[cmd]]
name = "exa --git -l handles non UTF8 file in Git repositories"
shell = "exa --git -l /testcases/git4"
stdout = { file = "outputs/git4_long.ansitxt" }
stderr = { empty = true }
status = 0
tags = [ 'long', 'git' ]
# Both repositories 1 and 2 at once # Both repositories 1 and 2 at once
[[cmd]] [[cmd]]

View File

@ -0,0 +1 @@
.rw-rw-r-- 0 cassowary  1 Jan 12:34 -N P\u{8}<30>UUU