Merge branch 'master' into makefile

This commit is contained in:
Benjamin Sago 2017-05-07 15:59:24 +01:00 committed by GitHub
commit 20b6588552
36 changed files with 980 additions and 478 deletions

111
Cargo.lock generated
View File

@ -8,7 +8,7 @@ dependencies = [
"git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"locale 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "locale 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"natord 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "natord 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -43,26 +43,13 @@ dependencies = [
"gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "curl-sys"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "datetime" name = "datetime"
version = "0.4.4" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"iso8601 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "iso8601 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"locale 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "locale 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"pad 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "pad 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -73,15 +60,6 @@ name = "gcc"
version = "0.3.45" version = "0.3.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gdi32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "getopts" name = "getopts"
version = "0.2.14" version = "0.2.14"
@ -93,10 +71,8 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"libgit2-sys 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "libgit2-sys 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -130,33 +106,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.21" version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "libgit2-sys" name = "libgit2-sys"
version = "0.6.8" version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"curl-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libssh2-sys"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -166,7 +127,7 @@ version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -175,7 +136,7 @@ name = "locale"
version = "0.2.1" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -265,7 +226,7 @@ name = "num_cpus"
version = "1.4.0" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -276,23 +237,6 @@ dependencies = [
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "openssl-probe"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "openssl-sys"
version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)",
"gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "pad" name = "pad"
version = "0.1.4" version = "0.1.4"
@ -311,7 +255,7 @@ name = "rand"
version = "0.3.15" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -359,33 +303,14 @@ dependencies = [
"matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "user32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "users" name = "users"
version = "0.5.2" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "zoneinfo_compiled" name = "zoneinfo_compiled"
version = "0.2.1" version = "0.2.1"
@ -400,19 +325,16 @@ dependencies = [
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" "checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304"
"checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" "checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac"
"checksum curl-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "23e7e544dc5e1ba42c4a4a678bd47985e84b9c3f4d3404c29700622a029db9c3"
"checksum datetime 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2d425bf1f6bbd57cf833081c1e60ac294fd74e7edd66acc91c3fca2e496bcee9" "checksum datetime 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2d425bf1f6bbd57cf833081c1e60ac294fd74e7edd66acc91c3fca2e496bcee9"
"checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" "checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae"
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
"checksum git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "046ae03385257040b2a35e56d9669d950dd911ba2bf48202fbef73ee6aab27b2" "checksum git2 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "046ae03385257040b2a35e56d9669d950dd911ba2bf48202fbef73ee6aab27b2"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum idna 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac85ec3f80c8e4e99d9325521337e14ec7555c458a14e377d189659a427f375" "checksum idna 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac85ec3f80c8e4e99d9325521337e14ec7555c458a14e377d189659a427f375"
"checksum iso8601 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "11dc464f8c6f17595d191447c9c6559298b2d023d6f846a4a23ac7ea3c46c477" "checksum iso8601 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "11dc464f8c6f17595d191447c9c6559298b2d023d6f846a4a23ac7ea3c46c477"
"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf"
"checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" "checksum libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "babb8281da88cba992fa1f4ddec7d63ed96280a1a53ec9b919fd37b53d71e502"
"checksum libgit2-sys 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "68bed1d1198da5d2b047af68fd71613ddfaa3d5b68797181b33e9d8547263b4b" "checksum libgit2-sys 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "a3aaa20337a0e79fb75180b6a1970c1f7cff9a413f570d6b999b38a5d5d54e81"
"checksum libssh2-sys 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "91e135645c2e198a39552c8c7686bb5b83b1b99f64831c040a6c2798a1195934"
"checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c" "checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c"
"checksum locale 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ecccf5186e43f84e543bbf61fcddf00b41d69d97093bc8989cc0cf1593681950" "checksum locale 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ecccf5186e43f84e543bbf61fcddf00b41d69d97093bc8989cc0cf1593681950"
"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" "checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1"
@ -427,8 +349,6 @@ dependencies = [
"checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99"
"checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167" "checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167"
"checksum number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59a14be9c211cb9c602bad35ac99f41e9a84b44d71b8cbd3040e3bd02a214902" "checksum number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59a14be9c211cb9c602bad35ac99f41e9a84b44d71b8cbd3040e3bd02a214902"
"checksum openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d98df0270d404ccd3c050a41d579c52d1db15375168bb3471e04ec0f5f378daf"
"checksum openssl-sys 0.9.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e5e0fd64cb2fa018ed2e7b2c8d9649114fe5da957c9a67432957f01e5dcc82e9"
"checksum pad 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d1bf3336e626b898e7263790d432a711d4277e22faea20dd9f70e0cab268fa58" "checksum pad 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d1bf3336e626b898e7263790d432a711d4277e22faea20dd9f70e0cab268fa58"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" "checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
@ -439,8 +359,5 @@ dependencies = [
"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff" "checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff"
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" "checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e"
"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
"checksum users 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7ae8fdf783cb9652109c99886459648feb92ecc749e6b8e7930f6decba74c7c" "checksum users 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7ae8fdf783cb9652109c99886459648feb92ecc749e6b8e7930f6decba74c7c"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum zoneinfo_compiled 0.2.1 (git+https://github.com/rust-datetime/zoneinfo-compiled.git)" = "<none>" "checksum zoneinfo_compiled 0.2.1 (git+https://github.com/rust-datetime/zoneinfo-compiled.git)" = "<none>"

View File

@ -39,6 +39,7 @@ lto = true
[dependencies.git2] [dependencies.git2]
version = "0.6.4" version = "0.6.4"
optional = true optional = true
default-features = false
[dependencies.zoneinfo_compiled] [dependencies.zoneinfo_compiled]
git = "https://github.com/rust-datetime/zoneinfo-compiled.git" git = "https://github.com/rust-datetime/zoneinfo-compiled.git"

View File

@ -1,25 +1,63 @@
PREFIX ?= /usr/local SRC = \
src/info/sources.rs \
src/info/mod.rs \
src/info/filetype.rs \
src/bin/main.rs \
src/term.rs \
src/exa.rs \
src/output/grid_details.rs \
src/output/tree.rs \
src/output/colours.rs \
src/output/grid.rs \
src/output/cell.rs \
src/output/mod.rs \
src/output/details.rs \
src/output/lines.rs \
src/output/column.rs \
src/fs/file.rs \
src/fs/fields.rs \
src/fs/mod.rs \
src/fs/dir.rs \
src/fs/feature/xattr.rs \
src/fs/feature/git.rs \
src/fs/feature/mod.rs \
src/options/misfire.rs \
src/options/filter.rs \
src/options/dir_action.rs \
src/options/view.rs \
src/options/mod.rs \
src/options/help.rs
BUILD = target/release/exa PREFIX = /usr/local
$(BUILD): CARGOFLAGS = --no-default-features
@which rustc > /dev/null || { echo "exa requires Rust to compile. For installation instructions, please visit http://rust-lang.org/"; exit 1; }
cargo build --release
build: $(BUILD) all: target/release/exa
build-no-git: build: CARGOFLAGS=
@which rustc > /dev/null || { echo "exa requires Rust to compile. For installation instructions, please visit http://rust-lang.org/"; exit 1; } build: all
cargo build --release --no-default-features build-no-git: all
INSTALL = $(PREFIX)/bin/exa target/release/exa: $(SRC)
if test -n "$$(echo "$$CC" | cut -d \ -f 1)"; then \
env CC="$$(echo "$$CC" | cut -d \ -f 1)" cargo build --release $(CARGOFLAGS); \
else\
env -u CC cargo build --release $(CARGOFLAGS); \
fi
$(INSTALL): install: target/release/exa
# BSD and OSX don't have -D to create leading directories # BSD and OSX don't have -D to create leading directories
install -dm755 $(PREFIX)/bin/ $(PREFIX)/share/man/man1/ install -dm755 -- "$(DESTDIR)$(PREFIX)/bin/" "$(DESTDIR)$(PREFIX)/share/man/man1/"
install -sm755 target/release/exa $(PREFIX)/bin/ install -m755 -- target/release/exa "$(DESTDIR)$(PREFIX)/bin/"
install -m644 contrib/man/*.1 $(PREFIX)/share/man/man1/ install -m644 -- contrib/man/exa.1 "$(DESTDIR)$(PREFIX)/share/man/man1/"
install: build $(INSTALL) uninstall:
-rm -- "$(DESTDIR)$(PREFIX)/share/man/man1/exa.1"
-rmdir -- "$(DESTDIR)$(PREFIX)/share/man/man1"
-rm -- "$(DESTDIR)$(PREFIX)/bin/exa"
-rmdir -- "$(DESTDIR)$(PREFIX)/bin"
.PHONY: $(BUILD) build-no-git $(INSTALL) clean:
-rm -rf target
.PHONY: all build install

View File

@ -14,21 +14,21 @@ exas options are similar, but not exactly the same, as `ls`.
### Display Options ### Display Options
- **-1**, **--oneline**: display one entry per line - **-1**, **--oneline**: display one entry per line
- **-G**, **--grid**: display entries in a grid view (default) - **-G**, **--grid**: display entries as a grid (default)
- **-l**, **--long**: display extended details and attributes - **-l**, **--long**: display extended details and attributes
- **-R**, **--recurse**: recurse into directories - **-R**, **--recurse**: recurse into directories
- **-T**, **--tree**: recurse into subdirectories in a tree view - **-T**, **--tree**: recurse into directories as a tree
- **-x**, **--across**: sort multi-column view entries across - **-x**, **--across**: sort the grid across, rather than downwards
- **--color**, **--colour**: when to colourise the output - **--colo[u]r**: when to use terminal colours
- **--color-scale**, **--colour-scale**: colour file sizes according to their magnitude - **--colo[u]r-scale**: highlight levels of file sizes distinctly
### Filtering Options ### Filtering Options
- **-a**, **--all**: show dot files - **-a**, **--all**: don't hide hidden and 'dot' files
- **-d**, **--list-dirs**: list directories as regular files - **-d**, **--list-dirs**: list directories like regular files
- **-L**, **--level=(depth)**: maximum depth of recursion - **-L**, **--level=(depth)**: limit the depth of recursion
- **-r**, **--reverse**: reverse sort order - **-r**, **--reverse**: reverse the sort order
- **-s**, **--sort=(field)**: field to sort by - **-s**, **--sort=(field)**: which field to sort by
- **--group-directories-first**: list directories before other files - **--group-directories-first**: list directories before other files
- **-I**, **--ignore-glob=(globs)**: glob patterns (pipe-separated) of files to ignore - **-I**, **--ignore-glob=(globs)**: glob patterns (pipe-separated) of files to ignore
@ -36,23 +36,23 @@ exas options are similar, but not exactly the same, as `ls`.
These options are available when running with --long (`-l`): These options are available when running with --long (`-l`):
- **-b**, **--binary**: use binary (power of two) file sizes - **-b**, **--binary**: list file sizes with binary prefixes
- **-B**, **--bytes**: list file sizes in bytes, without prefixes - **-B**, **--bytes**: list file sizes in bytes, without any prefixes
- **-g**, **--group**: show group as well as user - **-g**, **--group**: list each file's group
- **-h**, **--header**: show a header row - **-h**, **--header**: add a header row to each column
- **-H**, **--links**: show number of hard links column - **-H**, **--links**: list each file's number of hard links
- **-i**, **--inode**: show inode number column - **-i**, **--inode**: list each file's inode number
- **-m**, **--modified**: display timestamp of most recent modification - **-m**, **--modified**: use the modified timestamp field
- **-S**, **--blocks**: show number of file system blocks - **-S**, **--blocks**: list each file's number of file system blocks
- **-t**, **--time=(field)**: which timestamp to show for a file - **-t**, **--time=(field)**: which timestamp field to use
- **-u**, **--accessed**: display timestamp of last access for a file - **-u**, **--accessed**: use the accessed timestamp field
- **-U**, **--created**: display timestamp of creation of a file - **-U**, **--created**: use the created timestamp field
- **-@**, **--extended**: display extended attribute keys and sizes - **-@**, **--extended**: list each file's extended attributes and sizes
- **--git**: show Git status for a file - **--git**: list each file's Git status, if tracked
Accepted **--color** options are **always**, **automatic**, and **never**. - Valid **--color** options are **always**, **automatic**, and **never**.
Valid sort fields are **name**, **size**, **extension**, **modified**, **accessed**, **created**, **inode**, and **none**. - Valid sort fields are **accessed**, **created**, **extension**, **Extension**, **inode**, **modified**, **name**, **Name**, **size**, and **none**. Fields starting with a capital letter are case-sensitive.
Valid time fields are **modified**, **accessed**, and **created**. - Valid time fields are **modified**, **accessed**, and **created**.
## Installation ## Installation

87
Vagrantfile vendored
View File

@ -7,6 +7,8 @@ Vagrant.configure(2) do |config|
v.cpus = 1 v.cpus = 1
end end
developer = 'ubuntu'
# We use Ubuntu instead of Debian because the image comes with two-way # We use Ubuntu instead of Debian because the image comes with two-way
# shared folder support by default. # shared folder support by default.
@ -16,8 +18,11 @@ Vagrant.configure(2) do |config|
# Install the dependencies needed for exa to build, as quietly as # Install the dependencies needed for exa to build, as quietly as
# apt can do. # apt can do.
config.vm.provision :shell, privileged: true, inline: config.vm.provision :shell, privileged: true, inline: <<-EOF
%[apt-get install -qq -o=Dpkg::Use-Pty=0 -y git cmake libssl-dev libgit2-dev libssh2-1-dev curl attr pkg-config] apt-get install -qq -o=Dpkg::Use-Pty=0 -y \
git cmake curl attr pkg-config libgit2-dev \
fish zsh bash bash-completion
EOF
# Guarantee that the timezone is UTC -- some of the tests # Guarantee that the timezone is UTC -- some of the tests
@ -38,13 +43,40 @@ Vagrant.configure(2) do |config|
# By default it just uses the one in /vagrant/target, which can # By default it just uses the one in /vagrant/target, which can
# cause problems if it has different permissions than the other # cause problems if it has different permissions than the other
# directories, or contains object files compiled for the host. # directories, or contains object files compiled for the host.
config.vm.provision :shell, privileged: false, inline: config.vm.provision :shell, privileged: false, inline: <<-EOF
%[echo "export CARGO_TARGET_DIR=/home/ubuntu/target" >> ~/.bashrc] function put_line() {
grep -q -F "$2" $1 || echo "$2" >> $1
}
put_line ~/.bashrc 'export CARGO_TARGET_DIR=/home/#{developer}/target'
EOF
# Create "dexa" and "rexa" scripts that run the debug and release
# compiled versions of exa.
config.vm.provision :shell, privileged: true, inline: <<-EOF
echo -e "#!/bin/sh\n/home/#{developer}/target/debug/exa \\$*" > /usr/bin/exa
echo -e "#!/bin/sh\n/home/#{developer}/target/release/exa \\$*" > /usr/bin/rexa
chmod +x /usr/bin/{exa,rexa}
EOF
# Link the completion files so theyre “installed”.
config.vm.provision :shell, privileged: true, inline: <<-EOF
test -h /etc/bash_completion.d/exa \
|| ln -s /vagrant/contrib/completions.bash /etc/bash_completion.d/exa
test -h /usr/share/zsh/vendor-completions/_exa \
|| ln -s /vagrant/contrib/completions.zsh /usr/share/zsh/vendor-completions/_exa
test -h /usr/share/fish/completions/exa.fish \
|| ln -s /vagrant/contrib/completions.fish /usr/share/fish/completions/exa.fish
EOF
# We create two users that own the test files. # We create two users that own the test files.
# The first one just owns the ordinary ones, because we dont want to # The first one just owns the ordinary ones, because we dont want the
# depend on “vagrant” or “ubuntu” existing. # test outputs to depend on “vagrant” or “ubuntu” existing.
user = "cassowary" user = "cassowary"
config.vm.provision :shell, privileged: true, inline: config.vm.provision :shell, privileged: true, inline:
%[id -u #{user} &>/dev/null || useradd #{user}] %[id -u #{user} &>/dev/null || useradd #{user}]
@ -142,6 +174,49 @@ Vagrant.configure(2) do |config|
EOF EOF
# File name testcases.
# bash really doesnt want you to create a file with escaped characters
# in its name, so we have to resort to the echo builtin and touch!
#
# The double backslashes are not strictly necessary; without them, Ruby
# will interpolate them instead of bash, but because Vagrant prints out
# each command it runs, your *own* terminal will go “ding” from the alarm!
config.vm.provision :shell, privileged: false, inline: <<-EOF
set -xe
mkdir "#{test_dir}/file-names"
echo -ne "#{test_dir}/file-names/ascii: hello" | xargs -0 touch
echo -ne "#{test_dir}/file-names/emoji: [🆒]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/utf-8: pâté" | xargs -0 touch
echo -ne "#{test_dir}/file-names/bell: [\\a]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/backspace: [\\b]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/form-feed: [\\f]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/new-line: [\\n]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/return: [\\r]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/tab: [\\t]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/vertical-tab: [\\v]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/escape: [\\033]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/ansi: [\\033[34mblue\\033[0m]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/invalid-utf8-1: [\\xFF]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/invalid-utf8-2: [\\xc3\\x28]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/invalid-utf8-3: [\\xe2\\x82\\x28]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/invalid-utf8-4: [\\xf0\\x28\\x8c\\x28]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]" | xargs -0 mkdir
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]/subfile" | xargs -0 touch
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]/another: [\\n]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]/broken" | xargs -0 touch
mkdir "#{test_dir}/file-names/links"
ln -s "#{test_dir}/file-names/new-line-dir"*/* "#{test_dir}/file-names/links"
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]/broken" | xargs -0 rm
EOF
# Special file testcases. # Special file testcases.
config.vm.provision :shell, privileged: false, inline: <<-EOF config.vm.provision :shell, privileged: false, inline: <<-EOF
set -xe set -xe

37
contrib/completions.bash Normal file
View File

@ -0,0 +1,37 @@
_exa()
{
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
case "$prev" in
-'?'|--help|-v|--version)
return
;;
-L|--level)
COMPREPLY=( $( compgen -W '{0..9}' -- "$cur" ) )
return
;;
-s|--sort)
COMPREPLY=( $( compgen -W 'name filename Name Filename size filesize extension Extension modified accessed created none inode --' -- "$cur" ) )
return
;;
-t|--time)
COMPREPLY=( $( compgen -W 'accessed modified created --' -- $cur ) )
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W '$( _parse_help "$1" )' -- "$cur" ) )
;;
*)
_filedir
;;
esac
} &&
complete -o filenames -o bashdefault -F _exa exa

62
contrib/completions.fish Normal file
View File

@ -0,0 +1,62 @@
# Meta-stuff
complete -c exa -s 'v' -l 'version' -d "Show version of exa"
complete -c exa -s '?' -l 'help' -d "Show list of command-line options"
# Display options
complete -c exa -s '1' -l 'oneline' -d "Display one entry per line"
complete -c exa -s 'l' -l 'long' -d "Display extended file metadata as a table"
complete -c exa -s 'G' -l 'grid' -d "Display entries in a grid"
complete -c exa -s 'x' -l 'across' -d "Sort the grid across, rather than downwards"
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 '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 'colour' -d "When to use terminal colours"
complete -c exa -l 'color-scale' -d "Highlight levels of file sizes distinctly"
complete -c exa -l 'colour-scale' -d "Highlight levels of file sizes distinctly"
# Filtering and sorting options
complete -c exa -l 'group-directories-first' -d "Sort directories before other files"
complete -c exa -s 'a' -l 'all' -d "Don't hide hidden and 'dot' 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 'r' -l 'reverse' -d "Reverse the sort order"
complete -c exa -s 's' -l 'sort' -x -d "Which field to sort by" -a "
accessed\t'Sort by file accessed time'
created\t'Sort by file modified time'
ext\t'Sort by file extension'
Ext\t'Sort by file extension (case-insensitive)'
extension\t'Sort by file extension'
Extension\t'Sort by file extension (case-insensitive)'
filename\t'Sort by filename'
Filename\t'Sort by filename (case-insensitive)'
inode\t'Sort by file inode'
modified\t'Sort by file modified time'
name\t'Sort by filename'
Name\t'Sort by filename (case-insensitive)'
none\t'Do not sort files at all'
size\t'Sort by file size'
"
complete -c exa -s 'I' -l 'ignore-glob' -d "Ignore files that match these glob patterns" -r
# Long view options
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 '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 '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 'm' -l 'modified' -d "Use the modified timestamp field"
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 "
accessed\t'Display accessed time'
created\t'Display created time'
modified\t'Display modified time'
"
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"
# Optional extras
complete -c exa -s 'g' -l 'git' -d "List each file's Git status, if tracked"
complete -c exa -s '@' -l 'extended' -d "List each file's extended attributes and sizes"

39
contrib/completions.zsh Normal file
View File

@ -0,0 +1,39 @@
#compdef exa
__exa() {
_arguments \
"(- 1 *)"{-v,--version}"[Show version of exa]" \
"(- 1 *)"{-\?,--help}"[Show list of command-line options]" \
{-1,--oneline}"[Display one entry per line]" \
{-l,--long}"[Display extended file metadata as a table]" \
{-G,--grid}"[Display entries as a grid]" \
{-x,--across}"[Sort the grid across, rather than downwards]" \
{-R,--recurse}"[Recurse into directories]" \
{-T,--tree}"[Recurse into directories as a tree]" \
{-F,--classify}"[Display type indicator by file names]" \
{--color,--colour}"[When to use terminal colours]" \
{--color,--colour}-scale"[Highlight levels of file sizes distinctly]" \
--group-directories-first"[Sort directories before other files]" \
{-a,--all}"[Don't hide hidden and 'dot' files]" \
{-d,--list-dirs}"[List directories like regular files]" \
{-L,--level}"+[Limit the depth of recursion]" \
{-r,--reverse}"[Reverse the sort order]" \
{-s,--sort}"[Which field to sort by]:(sort field):(accessed created extension Extension filename Filename inode modified name Name none size)" \
{-I,--ignore-glob}"[Ignore files that match these glob patterns]" \
{-b,--binary}"[List file sizes with binary prefixes]" \
{-B,--bytes}"[List file sizes in bytes, without any prefixes]" \
{-g,--group}"[List each file's group]" \
{-h,--header}"[Add a header row to each column]" \
{-H,--links}"[List each file's number of hard links]" \
{-i,--inode}"[List each file's inode number]" \
{-m,--modified}"[Use the modified timestamp field]" \
{-S,--blocks}"[List each file's number of filesystem blocks]" \
{-t,--time}"[Which time field to show]:(time field):(accessed created modified)" \
{-u,--accessed}"[Use the accessed timestamp field]" \
{-U,--created}"[Use the created timestamp field]" \
--git"[List each file's Git status, if tracked]" \
{-@,--extended}"[List each file's extended attributes and sizes]" \
'*:filename:_files'
}
__exa

View File

@ -1,5 +1,5 @@
.hy .hy
.TH "exa" "1" "2015\-10\-18" "exa 0.4.0" "" .TH "exa" "1" "2017\-05\-06" "exa 0.5.0" ""
.SH NAME .SH NAME
.PP .PP
exa \- a modern replacement for ls exa \- a modern replacement for ls
@ -23,12 +23,17 @@ display one entry per line
.RE .RE
.TP .TP
.B \-G, \-\-grid .B \-G, \-\-grid
display entries in a grid view (default) display entries as a grid (default)
.RS .RS
.RE .RE
.TP .TP
.B \-l, \-\-long .B \-l, \-\-long
display extended details and attributes display extended file metadata as a table
.RS
.RE
.TP
.B \-x, \-\-across
sort the grid across, rather than downwards
.RS .RS
.RE .RE
.TP .TP
@ -38,39 +43,45 @@ recurse into directories
.RE .RE
.TP .TP
.B \-T, \-\-tree .B \-T, \-\-tree
recurse into subdirectories in a tree view recurse into directories as a tree
.RS
.RE
.TP
.B \-x, \-\-across
sort multi\-column view entries across
.RS .RS
.RE .RE
.TP .TP
.B \-\-color, \-\-colour=\f[I]WHEN\f[] .B \-\-color, \-\-colour=\f[I]WHEN\f[]
when to colourise the output (always, automatic, never) when to use terminal colours (always, automatic, never)
.RS
.RE
.TP
.B \-\-color-scale, \-\-colour-scale
highlight levels of file sizes distinctly
.RS .RS
.RE .RE
.SH FILTERING AND SORTING OPTIONS .SH FILTERING AND SORTING OPTIONS
.TP .TP
.B \-a, \-\-all .B \-a, \-\-all
show dot\-files don\[aq]t hide hidden and \[aq]dot\[aq] files
.RS .RS
.RE .RE
.TP .TP
.B \-d, \-\-list\-dirs .B \-d, \-\-list\-dirs
list directories as regular files list directories like regular files
.RS .RS
.RE .RE
.TP .TP
.B \-r, \-\-reverse .B \-r, \-\-reverse
reverse order of files reverse the sort order
.RS .RS
.RE .RE
.TP .TP
.B \-s, \-\-sort=\f[I]WORD\f[] .B \-s, \-\-sort=\f[I]SORT_FIELD\f[]
field to sort by (name, size, extension, modified, accessed, created, which field to sort by.
inode, none) Valid fields are name, Name, extension, Extension, size, modified, accessed, created, inode, and none.
Fields starting with a capital letter are case-sensitive.
.RS
.RE
.TP
.B \-I, \-\-ignore\-glob=\f[I]GLOBS\f[]
Glob patterns, pipe-separated, of files to ignore
.RS .RS
.RE .RE
.TP .TP
@ -84,72 +95,72 @@ These options are available when running with \f[C]\-\-long\f[]
(\f[C]\-l\f[]): (\f[C]\-l\f[]):
.TP .TP
.B \-b, \-\-binary .B \-b, \-\-binary
use binary prefixes in file sizes list file sizes with binary prefixes
.RS .RS
.RE .RE
.TP .TP
.B \-B, \-\-bytes .B \-B, \-\-bytes
list file sizes in bytes, without prefixes list file sizes in bytes, without any prefixes
.RS .RS
.RE .RE
.TP .TP
.B \-g, \-\-group .B \-g, \-\-group
show group as well as user list each file\[aq]s group
.RS .RS
.RE .RE
.TP .TP
.B \-h, \-\-header .B \-h, \-\-header
show a header row at the top add a header row to each column
.RS .RS
.RE .RE
.TP .TP
.B \-H, \-\-links .B \-H, \-\-links
show number of hard links list each file\[aq]s number of hard links
.RS .RS
.RE .RE
.TP .TP
.B \-i, \-\-inode .B \-i, \-\-inode
show each file\[aq]s inode number list each file\[aq]s inode number
.RS .RS
.RE .RE
.TP .TP
.B \-L, \-\-level=\f[I]DEPTH\f[] .B \-L, \-\-level=\f[I]DEPTH\f[]
maximum depth of recursion limit the depth of recursion
.RS .RS
.RE .RE
.TP .TP
.B \-m, \-\-modified .B \-m, \-\-modified
display timestamp of most recent modification use the modified timestamp field
.RS .RS
.RE .RE
.TP .TP
.B \-S, \-\-blocks .B \-S, \-\-blocks
show number of file system blocks list each file\[aq]s number of file system blocks
.RS .RS
.RE .RE
.TP .TP
.B \-t, \-\-time=\f[I]WORD\f[] .B \-t, \-\-time=\f[I]WORD\f[]
which timestamp to show for a file (modified, accessed, created) which timestamp field to list (modified, accessed, created)
.RS .RS
.RE .RE
.TP .TP
.B \-u, \-\-accessed .B \-u, \-\-accessed
display timestamp of last access for a file use the accessed timestamp field
.RS .RS
.RE .RE
.TP .TP
.B \-U, \-\-created .B \-U, \-\-created
display timestamp of creation for a file use the created timestamp field
.RS .RS
.RE .RE
.TP .TP
.B \-\@, \-\-extended .B \-\@, \-\-extended
display extended attribute keys and sizes list each file\[aq]s extended attributes and sizes
.RS .RS
.RE .RE
.TP .TP
.B \-\-git .B \-\-git
display Git status for a file, if available list each file\[aq]s Git status, if tracked
.RS .RS
.RE .RE
.SH EXAMPLES .SH EXAMPLES

View File

@ -23,9 +23,12 @@ use std::ffi::OsStr;
use std::io::{stderr, Write, Result as IOResult}; use std::io::{stderr, Write, Result as IOResult};
use std::path::{Component, Path}; use std::path::{Component, Path};
use ansi_term::{ANSIStrings, Style};
use fs::{Dir, File}; use fs::{Dir, File};
use options::{Options, View}; use options::{Options, View};
pub use options::Misfire; pub use options::Misfire;
use output::escape;
mod fs; mod fs;
mod info; mod info;
@ -116,7 +119,9 @@ impl<'w, W: Write + 'w> Exa<'w, W> {
} }
if !is_only_dir { if !is_only_dir {
writeln!(self.writer, "{}:", dir.path.display())?; let mut bits = Vec::new();
escape(dir.path.display().to_string(), &mut bits, Style::default(), Style::default());
writeln!(self.writer, "{}:", ANSIStrings(&bits))?;
} }
let mut children = Vec::new(); let mut children = Vec::new();

View File

@ -1,45 +1,32 @@
//! Files, and methods and fields to access their metadata. //! Files, and methods and fields to access their metadata.
use std::ascii::AsciiExt;
use std::env::current_dir;
use std::fs; use std::fs;
use std::io::Error as IOError; use std::io::Error as IOError;
use std::io::Result as IOResult; use std::io::Result as IOResult;
use std::os::unix::fs::{MetadataExt, PermissionsExt}; use std::os::unix::fs::{MetadataExt, PermissionsExt, FileTypeExt};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use fs::dir::Dir; use fs::dir::Dir;
use fs::fields as f; use fs::fields as f;
#[cfg(any(target_os = "macos", target_os = "linux"))]
use std::os::unix::fs::FileTypeExt;
/// Constant table copied from https://doc.rust-lang.org/src/std/sys/unix/ext/fs.rs.html#11-259 #[allow(trivial_numeric_casts)]
/// which is currently unstable and lacks vision for stabilization,
/// see https://github.com/rust-lang/rust/issues/27712
#[allow(dead_code, non_camel_case_types)]
mod modes { mod modes {
pub type mode_t = u32; use libc;
pub const USER_READ: mode_t = 0o400; pub type Mode = u32;
pub const USER_WRITE: mode_t = 0o200; // The `libc::mode_t` types actual type varies, but the value returned
pub const USER_EXECUTE: mode_t = 0o100; // from `metadata.permissions().mode()` is always `u32`.
pub const USER_RWX: mode_t = 0o700;
pub const GROUP_READ: mode_t = 0o040; pub const USER_READ: Mode = libc::S_IRUSR as Mode;
pub const GROUP_WRITE: mode_t = 0o020; pub const USER_WRITE: Mode = libc::S_IWUSR as Mode;
pub const GROUP_EXECUTE: mode_t = 0o010; pub const USER_EXECUTE: Mode = libc::S_IXUSR as Mode;
pub const GROUP_RWX: mode_t = 0o070; pub const GROUP_READ: Mode = libc::S_IRGRP as Mode;
pub const OTHER_READ: mode_t = 0o004; pub const GROUP_WRITE: Mode = libc::S_IWGRP as Mode;
pub const OTHER_WRITE: mode_t = 0o002; pub const GROUP_EXECUTE: Mode = libc::S_IXGRP as Mode;
pub const OTHER_EXECUTE: mode_t = 0o001; pub const OTHER_READ: Mode = libc::S_IROTH as Mode;
pub const OTHER_RWX: mode_t = 0o007; pub const OTHER_WRITE: Mode = libc::S_IWOTH as Mode;
pub const ALL_READ: mode_t = 0o444; pub const OTHER_EXECUTE: Mode = libc::S_IXOTH as Mode;
pub const ALL_WRITE: mode_t = 0o222;
pub const ALL_EXECUTE: mode_t = 0o111;
pub const ALL_RWX: mode_t = 0o777;
pub const SETUID: mode_t = 0o4000;
pub const SETGID: mode_t = 0o2000;
pub const STICKY_BIT: mode_t = 0o1000;
} }
@ -150,6 +137,27 @@ impl<'dir> File<'dir> {
self.metadata.file_type().is_symlink() self.metadata.file_type().is_symlink()
} }
/// Whether this file is a named pipe on the filesystem.
pub fn is_pipe(&self) -> bool {
self.metadata.file_type().is_fifo()
}
/// Whether this file is a char device on the filesystem.
pub fn is_char_device(&self) -> bool {
self.metadata.file_type().is_char_device()
}
/// Whether this file is a block device on the filesystem.
pub fn is_block_device(&self) -> bool {
self.metadata.file_type().is_block_device()
}
/// Whether this file is a socket on the filesystem.
pub fn is_socket(&self) -> bool {
self.metadata.file_type().is_socket()
}
/// Whether this file is a dotfile, based on its name. In Unix, file names /// Whether this file is a dotfile, based on its name. In Unix, file names
/// beginning with a dot represent system or configuration files, and /// beginning with a dot represent system or configuration files, and
/// should be hidden by default. /// should be hidden by default.
@ -344,6 +352,8 @@ impl<'dir> File<'dir> {
/// directory, so will not work if this file has just been passed in on /// directory, so will not work if this file has just been passed in on
/// the command line. /// the command line.
pub fn git_status(&self) -> f::Git { pub fn git_status(&self) -> f::Git {
use std::env::current_dir;
match self.dir { match self.dir {
None => f::Git { staged: f::GitStatus::NotModified, unstaged: f::GitStatus::NotModified }, None => f::Git { staged: f::GitStatus::NotModified, unstaged: f::GitStatus::NotModified },
Some(d) => { Some(d) => {
@ -358,52 +368,6 @@ impl<'dir> File<'dir> {
} }
} }
#[cfg(any(target_os = "macos", target_os = "linux"))]
impl<'dir> File<'dir> {
/// Whether this file is a named pipe on the filesystem.
pub fn is_pipe(&self) -> bool {
self.metadata.file_type().is_fifo()
}
/// Whether this file is a char device on the filesystem.
pub fn is_char_device(&self) -> bool {
self.metadata.file_type().is_char_device()
}
/// Whether this file is a block device on the filesystem.
pub fn is_block_device(&self) -> bool {
self.metadata.file_type().is_block_device()
}
/// Whether this file is a socket on the filesystem.
pub fn is_socket(&self) -> bool {
self.metadata.file_type().is_socket()
}
}
#[cfg(not(any(target_os = "macos", target_os = "linux")))]
impl<'dir> File<'dir> {
/// Whether this file is a named pipe on the filesystem.
pub fn is_pipe(&self) -> bool {
false
}
/// Whether this file is a char device on the filesystem.
pub fn is_char_device(&self) -> bool {
false
}
/// Whether this file is a block device on the filesystem.
pub fn is_block_device(&self) -> bool {
false
}
/// Whether this file is a socket on the filesystem.
pub fn is_socket(&self) -> bool {
false
}
}
impl<'a> AsRef<File<'a>> for File<'a> { impl<'a> AsRef<File<'a>> for File<'a> {
fn as_ref(&self) -> &File<'a> { fn as_ref(&self) -> &File<'a> {
@ -421,6 +385,8 @@ impl<'a> AsRef<File<'a>> for File<'a> {
/// against a pre-compiled list of extensions which are known to only exist /// against a pre-compiled list of extensions which are known to only exist
/// within ASCII, so it's alright. /// within ASCII, so it's alright.
fn ext(path: &Path) -> Option<String> { fn ext(path: &Path) -> Option<String> {
use std::ascii::AsciiExt;
let name = match path.file_name() { let name = match path.file_name() {
Some(f) => f.to_string_lossy().to_string(), Some(f) => f.to_string_lossy().to_string(),
None => return None, None => return None,
@ -441,11 +407,24 @@ pub enum FileTarget<'dir> {
Broken(PathBuf), Broken(PathBuf),
/// There was an IO error when following the link. This can happen if the /// There was an IO error when following the link. This can happen if the
/// file isn't a link to begin with, but also if, say, we don't have /// file isnt a link to begin with, but also if, say, we dont have
/// permission to follow it. /// permission to follow it.
Err(IOError), Err(IOError),
} }
impl<'dir> FileTarget<'dir> {
/// Whether this link doesnt lead to a file, for whatever reason. This
/// gets used to determine how to highlight the link in grid views.
pub fn is_broken(&self) -> bool {
match self {
&FileTarget::Ok(_) => false,
&FileTarget::Broken(_) => true,
&FileTarget::Err(_) => true,
}
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {

View File

@ -1,44 +1,46 @@
pub static OPTIONS: &'static str = r##" pub static OPTIONS: &'static str = r##"
-?, --help show list of command-line options
-v, --version show version of exa
DISPLAY OPTIONS DISPLAY OPTIONS
-1, --oneline display one entry per line -1, --oneline display one entry per line
-G, --grid display entries in a grid view (default) -l, --long display extended file metadata as a table
-l, --long display extended details and attributes -G, --grid display entries as a grid (default)
-x, --across sort the grid across, rather than downwards
-R, --recurse recurse into directories -R, --recurse recurse into directories
-T, --tree recurse into subdirectories in a tree view -T, --tree recurse into directories as a tree
-x, --across sort multi-column view entries across -F, --classify display type indicator by file names
-F, --classify show file type indicator (one of */=@|) --colo[u]r=WHEN when to use terminal colours (always, auto, never)
--colo[u]r-scale highlight levels of file sizes distinctly
--color=WHEN, --colour=WHEN when to colourise the output (always, auto, never)
--color-scale, --colour-scale colour file sizes according to their magnitude
FILTERING AND SORTING OPTIONS FILTERING AND SORTING OPTIONS
-a, --all show dot-files -a, --all don't hide hidden and 'dot' files
-d, --list-dirs list directories as regular files -d, --list-dirs list directories like regular files
-r, --reverse reverse order of files -r, --reverse reverse the sort order
-s, --sort SORT_FIELD field to sort by. Choices: name, -s, --sort SORT_FIELD which field to sort by:
size, extension, modified,
accessed, created, inode, none
--group-directories-first list directories before other files --group-directories-first list directories before other files
-I, --ignore-glob GLOBS glob patterns (pipe-separated) of files to ignore -I, --ignore-glob GLOBS glob patterns (pipe-separated) of files to ignore
Valid sort fields: name, Name, extension, Extension, size,
modified, accessed, created, inode, none
"##; "##;
pub static LONG_OPTIONS: &'static str = r##" pub static LONG_OPTIONS: &'static str = r##"
LONG VIEW OPTIONS LONG VIEW OPTIONS
-b, --binary use binary prefixes in file sizes -b, --binary list file sizes with binary prefixes
-B, --bytes list file sizes in bytes, without prefixes -B, --bytes list file sizes in bytes, without any prefixes
-g, --group show group as well as user -g, --group list each file's group
-h, --header show a header row at the top -h, --header add a header row to each column
-H, --links show number of hard links -H, --links list each file's number of hard links
-i, --inode show each file's inode number -i, --inode list each file's inode number
-L, --level DEPTH maximum depth of recursion -L, --level DEPTH limit the depth of recursion
-m, --modified display timestamp of most recent modification -m, --modified use the modified timestamp field
-S, --blocks show number of file system blocks -S, --blocks show number of file system blocks
-t, --time FIELD which timestamp to show for a file. Choices: -t, --time FIELD which timestamp field to list (modified, accessed, created)
modified, accessed, created -u, --accessed use the accessed timestamp field
-u, --accessed display timestamp of last access for a file -U, --created use the created timestamp field
-U, --created display timestamp of creation for a file
"##; "##;
pub static GIT_HELP: &'static str = r##" --git show git status for files"##; pub static GIT_HELP: &'static str = r##" --git list each file's Git status, if tracked"##;
pub static EXTENDED_HELP: &'static str = r##" -@, --extended display extended attribute keys and sizes"##; pub static EXTENDED_HELP: &'static str = r##" -@, --extended list each file's extended attributes and sizes"##;

View File

@ -45,50 +45,50 @@ impl Options {
where S: AsRef<OsStr> { where S: AsRef<OsStr> {
let mut opts = getopts::Options::new(); let mut opts = getopts::Options::new();
opts.optflag("v", "version", "display version of exa"); opts.optflag("v", "version", "show version of exa");
opts.optflag("?", "help", "show list of command-line options"); opts.optflag("?", "help", "show list of command-line options");
// Display options // Display options
opts.optflag("1", "oneline", "display one entry per line"); opts.optflag("1", "oneline", "display one entry per line");
opts.optflag("G", "grid", "display entries in a grid view (default)"); opts.optflag("l", "long", "display extended file metadata in a table");
opts.optflag("l", "long", "display extended details and attributes"); opts.optflag("G", "grid", "display entries as a grid (default)");
opts.optflag("x", "across", "sort the grid across, rather than downwards");
opts.optflag("R", "recurse", "recurse into directories"); opts.optflag("R", "recurse", "recurse into directories");
opts.optflag("T", "tree", "recurse into subdirectories in a tree view"); opts.optflag("T", "tree", "recurse into directories as a tree");
opts.optflag("x", "across", "sort multi-column view entries across"); opts.optflag("F", "classify", "display type indicator by file names (one of */=@|)");
opts.optflag("F", "classify", "show file type indicator (one of */=@|)"); opts.optopt ("", "color", "when to use terminal colours", "WHEN");
opts.optopt ("", "color", "when to show anything in colours", "WHEN"); opts.optopt ("", "colour", "when to use terminal colours", "WHEN");
opts.optopt ("", "colour", "when to show anything in colours (alternate spelling)", "WHEN"); opts.optflag("", "color-scale", "highlight levels of file sizes distinctly");
opts.optflag("", "color-scale", "use a colour scale when displaying file sizes (alternate spelling)"); opts.optflag("", "colour-scale", "highlight levels of file sizes distinctly");
opts.optflag("", "colour-scale", "use a colour scale when displaying file sizes");
// Filtering and sorting options // Filtering and sorting options
opts.optflag("", "group-directories-first", "list directories before other files"); opts.optflag("", "group-directories-first", "sort directories before other files");
opts.optflag("a", "all", "show dot-files"); opts.optflag("a", "all", "don't hide hidden and 'dot' files");
opts.optflag("d", "list-dirs", "list directories as regular files"); opts.optflag("d", "list-dirs", "list directories like regular files");
opts.optflag("r", "reverse", "reverse order of files"); opts.optopt ("L", "level", "limit the depth of recursion", "DEPTH");
opts.optopt ("s", "sort", "field to sort by", "WORD"); opts.optflag("r", "reverse", "reverse the sert order");
opts.optopt ("I", "ignore-glob", "patterns (|-separated) of names to ignore", "GLOBS"); opts.optopt ("s", "sort", "which field to sort by", "WORD");
opts.optopt ("I", "ignore-glob", "ignore files that match these glob patterns", "GLOB1|GLOB2...");
// Long view options // Long view options
opts.optflag("b", "binary", "use binary prefixes in file sizes"); opts.optflag("b", "binary", "list file sizes with binary prefixes");
opts.optflag("B", "bytes", "list file sizes in bytes, without prefixes"); opts.optflag("B", "bytes", "list file sizes in bytes, without prefixes");
opts.optflag("g", "group", "show group as well as user"); opts.optflag("g", "group", "list each file's group");
opts.optflag("h", "header", "show a header row at the top"); opts.optflag("h", "header", "add a header row to each column");
opts.optflag("H", "links", "show number of hard links"); opts.optflag("H", "links", "list each file's number of hard links");
opts.optflag("i", "inode", "show each file's inode number"); opts.optflag("i", "inode", "list each file's inode number");
opts.optopt ("L", "level", "maximum depth of recursion", "DEPTH"); opts.optflag("m", "modified", "use the modified timestamp field");
opts.optflag("m", "modified", "display timestamp of most recent modification"); opts.optflag("S", "blocks", "list each file's number of file system blocks");
opts.optflag("S", "blocks", "show number of file system blocks"); opts.optopt ("t", "time", "which timestamp field to show", "WORD");
opts.optopt ("t", "time", "which timestamp to show for a file", "WORD"); opts.optflag("u", "accessed", "use the accessed timestamp field");
opts.optflag("u", "accessed", "display timestamp of last access for a file"); opts.optflag("U", "created", "use the created timestamp field");
opts.optflag("U", "created", "display timestamp of creation for a file");
if cfg!(feature="git") { if cfg!(feature="git") {
opts.optflag("", "git", "show git status"); opts.optflag("", "git", "list each file's git status");
} }
if xattr::ENABLED { if xattr::ENABLED {
opts.optflag("@", "extended", "display extended attribute keys and sizes"); opts.optflag("@", "extended", "list each file's extended attribute keys and sizes");
} }
let matches = match opts.parse(args) { let matches = match opts.parse(args) {

View File

@ -4,8 +4,9 @@ use getopts;
use output::Colours; use output::Colours;
use output::{Grid, Details, GridDetails, Lines}; use output::{Grid, Details, GridDetails, Lines};
use options::{FileFilter, DirAction, Misfire};
use output::column::{Columns, TimeTypes, SizeFormat}; use output::column::{Columns, TimeTypes, SizeFormat};
use output::file_name::Classify;
use options::{FileFilter, DirAction, Misfire};
use term::dimensions; use term::dimensions;
use fs::feature::xattr; use fs::feature::xattr;
@ -58,7 +59,7 @@ impl View {
filter: filter.clone(), filter: filter.clone(),
xattr: xattr::ENABLED && matches.opt_present("extended"), xattr: xattr::ENABLED && matches.opt_present("extended"),
colours: colours, colours: colours,
classify: matches.opt_present("classify"), classify: Classify::deduce(matches),
}; };
Ok(details) Ok(details)
@ -87,8 +88,7 @@ impl View {
}; };
let other_options_scan = || { let other_options_scan = || {
let classify = matches.opt_present("classify"); let classify = Classify::deduce(matches);
let term_colours = TerminalColours::deduce(matches)?; let term_colours = TerminalColours::deduce(matches)?;
let term_width = TerminalWidth::deduce()?; let term_width = TerminalWidth::deduce()?;
@ -366,3 +366,12 @@ impl TerminalColours {
} }
} }
} }
impl Classify {
fn deduce(matches: &getopts::Matches) -> Classify {
if matches.opt_present("classify") { Classify::AddFileIndicators }
else { Classify::JustFilenames }
}
}

View File

@ -5,8 +5,6 @@ use std::ops::{Add, Deref, DerefMut};
use ansi_term::{Style, ANSIString, ANSIStrings}; use ansi_term::{Style, ANSIString, ANSIStrings};
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
use fs::File;
/// An individual cell that holds text in a table, used in the details and /// An individual cell that holds text in a table, used in the details and
/// lines views to store ANSI-terminal-formatted data before it is printed. /// lines views to store ANSI-terminal-formatted data before it is printed.
@ -161,6 +159,22 @@ impl TextCellContents {
pub fn strings(&self) -> ANSIStrings { pub fn strings(&self) -> ANSIStrings {
ANSIStrings(&self.0) ANSIStrings(&self.0)
} }
/// Calculates the width that a cell with these contents would take up, by
/// counting the number of characters in each unformatted ANSI string.
pub fn width(&self) -> DisplayWidth {
let foo = self.0.iter().map(|anstr| anstr.chars().count()).sum();
DisplayWidth(foo)
}
/// Promotes these contents to a full cell containing them alongside
/// their calculated width.
pub fn promote(self) -> TextCell {
TextCell {
width: self.width(),
contents: self,
}
}
} }
@ -180,19 +194,6 @@ impl TextCellContents {
#[derive(PartialEq, Debug, Clone, Copy, Default)] #[derive(PartialEq, Debug, Clone, Copy, Default)]
pub struct DisplayWidth(usize); pub struct DisplayWidth(usize);
impl DisplayWidth {
pub fn from_file(file: &File, classify: bool) -> DisplayWidth {
let name_width = *DisplayWidth::from(&*file.name);
if classify {
if file.is_executable_file() || file.is_directory() ||
file.is_pipe() || file.is_link() || file.is_socket() {
return DisplayWidth(name_width + 1);
}
}
DisplayWidth(name_width)
}
}
impl<'a> From<&'a str> for DisplayWidth { impl<'a> From<&'a str> for DisplayWidth {
fn from(input: &'a str) -> DisplayWidth { fn from(input: &'a str) -> DisplayWidth {
DisplayWidth(UnicodeWidthStr::width(input)) DisplayWidth(UnicodeWidthStr::width(input))

View File

@ -22,6 +22,7 @@ pub struct Colours {
pub symlink_path: Style, pub symlink_path: Style,
pub broken_arrow: Style, pub broken_arrow: Style,
pub broken_filename: Style, pub broken_filename: Style,
pub control_char: Style,
} }
#[derive(Clone, Copy, Debug, Default, PartialEq)] #[derive(Clone, Copy, Debug, Default, PartialEq)]
@ -170,7 +171,8 @@ impl Colours {
symlink_path: Cyan.normal(), symlink_path: Cyan.normal(),
broken_arrow: Red.normal(), broken_arrow: Red.normal(),
broken_filename: Red.underline() broken_filename: Red.underline(),
control_char: Red.normal(),
} }
} }

View File

@ -99,9 +99,9 @@ use fs::feature::xattr::{Attribute, FileAttributes};
use options::{FileFilter, RecurseOptions}; use options::{FileFilter, RecurseOptions};
use output::colours::Colours; use output::colours::Colours;
use output::column::{Alignment, Column, Columns, SizeFormat}; use output::column::{Alignment, Column, Columns, SizeFormat};
use output::cell::{TextCell, DisplayWidth}; use output::cell::{TextCell, TextCellContents, DisplayWidth};
use output::tree::TreeTrunk; use output::tree::TreeTrunk;
use super::filename; use output::file_name::{FileName, LinkStyle, Classify};
/// With the **Details** view, the output gets formatted into columns, with /// With the **Details** view, the output gets formatted into columns, with
@ -142,7 +142,7 @@ pub struct Details {
pub colours: Colours, pub colours: Colours,
/// Whether to show a file type indiccator. /// Whether to show a file type indiccator.
pub classify: bool, pub classify: Classify,
} }
/// The **environment** struct contains any data that could change between /// The **environment** struct contains any data that could change between
@ -306,23 +306,11 @@ impl Details {
for (index, egg) in file_eggs.into_iter().enumerate() { for (index, egg) in file_eggs.into_iter().enumerate() {
let mut files = Vec::new(); let mut files = Vec::new();
let mut errors = egg.errors; let mut errors = egg.errors;
let mut width = DisplayWidth::from_file(&egg.file, self.classify);
if egg.file.dir.is_none() {
if let Some(parent) = egg.file.path.parent() {
width = width + 1 + DisplayWidth::from(parent.to_string_lossy().as_ref());
}
}
let name = TextCell {
contents: filename(&egg.file, &self.colours, true, self.classify),
width: width,
};
let row = Row { let row = Row {
depth: depth, depth: depth,
cells: Some(egg.cells), cells: Some(egg.cells),
name: name, name: FileName::new(&egg.file, LinkStyle::FullLinkPaths, self.classify, &self.colours).paint().promote(),
last: index == num_eggs - 1, last: index == num_eggs - 1,
}; };
@ -455,19 +443,8 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> {
self.rows.push(row); self.rows.push(row);
} }
pub fn filename_cell(&self, file: File, links: bool) -> TextCell { pub fn filename(&self, file: File, links: LinkStyle) -> TextCellContents {
let mut width = DisplayWidth::from_file(&file, self.opts.classify); FileName::new(&file, links, self.opts.classify, &self.opts.colours).paint()
if file.dir.is_none() {
if let Some(parent) = file.path.parent() {
width = width + 1 + DisplayWidth::from(parent.to_string_lossy().as_ref());
}
}
TextCell {
contents: filename(&file, &self.opts.colours, links, self.opts.classify),
width: width,
}
} }
pub fn add_file_with_cells(&mut self, cells: Vec<TextCell>, name_cell: TextCell, depth: usize, last: bool) { pub fn add_file_with_cells(&mut self, cells: Vec<TextCell>, name_cell: TextCell, depth: usize, last: bool) {

25
src/output/escape.rs Normal file
View File

@ -0,0 +1,25 @@
use ansi_term::{ANSIString, Style};
pub fn escape<'a>(string: String, bits: &mut Vec<ANSIString<'a>>, good: Style, bad: Style) {
if string.chars().all(|c| c >= 0x20 as char) {
bits.push(good.paint(string));
}
else {
for c in string.chars() {
// The `escape_default` method on `char` is *almost* what we want here, but
// it still escapes non-ASCII UTF-8 characters, which are still printable.
if c >= 0x20 as char {
// TODO: This allocates way too much,
// hence the `all` check above.
let mut s = String::new();
s.push(c);
bits.push(good.paint(s));
} else {
let s = c.escape_default().collect::<String>();
bits.push(bad.paint(s));
}
}
}
}

238
src/output/file_name.rs Normal file
View File

@ -0,0 +1,238 @@
use std::path::Path;
use ansi_term::{ANSIString, Style};
use fs::{File, FileTarget};
use output::Colours;
use output::escape;
use output::cell::TextCellContents;
/// A **file name** holds all the information necessary to display the name
/// of the given file. This is used in all of the views.
pub struct FileName<'a, 'dir: 'a> {
/// A reference to the file that we're getting the name of.
file: &'a File<'dir>,
/// The colours used to paint the file name and its surrounding text.
colours: &'a Colours,
/// The file that this file points to if it's a link.
target: Option<FileTarget<'dir>>,
/// How to handle displaying links.
link_style: LinkStyle,
/// Whether to append file class characters to file names.
classify: Classify,
}
impl<'a, 'dir> FileName<'a, 'dir> {
/// Create a new `FileName` that prints the given files name, painting it
/// with the remaining arguments.
pub fn new(file: &'a File<'dir>, link_style: LinkStyle, classify: Classify, colours: &'a Colours) -> FileName<'a, 'dir> {
let target = if file.is_link() { Some(file.link_target()) }
else { None };
FileName {
file: file,
colours: colours,
target: target,
link_style: link_style,
classify: classify,
}
}
/// Paints the name of the file using the colours, resulting in a vector
/// of coloured cells that can be printed to the terminal.
///
/// This method returns some `TextCellContents`, rather than a `TextCell`,
/// because for the last cell in a table, it doesnt need to have its
/// width calculated.
pub fn paint(&self) -> TextCellContents {
let mut bits = Vec::new();
if self.file.dir.is_none() {
if let Some(parent) = self.file.path.parent() {
self.add_parent_bits(&mut bits, parent);
}
}
if !self.file.name.is_empty() {
for bit in self.coloured_file_name() {
bits.push(bit);
}
}
if let (LinkStyle::FullLinkPaths, Some(ref target)) = (self.link_style, self.target.as_ref()) {
match **target {
FileTarget::Ok(ref target) => {
bits.push(Style::default().paint(" "));
bits.push(self.colours.punctuation.paint("->"));
bits.push(Style::default().paint(" "));
if let Some(parent) = target.path.parent() {
self.add_parent_bits(&mut bits, parent);
}
if !target.name.is_empty() {
let target = FileName::new(&target, LinkStyle::FullLinkPaths, Classify::JustFilenames, self.colours);
for bit in target.coloured_file_name() {
bits.push(bit);
}
}
},
FileTarget::Broken(ref broken_path) => {
bits.push(Style::default().paint(" "));
bits.push(self.colours.broken_arrow.paint("->"));
bits.push(Style::default().paint(" "));
escape(broken_path.display().to_string(), &mut bits, self.colours.broken_filename, self.colours.control_char.underline());
},
FileTarget::Err(_) => {
// Do nothing -- the error gets displayed on the next line
},
}
}
else if let Classify::AddFileIndicators = self.classify {
if let Some(class) = self.classify_char() {
bits.push(Style::default().paint(class));
}
}
bits.into()
}
/// Adds the bits of the parent path to the given bits vector.
/// The path gets its characters escaped based on the colours.
fn add_parent_bits(&self, bits: &mut Vec<ANSIString>, parent: &Path) {
let coconut = parent.components().count();
if coconut == 1 && parent.has_root() {
bits.push(self.colours.symlink_path.paint("/"));
}
else if coconut >= 1 {
escape(parent.to_string_lossy().to_string(), bits, self.colours.symlink_path, self.colours.control_char);
bits.push(self.colours.symlink_path.paint("/"));
}
}
/// The character to be displayed after a file when classifying is on, if
/// the files type has one associated with it.
fn classify_char(&self) -> Option<&'static str> {
if self.file.is_executable_file() {
Some("*")
} else if self.file.is_directory() {
Some("/")
} else if self.file.is_pipe() {
Some("|")
} else if self.file.is_link() {
Some("@")
} else if self.file.is_socket() {
Some("=")
} else {
None
}
}
/// Returns at least one ANSI-highlighted string representing this files
/// name using the given set of colours.
///
/// Ordinarily, this will be just one string: the files complete name,
/// coloured according to its file type. If the name contains control
/// characters such as newlines or escapes, though, we cant just print them
/// to the screen directly, because then therell be newlines in weird places.
///
/// So in that situation, those characters will be escaped and highlighted in
/// a different colour.
fn coloured_file_name<'unused>(&self) -> Vec<ANSIString<'unused>> {
let file_style = self.style();
let mut bits = Vec::new();
escape(self.file.name.clone(), &mut bits, file_style, self.colours.control_char);
bits
}
/// Figures out which colour to paint the filename part of the output,
/// depending on which “type” of file it appears to be -- either from the
/// class on the filesystem or from its name.
pub fn style(&self) -> Style {
// Override the style with the “broken link” style when this file is
// a link that we cant follow for whatever reason. This is used when
// theres no other place to show that the link doesnt work.
if let LinkStyle::JustFilenames = self.link_style {
if let Some(ref target) = self.target {
if target.is_broken() {
return self.colours.broken_arrow;
}
}
}
// Otherwise, just apply a bunch of rules in order. For example,
// executable image files should be executable rather than images.
match self.file {
f if f.is_directory() => self.colours.filetypes.directory,
f if f.is_executable_file() => self.colours.filetypes.executable,
f if f.is_link() => self.colours.filetypes.symlink,
f if f.is_pipe() => self.colours.filetypes.pipe,
f if f.is_char_device()
| f.is_block_device() => self.colours.filetypes.device,
f if f.is_socket() => self.colours.filetypes.socket,
f if !f.is_file() => self.colours.filetypes.special,
f if f.is_immediate() => self.colours.filetypes.immediate,
f if f.is_image() => self.colours.filetypes.image,
f if f.is_video() => self.colours.filetypes.video,
f if f.is_music() => self.colours.filetypes.music,
f if f.is_lossless() => self.colours.filetypes.lossless,
f if f.is_crypto() => self.colours.filetypes.crypto,
f if f.is_document() => self.colours.filetypes.document,
f if f.is_compressed() => self.colours.filetypes.compressed,
f if f.is_temp() => self.colours.filetypes.temp,
f if f.is_compiled() => self.colours.filetypes.compiled,
_ => self.colours.filetypes.normal,
}
}
}
/// When displaying a file name, there needs to be some way to handle broken
/// links, depending on how long the resulting Cell can be.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum LinkStyle {
/// Just display the file names, but colour them differently if theyre
/// a broken link or cant be followed.
JustFilenames,
/// Display all files in their usual style, but follow each link with an
/// arrow pointing to their path, colouring the path differently if its
/// a broken link, and doing nothing if it cant be followed.
FullLinkPaths,
}
/// Whether to append file class characters to the file names.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum Classify {
/// Just display the file names, without any characters.
JustFilenames,
/// Add a character after the file name depending on what class of file
/// it is.
AddFileIndicators,
}
impl Default for Classify {
fn default() -> Classify {
Classify::JustFilenames
}
}

View File

@ -3,9 +3,8 @@ use std::io::{Write, Result as IOResult};
use term_grid as grid; use term_grid as grid;
use fs::File; use fs::File;
use output::DisplayWidth;
use output::colours::Colours; use output::colours::Colours;
use super::filename; use output::file_name::{FileName, LinkStyle, Classify};
#[derive(PartialEq, Debug, Copy, Clone)] #[derive(PartialEq, Debug, Copy, Clone)]
@ -13,7 +12,7 @@ pub struct Grid {
pub across: bool, pub across: bool,
pub console_width: usize, pub console_width: usize,
pub colours: Colours, pub colours: Colours,
pub classify: bool, pub classify: Classify,
} }
impl Grid { impl Grid {
@ -29,16 +28,11 @@ impl Grid {
grid.reserve(files.len()); grid.reserve(files.len());
for file in files.iter() { for file in files.iter() {
let mut width = DisplayWidth::from_file(file, self.classify); let filename = FileName::new(file, LinkStyle::JustFilenames, self.classify, &self.colours).paint();
let width = filename.width();
if file.dir.is_none() {
if let Some(parent) = file.path.parent() {
width = width + 1 + DisplayWidth::from(parent.to_string_lossy().as_ref());
}
}
grid.add(grid::Cell { grid.add(grid::Cell {
contents: filename(file, &self.colours, false, self.classify).strings().to_string(), contents: filename.strings().to_string(),
width: *width, width: *width,
}); });
} }
@ -49,7 +43,8 @@ impl Grid {
else { else {
// File names too long for a grid - drop down to just listing them! // File names too long for a grid - drop down to just listing them!
for file in files.iter() { for file in files.iter() {
writeln!(w, "{}", filename(file, &self.colours, false, self.classify).strings())?; let name_cell = FileName::new(file, LinkStyle::JustFilenames, self.classify, &self.colours).paint();
writeln!(w, "{}", name_cell.strings())?;
} }
Ok(()) Ok(())
} }

View File

@ -12,6 +12,8 @@ use output::cell::TextCell;
use output::column::Column; use output::column::Column;
use output::details::{Details, Table, Environment}; use output::details::{Details, Table, Environment};
use output::grid::Grid; use output::grid::Grid;
use output::file_name::LinkStyle;
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
pub struct GridDetails { pub struct GridDetails {
@ -45,7 +47,7 @@ impl GridDetails {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let file_names = files.into_iter() let file_names = files.into_iter()
.map(|file| first_table.filename_cell(file, false)) .map(|file| first_table.filename(file, LinkStyle::JustFilenames).promote())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
(cells, file_names) (cells, file_names)

View File

@ -4,21 +4,22 @@ use ansi_term::ANSIStrings;
use fs::File; use fs::File;
use super::filename; use output::file_name::{FileName, LinkStyle, Classify};
use super::colours::Colours; use super::colours::Colours;
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct Lines { pub struct Lines {
pub colours: Colours, pub colours: Colours,
pub classify: bool, pub classify: Classify,
} }
/// The lines view literally just displays each file, line-by-line. /// The lines view literally just displays each file, line-by-line.
impl Lines { impl Lines {
pub fn view<W: Write>(&self, files: Vec<File>, w: &mut W) -> IOResult<()> { pub fn view<W: Write>(&self, files: Vec<File>, w: &mut W) -> IOResult<()> {
for file in files { for file in files {
writeln!(w, "{}", ANSIStrings(&filename(&file, &self.colours, true, self.classify)))?; let name_cell = FileName::new(&file, LinkStyle::FullLinkPaths, self.classify, &self.colours).paint();
writeln!(w, "{}", ANSIStrings(&name_cell))?;
} }
Ok(()) Ok(())
} }

View File

@ -1,13 +1,10 @@
use ansi_term::Style;
use fs::{File, FileTarget};
pub use self::cell::{TextCell, TextCellContents, DisplayWidth}; pub use self::cell::{TextCell, TextCellContents, DisplayWidth};
pub use self::colours::Colours; pub use self::colours::Colours;
pub use self::details::Details; pub use self::details::Details;
pub use self::grid_details::GridDetails; pub use self::grid_details::GridDetails;
pub use self::grid::Grid; pub use self::grid::Grid;
pub use self::lines::Lines; pub use self::lines::Lines;
pub use self::escape::escape;
mod grid; mod grid;
pub mod details; pub mod details;
@ -17,101 +14,5 @@ pub mod column;
mod cell; mod cell;
mod colours; mod colours;
mod tree; mod tree;
pub mod file_name;
mod escape;
pub fn filename(file: &File, colours: &Colours, links: bool, classify: bool) -> TextCellContents {
let mut bits = Vec::new();
if file.dir.is_none() {
if let Some(parent) = file.path.parent() {
let coconut = parent.components().count();
if coconut == 1 && parent.has_root() {
bits.push(colours.symlink_path.paint("/"));
}
else if coconut >= 1 {
bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
bits.push(colours.symlink_path.paint("/"));
}
}
}
if !file.name.is_empty() {
bits.push(file_colour(colours, file).paint(file.name.clone()));
}
if links && file.is_link() {
match file.link_target() {
FileTarget::Ok(target) => {
bits.push(Style::default().paint(" "));
bits.push(colours.punctuation.paint("->"));
bits.push(Style::default().paint(" "));
if let Some(parent) = target.path.parent() {
let coconut = parent.components().count();
if coconut == 1 && parent.has_root() {
bits.push(colours.symlink_path.paint("/"));
}
else if coconut >= 1 {
bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
bits.push(colours.symlink_path.paint("/"));
}
}
if !target.name.is_empty() {
bits.push(file_colour(colours, &target).paint(target.name));
}
},
FileTarget::Broken(broken_path) => {
bits.push(Style::default().paint(" "));
bits.push(colours.broken_arrow.paint("->"));
bits.push(Style::default().paint(" "));
bits.push(colours.broken_filename.paint(broken_path.display().to_string()));
},
FileTarget::Err(_) => {
// Do nothing -- the error gets displayed on the next line
}
}
} else if classify {
if file.is_executable_file() {
bits.push(Style::default().paint("*"));
} else if file.is_directory() {
bits.push(Style::default().paint("/"));
} else if file.is_pipe() {
bits.push(Style::default().paint("|"));
} else if file.is_link() {
bits.push(Style::default().paint("@"));
} else if file.is_socket() {
bits.push(Style::default().paint("="));
}
}
bits.into()
}
pub fn file_colour(colours: &Colours, file: &File) -> Style {
match file {
f if f.is_directory() => colours.filetypes.directory,
f if f.is_executable_file() => colours.filetypes.executable,
f if f.is_link() => colours.filetypes.symlink,
f if f.is_pipe() => colours.filetypes.pipe,
f if f.is_char_device()
| f.is_block_device() => colours.filetypes.device,
f if f.is_socket() => colours.filetypes.socket,
f if !f.is_file() => colours.filetypes.special,
f if f.is_immediate() => colours.filetypes.immediate,
f if f.is_image() => colours.filetypes.image,
f if f.is_video() => colours.filetypes.video,
f if f.is_music() => colours.filetypes.music,
f if f.is_lossless() => colours.filetypes.lossless,
f if f.is_crypto() => colours.filetypes.crypto,
f if f.is_document() => colours.filetypes.document,
f if f.is_compressed() => colours.filetypes.compressed,
f if f.is_temp() => colours.filetypes.temp,
f if f.is_compiled() => colours.filetypes.compiled,
_ => colours.filetypes.normal,
}
}

6
xtests/file_names Normal file
View File

@ -0,0 +1,6 @@
ansi: [\u{1b}[34mblue\u{1b}[0m] form-feed: [\u{c}] new-line-dir: [\n]
ascii: hello invalid-utf8-1: [<5B>] new-line: [\n]
backspace: [\u{8}] invalid-utf8-2: [<5B>(] return: [\r]
bell: [\u{7}] invalid-utf8-3: [<5B>(] tab: [\t]
emoji: [🆒] invalid-utf8-4: [<5B>(<28>(] utf-8: pâté
escape: [\u{1b}] links vertical-tab: [\u{b}]

18
xtests/file_names_1 Normal file
View File

@ -0,0 +1,18 @@
ansi: [\u{1b}[34mblue\u{1b}[0m]
ascii: hello
backspace: [\u{8}]
bell: [\u{7}]
emoji: [🆒]
escape: [\u{1b}]
form-feed: [\u{c}]
invalid-utf8-1: [<5B>]
invalid-utf8-2: [<5B>(]
invalid-utf8-3: [<5B>(]
invalid-utf8-4: [<5B>(<28>(]
links
new-line-dir: [\n]
new-line: [\n]
return: [\r]
tab: [\t]
utf-8: pâté
vertical-tab: [\u{b}]

12
xtests/file_names_R Normal file
View File

@ -0,0 +1,12 @@
ansi: [\u{1b}[34mblue\u{1b}[0m] form-feed: [\u{c}] new-line-dir: [\n]
ascii: hello invalid-utf8-1: [<5B>] new-line: [\n]
backspace: [\u{8}] invalid-utf8-2: [<5B>(] return: [\r]
bell: [\u{7}] invalid-utf8-3: [<5B>(] tab: [\t]
emoji: [🆒] invalid-utf8-4: [<5B>(<28>(] utf-8: pâté
escape: [\u{1b}] links vertical-tab: [\u{b}]
/testcases/file-names/links:
another: [\n] broken subfile
/testcases/file-names/new-line-dir: [\n]:
another: [\n] subfile

29
xtests/file_names_T Normal file
View File

@ -0,0 +1,29 @@
/testcases/file-names
├── ansi: [\u{1b}[34mblue\u{1b}[0m]
├── ascii: hello
├── backspace: [\u{8}]
├── bell: [\u{7}]
├── emoji: [🆒]
├── escape: [\u{1b}]
├── form-feed: [\u{c}]
├── invalid-utf8-1: [<5B>]
│ └── <Error: path somehow contained a NUL?>
├── invalid-utf8-2: [<5B>(]
│ └── <Error: path somehow contained a NUL?>
├── invalid-utf8-3: [<5B>(]
│ └── <Error: path somehow contained a NUL?>
├── invalid-utf8-4: [<5B>(<28>(]
│ └── <Error: path somehow contained a NUL?>
├── links
│ ├── another: [\n] -> /testcases/file-names/new-line-dir: [\n]/another: [\n]
│ ├── broken -> /testcases/file-names/new-line-dir: [\n]/broken
│ │ └── <No such file or directory (os error 2)>
│ └── subfile -> /testcases/file-names/new-line-dir: [\n]/subfile
├── new-line-dir: [\n]
│ ├── another: [\n]
│ └── subfile
├── new-line: [\n]
├── return: [\r]
├── tab: [\t]
├── utf-8: pâté
└── vertical-tab: [\u{b}]

6
xtests/file_names_x Normal file
View File

@ -0,0 +1,6 @@
ansi: [\u{1b}[34mblue\u{1b}[0m] ascii: hello backspace: [\u{8}]
bell: [\u{7}] emoji: [🆒] escape: [\u{1b}]
form-feed: [\u{c}] invalid-utf8-1: [<5B>] invalid-utf8-2: [<5B>(]
invalid-utf8-3: [<5B>(] invalid-utf8-4: [<5B>(<28>(] links
new-line-dir: [\n] new-line: [\n] return: [\r]
tab: [\t] utf-8: pâté vertical-tab: [\u{b}]

13
xtests/files_star_100 Normal file
View File

@ -0,0 +1,13 @@
/testcases/files/10_bytes /testcases/files/1_KiB /testcases/files/5_MiB
/testcases/files/10_KiB /testcases/files/1_MiB /testcases/files/6_bytes
/testcases/files/10_MiB /testcases/files/2_bytes /testcases/files/6_KiB
/testcases/files/11_bytes /testcases/files/2_KiB /testcases/files/6_MiB
/testcases/files/11_KiB /testcases/files/2_MiB /testcases/files/7_bytes
/testcases/files/11_MiB /testcases/files/3_bytes /testcases/files/7_KiB
/testcases/files/12_bytes /testcases/files/3_KiB /testcases/files/7_MiB
/testcases/files/12_KiB /testcases/files/3_MiB /testcases/files/8_bytes
/testcases/files/12_MiB /testcases/files/4_bytes /testcases/files/8_KiB
/testcases/files/13_bytes /testcases/files/4_KiB /testcases/files/8_MiB
/testcases/files/13_KiB /testcases/files/4_MiB /testcases/files/9_bytes
/testcases/files/13_MiB /testcases/files/5_bytes /testcases/files/9_KiB
/testcases/files/1_bytes /testcases/files/5_KiB /testcases/files/9_MiB

8
xtests/files_star_150 Normal file
View File

@ -0,0 +1,8 @@
/testcases/files/10_bytes /testcases/files/12_MiB /testcases/files/2_KiB /testcases/files/5_bytes /testcases/files/7_MiB
/testcases/files/10_KiB /testcases/files/13_bytes /testcases/files/2_MiB /testcases/files/5_KiB /testcases/files/8_bytes
/testcases/files/10_MiB /testcases/files/13_KiB /testcases/files/3_bytes /testcases/files/5_MiB /testcases/files/8_KiB
/testcases/files/11_bytes /testcases/files/13_MiB /testcases/files/3_KiB /testcases/files/6_bytes /testcases/files/8_MiB
/testcases/files/11_KiB /testcases/files/1_bytes /testcases/files/3_MiB /testcases/files/6_KiB /testcases/files/9_bytes
/testcases/files/11_MiB /testcases/files/1_KiB /testcases/files/4_bytes /testcases/files/6_MiB /testcases/files/9_KiB
/testcases/files/12_bytes /testcases/files/1_MiB /testcases/files/4_KiB /testcases/files/7_bytes /testcases/files/9_MiB
/testcases/files/12_KiB /testcases/files/2_bytes /testcases/files/4_MiB /testcases/files/7_KiB

6
xtests/files_star_200 Normal file
View File

@ -0,0 +1,6 @@
/testcases/files/10_bytes /testcases/files/12_bytes /testcases/files/1_bytes /testcases/files/3_bytes /testcases/files/5_bytes /testcases/files/7_bytes /testcases/files/9_bytes
/testcases/files/10_KiB /testcases/files/12_KiB /testcases/files/1_KiB /testcases/files/3_KiB /testcases/files/5_KiB /testcases/files/7_KiB /testcases/files/9_KiB
/testcases/files/10_MiB /testcases/files/12_MiB /testcases/files/1_MiB /testcases/files/3_MiB /testcases/files/5_MiB /testcases/files/7_MiB /testcases/files/9_MiB
/testcases/files/11_bytes /testcases/files/13_bytes /testcases/files/2_bytes /testcases/files/4_bytes /testcases/files/6_bytes /testcases/files/8_bytes
/testcases/files/11_KiB /testcases/files/13_KiB /testcases/files/2_KiB /testcases/files/4_KiB /testcases/files/6_KiB /testcases/files/8_KiB
/testcases/files/11_MiB /testcases/files/13_MiB /testcases/files/2_MiB /testcases/files/4_MiB /testcases/files/6_MiB /testcases/files/8_MiB

39
xtests/files_star_lG_100 Normal file
View File

@ -0,0 +1,39 @@
.rw-r--r-- 10 cassowary  1 Jan 12:34 /testcases/files/10_bytes
.rw-r--r-- 10k cassowary  1 Jan 12:34 /testcases/files/10_KiB
.rw-r--r-- 10M cassowary  1 Jan 12:34 /testcases/files/10_MiB
.rw-r--r-- 11 cassowary  1 Jan 12:34 /testcases/files/11_bytes
.rw-r--r-- 11k cassowary  1 Jan 12:34 /testcases/files/11_KiB
.rw-r--r-- 11M cassowary  1 Jan 12:34 /testcases/files/11_MiB
.rw-r--r-- 12 cassowary  1 Jan 12:34 /testcases/files/12_bytes
.rw-r--r-- 12k cassowary  1 Jan 12:34 /testcases/files/12_KiB
.rw-r--r-- 12M cassowary  1 Jan 12:34 /testcases/files/12_MiB
.rw-r--r-- 13 cassowary  1 Jan 12:34 /testcases/files/13_bytes
.rw-r--r-- 13k cassowary  1 Jan 12:34 /testcases/files/13_KiB
.rw-r--r-- 13M cassowary  1 Jan 12:34 /testcases/files/13_MiB
.rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes
.rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB
.rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB
.rw-r--r-- 2 cassowary  1 Jan 12:34 /testcases/files/2_bytes
.rw-r--r-- 2.0k cassowary  1 Jan 12:34 /testcases/files/2_KiB
.rw-r--r-- 2.1M cassowary  1 Jan 12:34 /testcases/files/2_MiB
.rw-r--r-- 3 cassowary  1 Jan 12:34 /testcases/files/3_bytes
.rw-r--r-- 3.1k cassowary  1 Jan 12:34 /testcases/files/3_KiB
.rw-r--r-- 3.1M cassowary  1 Jan 12:34 /testcases/files/3_MiB
.rw-r--r-- 4 cassowary  1 Jan 12:34 /testcases/files/4_bytes
.rw-r--r-- 4.1k cassowary  1 Jan 12:34 /testcases/files/4_KiB
.rw-r--r-- 4.2M cassowary  1 Jan 12:34 /testcases/files/4_MiB
.rw-r--r-- 5 cassowary  1 Jan 12:34 /testcases/files/5_bytes
.rw-r--r-- 5.1k cassowary  1 Jan 12:34 /testcases/files/5_KiB
.rw-r--r-- 5.2M cassowary  1 Jan 12:34 /testcases/files/5_MiB
.rw-r--r-- 6 cassowary  1 Jan 12:34 /testcases/files/6_bytes
.rw-r--r-- 6.1k cassowary  1 Jan 12:34 /testcases/files/6_KiB
.rw-r--r-- 6.3M cassowary  1 Jan 12:34 /testcases/files/6_MiB
.rw-r--r-- 7 cassowary  1 Jan 12:34 /testcases/files/7_bytes
.rw-r--r-- 7.2k cassowary  1 Jan 12:34 /testcases/files/7_KiB
.rw-r--r-- 7.3M cassowary  1 Jan 12:34 /testcases/files/7_MiB
.rw-r--r-- 8 cassowary  1 Jan 12:34 /testcases/files/8_bytes
.rw-r--r-- 8.2k cassowary  1 Jan 12:34 /testcases/files/8_KiB
.rw-r--r-- 8.4M cassowary  1 Jan 12:34 /testcases/files/8_MiB
.rw-r--r-- 9 cassowary  1 Jan 12:34 /testcases/files/9_bytes
.rw-r--r-- 9.2k cassowary  1 Jan 12:34 /testcases/files/9_KiB
.rw-r--r-- 9.4M cassowary  1 Jan 12:34 /testcases/files/9_MiB

20
xtests/files_star_lG_150 Normal file
View File

@ -0,0 +1,20 @@
.rw-r--r-- 10 cassowary  1 Jan 12:34 /testcases/files/10_bytes .rw-r--r-- 3.1M cassowary  1 Jan 12:34 /testcases/files/3_MiB
.rw-r--r-- 10k cassowary  1 Jan 12:34 /testcases/files/10_KiB .rw-r--r-- 4 cassowary  1 Jan 12:34 /testcases/files/4_bytes
.rw-r--r-- 10M cassowary  1 Jan 12:34 /testcases/files/10_MiB .rw-r--r-- 4.1k cassowary  1 Jan 12:34 /testcases/files/4_KiB
.rw-r--r-- 11 cassowary  1 Jan 12:34 /testcases/files/11_bytes .rw-r--r-- 4.2M cassowary  1 Jan 12:34 /testcases/files/4_MiB
.rw-r--r-- 11k cassowary  1 Jan 12:34 /testcases/files/11_KiB .rw-r--r-- 5 cassowary  1 Jan 12:34 /testcases/files/5_bytes
.rw-r--r-- 11M cassowary  1 Jan 12:34 /testcases/files/11_MiB .rw-r--r-- 5.1k cassowary  1 Jan 12:34 /testcases/files/5_KiB
.rw-r--r-- 12 cassowary  1 Jan 12:34 /testcases/files/12_bytes .rw-r--r-- 5.2M cassowary  1 Jan 12:34 /testcases/files/5_MiB
.rw-r--r-- 12k cassowary  1 Jan 12:34 /testcases/files/12_KiB .rw-r--r-- 6 cassowary  1 Jan 12:34 /testcases/files/6_bytes
.rw-r--r-- 12M cassowary  1 Jan 12:34 /testcases/files/12_MiB .rw-r--r-- 6.1k cassowary  1 Jan 12:34 /testcases/files/6_KiB
.rw-r--r-- 13 cassowary  1 Jan 12:34 /testcases/files/13_bytes .rw-r--r-- 6.3M cassowary  1 Jan 12:34 /testcases/files/6_MiB
.rw-r--r-- 13k cassowary  1 Jan 12:34 /testcases/files/13_KiB .rw-r--r-- 7 cassowary  1 Jan 12:34 /testcases/files/7_bytes
.rw-r--r-- 13M cassowary  1 Jan 12:34 /testcases/files/13_MiB .rw-r--r-- 7.2k cassowary  1 Jan 12:34 /testcases/files/7_KiB
.rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes .rw-r--r-- 7.3M cassowary  1 Jan 12:34 /testcases/files/7_MiB
.rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB .rw-r--r-- 8 cassowary  1 Jan 12:34 /testcases/files/8_bytes
.rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB .rw-r--r-- 8.2k cassowary  1 Jan 12:34 /testcases/files/8_KiB
.rw-r--r-- 2 cassowary  1 Jan 12:34 /testcases/files/2_bytes .rw-r--r-- 8.4M cassowary  1 Jan 12:34 /testcases/files/8_MiB
.rw-r--r-- 2.0k cassowary  1 Jan 12:34 /testcases/files/2_KiB .rw-r--r-- 9 cassowary  1 Jan 12:34 /testcases/files/9_bytes
.rw-r--r-- 2.1M cassowary  1 Jan 12:34 /testcases/files/2_MiB .rw-r--r-- 9.2k cassowary  1 Jan 12:34 /testcases/files/9_KiB
.rw-r--r-- 3 cassowary  1 Jan 12:34 /testcases/files/3_bytes .rw-r--r-- 9.4M cassowary  1 Jan 12:34 /testcases/files/9_MiB
.rw-r--r-- 3.1k cassowary  1 Jan 12:34 /testcases/files/3_KiB

13
xtests/files_star_lG_200 Normal file
View File

@ -0,0 +1,13 @@
.rw-r--r-- 10 cassowary  1 Jan 12:34 /testcases/files/10_bytes .rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB .rw-r--r-- 5.2M cassowary  1 Jan 12:34 /testcases/files/5_MiB
.rw-r--r-- 10k cassowary  1 Jan 12:34 /testcases/files/10_KiB .rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB .rw-r--r-- 6 cassowary  1 Jan 12:34 /testcases/files/6_bytes
.rw-r--r-- 10M cassowary  1 Jan 12:34 /testcases/files/10_MiB .rw-r--r-- 2 cassowary  1 Jan 12:34 /testcases/files/2_bytes .rw-r--r-- 6.1k cassowary  1 Jan 12:34 /testcases/files/6_KiB
.rw-r--r-- 11 cassowary  1 Jan 12:34 /testcases/files/11_bytes .rw-r--r-- 2.0k cassowary  1 Jan 12:34 /testcases/files/2_KiB .rw-r--r-- 6.3M cassowary  1 Jan 12:34 /testcases/files/6_MiB
.rw-r--r-- 11k cassowary  1 Jan 12:34 /testcases/files/11_KiB .rw-r--r-- 2.1M cassowary  1 Jan 12:34 /testcases/files/2_MiB .rw-r--r-- 7 cassowary  1 Jan 12:34 /testcases/files/7_bytes
.rw-r--r-- 11M cassowary  1 Jan 12:34 /testcases/files/11_MiB .rw-r--r-- 3 cassowary  1 Jan 12:34 /testcases/files/3_bytes .rw-r--r-- 7.2k cassowary  1 Jan 12:34 /testcases/files/7_KiB
.rw-r--r-- 12 cassowary  1 Jan 12:34 /testcases/files/12_bytes .rw-r--r-- 3.1k cassowary  1 Jan 12:34 /testcases/files/3_KiB .rw-r--r-- 7.3M cassowary  1 Jan 12:34 /testcases/files/7_MiB
.rw-r--r-- 12k cassowary  1 Jan 12:34 /testcases/files/12_KiB .rw-r--r-- 3.1M cassowary  1 Jan 12:34 /testcases/files/3_MiB .rw-r--r-- 8 cassowary  1 Jan 12:34 /testcases/files/8_bytes
.rw-r--r-- 12M cassowary  1 Jan 12:34 /testcases/files/12_MiB .rw-r--r-- 4 cassowary  1 Jan 12:34 /testcases/files/4_bytes .rw-r--r-- 8.2k cassowary  1 Jan 12:34 /testcases/files/8_KiB
.rw-r--r-- 13 cassowary  1 Jan 12:34 /testcases/files/13_bytes .rw-r--r-- 4.1k cassowary  1 Jan 12:34 /testcases/files/4_KiB .rw-r--r-- 8.4M cassowary  1 Jan 12:34 /testcases/files/8_MiB
.rw-r--r-- 13k cassowary  1 Jan 12:34 /testcases/files/13_KiB .rw-r--r-- 4.2M cassowary  1 Jan 12:34 /testcases/files/4_MiB .rw-r--r-- 9 cassowary  1 Jan 12:34 /testcases/files/9_bytes
.rw-r--r-- 13M cassowary  1 Jan 12:34 /testcases/files/13_MiB .rw-r--r-- 5 cassowary  1 Jan 12:34 /testcases/files/5_bytes .rw-r--r-- 9.2k cassowary  1 Jan 12:34 /testcases/files/9_KiB
.rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes .rw-r--r-- 5.1k cassowary  1 Jan 12:34 /testcases/files/5_KiB .rw-r--r-- 9.4M cassowary  1 Jan 12:34 /testcases/files/9_MiB

View File

@ -1,2 +1,2 @@
broken forbidden parent_dir some_file some_file_relative broken forbidden parent_dir some_file some_file_relative
current_dir itself root some_file_absolute usr current_dir itself root some_file_absolute usr

View File

@ -33,6 +33,10 @@ COLUMNS=120 $exa $testcases/files | diff -q - $results/files_120 || exit 1
COLUMNS=160 $exa $testcases/files | diff -q - $results/files_160 || exit 1 COLUMNS=160 $exa $testcases/files | diff -q - $results/files_160 || exit 1
COLUMNS=200 $exa $testcases/files | diff -q - $results/files_200 || exit 1 COLUMNS=200 $exa $testcases/files | diff -q - $results/files_200 || exit 1
COLUMNS=100 $exa $testcases/files/* | diff -q - $results/files_star_100 || exit 1
COLUMNS=150 $exa $testcases/files/* | diff -q - $results/files_star_150 || exit 1
COLUMNS=200 $exa $testcases/files/* | diff -q - $results/files_star_200 || exit 1
# Long grid view tests # Long grid view tests
COLUMNS=40 $exa $testcases/files -lG | diff -q - $results/files_lG_40 || exit 1 COLUMNS=40 $exa $testcases/files -lG | diff -q - $results/files_lG_40 || exit 1
@ -41,6 +45,10 @@ COLUMNS=120 $exa $testcases/files -lG | diff -q - $results/files_lG_120 || exit
COLUMNS=160 $exa $testcases/files -lG | diff -q - $results/files_lG_160 || exit 1 COLUMNS=160 $exa $testcases/files -lG | diff -q - $results/files_lG_160 || exit 1
COLUMNS=200 $exa $testcases/files -lG | diff -q - $results/files_lG_200 || exit 1 COLUMNS=200 $exa $testcases/files -lG | diff -q - $results/files_lG_200 || exit 1
COLUMNS=100 $exa $testcases/files/* -lG | diff -q - $results/files_star_lG_100 || exit 1
COLUMNS=150 $exa $testcases/files/* -lG | diff -q - $results/files_star_lG_150 || exit 1
COLUMNS=200 $exa $testcases/files/* -lG | diff -q - $results/files_star_lG_200 || exit 1
# Attributes # Attributes
$exa $testcases/attributes -l@T | diff -q - $results/attributes || exit 1 $exa $testcases/attributes -l@T | diff -q - $results/attributes || exit 1
@ -54,6 +62,13 @@ $exa $testcases/passwd -lgh | diff -q - $results/passwd || exit 1
sudo -u cassowary $exa $testcases/permissions -lghR 2>&1 | diff -q - $results/permissions_sudo || exit 1 sudo -u cassowary $exa $testcases/permissions -lghR 2>&1 | diff -q - $results/permissions_sudo || exit 1
$exa $testcases/permissions -lghR 2>&1 | diff -q - $results/permissions || exit 1 $exa $testcases/permissions -lghR 2>&1 | diff -q - $results/permissions || exit 1
# File names
# (Mostly escaping control characters in file names)
COLUMNS=80 $exa $testcases/file-names 2>&1 | diff -q - $results/file_names || exit 1
COLUMNS=80 $exa $testcases/file-names -x 2>&1 | diff -q - $results/file_names_x || exit 1
COLUMNS=80 $exa $testcases/file-names -R 2>&1 | diff -q - $results/file_names_R || exit 1
$exa $testcases/file-names -1 2>&1 | diff -q - $results/file_names_1 || exit 1
$exa $testcases/file-names -T 2>&1 | diff -q - $results/file_names_T || exit 1
# File types # File types
$exa $testcases/file-names-exts -1 2>&1 | diff -q - $results/file-names-exts || exit 1 $exa $testcases/file-names-exts -1 2>&1 | diff -q - $results/file-names-exts || exit 1