mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
dircolors: implemented
TODO: More test case
This commit is contained in:
parent
c9f363d09c
commit
ad9bfcef5b
2 changed files with 572 additions and 0 deletions
192
src/dircolors/colors.rs
Normal file
192
src/dircolors/colors.rs
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
pub const INTERNAL_DB: &'static str =
|
||||||
|
r#"# Configuration file for dircolors, a utility to help you set the
|
||||||
|
# LS_COLORS environment variable used by GNU ls with the --color option.
|
||||||
|
# Copyright (C) 1996-2016 Free Software Foundation, Inc.
|
||||||
|
# Copying and distribution of this file, with or without modification,
|
||||||
|
# are permitted provided the copyright notice and this notice are preserved.
|
||||||
|
# The keywords COLOR, OPTIONS, and EIGHTBIT (honored by the
|
||||||
|
# slackware version of dircolors) are recognized but ignored.
|
||||||
|
# Below are TERM entries, which can be a glob patterns, to match
|
||||||
|
# against the TERM environment variable to determine if it is colorizable.
|
||||||
|
TERM Eterm
|
||||||
|
TERM ansi
|
||||||
|
TERM color-xterm
|
||||||
|
TERM con[0-9]*x[0-9]*
|
||||||
|
TERM cons25
|
||||||
|
TERM console
|
||||||
|
TERM cygwin
|
||||||
|
TERM dtterm
|
||||||
|
TERM eterm-color
|
||||||
|
TERM gnome
|
||||||
|
TERM gnome-256color
|
||||||
|
TERM hurd
|
||||||
|
TERM jfbterm
|
||||||
|
TERM konsole
|
||||||
|
TERM kterm
|
||||||
|
TERM linux
|
||||||
|
TERM linux-c
|
||||||
|
TERM mach-color
|
||||||
|
TERM mach-gnu-color
|
||||||
|
TERM mlterm
|
||||||
|
TERM putty
|
||||||
|
TERM putty-256color
|
||||||
|
TERM rxvt*
|
||||||
|
TERM screen*
|
||||||
|
TERM st
|
||||||
|
TERM st-256color
|
||||||
|
TERM terminator
|
||||||
|
TERM tmux*
|
||||||
|
TERM vt100
|
||||||
|
TERM xterm*
|
||||||
|
# Below are the color init strings for the basic file types. A color init
|
||||||
|
# string consists of one or more of the following numeric codes:
|
||||||
|
# Attribute codes:
|
||||||
|
# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
|
||||||
|
# Text color codes:
|
||||||
|
# 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
|
||||||
|
# Background color codes:
|
||||||
|
# 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
|
||||||
|
#NORMAL 00 # no color code at all
|
||||||
|
#FILE 00 # regular file: use no color at all
|
||||||
|
RESET 0 # reset to "normal" color
|
||||||
|
DIR 01;34 # directory
|
||||||
|
LINK 01;36 # symbolic link. (If you set this to 'target' instead of a
|
||||||
|
# numerical value, the color is as for the file pointed to.)
|
||||||
|
MULTIHARDLINK 00 # regular file with more than one link
|
||||||
|
FIFO 40;33 # pipe
|
||||||
|
SOCK 01;35 # socket
|
||||||
|
DOOR 01;35 # door
|
||||||
|
BLK 40;33;01 # block device driver
|
||||||
|
CHR 40;33;01 # character device driver
|
||||||
|
ORPHAN 40;31;01 # symlink to nonexistent file, or non-stat'able file ...
|
||||||
|
MISSING 00 # ... and the files they point to
|
||||||
|
SETUID 37;41 # file that is setuid (u+s)
|
||||||
|
SETGID 30;43 # file that is setgid (g+s)
|
||||||
|
CAPABILITY 30;41 # file with capability
|
||||||
|
STICKY_OTHER_WRITABLE 30;42 # dir that is sticky and other-writable (+t,o+w)
|
||||||
|
OTHER_WRITABLE 34;42 # dir that is other-writable (o+w) and not sticky
|
||||||
|
STICKY 37;44 # dir with the sticky bit set (+t) and not other-writable
|
||||||
|
# This is for files with execute permission:
|
||||||
|
EXEC 01;32
|
||||||
|
# List any file extensions like '.gz' or '.tar' that you would like ls
|
||||||
|
# to colorize below. Put the extension, a space, and the color init string.
|
||||||
|
# (and any comments you want to add after a '#')
|
||||||
|
# If you use DOS-style suffixes, you may want to uncomment the following:
|
||||||
|
#.cmd 01;32 # executables (bright green)
|
||||||
|
#.exe 01;32
|
||||||
|
#.com 01;32
|
||||||
|
#.btm 01;32
|
||||||
|
#.bat 01;32
|
||||||
|
# Or if you want to colorize scripts even if they do not have the
|
||||||
|
# executable bit actually set.
|
||||||
|
#.sh 01;32
|
||||||
|
#.csh 01;32
|
||||||
|
# archives or compressed (bright red)
|
||||||
|
.tar 01;31
|
||||||
|
.tgz 01;31
|
||||||
|
.arc 01;31
|
||||||
|
.arj 01;31
|
||||||
|
.taz 01;31
|
||||||
|
.lha 01;31
|
||||||
|
.lz4 01;31
|
||||||
|
.lzh 01;31
|
||||||
|
.lzma 01;31
|
||||||
|
.tlz 01;31
|
||||||
|
.txz 01;31
|
||||||
|
.tzo 01;31
|
||||||
|
.t7z 01;31
|
||||||
|
.zip 01;31
|
||||||
|
.z 01;31
|
||||||
|
.Z 01;31
|
||||||
|
.dz 01;31
|
||||||
|
.gz 01;31
|
||||||
|
.lrz 01;31
|
||||||
|
.lz 01;31
|
||||||
|
.lzo 01;31
|
||||||
|
.xz 01;31
|
||||||
|
.bz2 01;31
|
||||||
|
.bz 01;31
|
||||||
|
.tbz 01;31
|
||||||
|
.tbz2 01;31
|
||||||
|
.tz 01;31
|
||||||
|
.deb 01;31
|
||||||
|
.rpm 01;31
|
||||||
|
.jar 01;31
|
||||||
|
.war 01;31
|
||||||
|
.ear 01;31
|
||||||
|
.sar 01;31
|
||||||
|
.rar 01;31
|
||||||
|
.alz 01;31
|
||||||
|
.ace 01;31
|
||||||
|
.zoo 01;31
|
||||||
|
.cpio 01;31
|
||||||
|
.7z 01;31
|
||||||
|
.rz 01;31
|
||||||
|
.cab 01;31
|
||||||
|
# image formats
|
||||||
|
.jpg 01;35
|
||||||
|
.jpeg 01;35
|
||||||
|
.gif 01;35
|
||||||
|
.bmp 01;35
|
||||||
|
.pbm 01;35
|
||||||
|
.pgm 01;35
|
||||||
|
.ppm 01;35
|
||||||
|
.tga 01;35
|
||||||
|
.xbm 01;35
|
||||||
|
.xpm 01;35
|
||||||
|
.tif 01;35
|
||||||
|
.tiff 01;35
|
||||||
|
.png 01;35
|
||||||
|
.svg 01;35
|
||||||
|
.svgz 01;35
|
||||||
|
.mng 01;35
|
||||||
|
.pcx 01;35
|
||||||
|
.mov 01;35
|
||||||
|
.mpg 01;35
|
||||||
|
.mpeg 01;35
|
||||||
|
.m2v 01;35
|
||||||
|
.mkv 01;35
|
||||||
|
.webm 01;35
|
||||||
|
.ogm 01;35
|
||||||
|
.mp4 01;35
|
||||||
|
.m4v 01;35
|
||||||
|
.mp4v 01;35
|
||||||
|
.vob 01;35
|
||||||
|
.qt 01;35
|
||||||
|
.nuv 01;35
|
||||||
|
.wmv 01;35
|
||||||
|
.asf 01;35
|
||||||
|
.rm 01;35
|
||||||
|
.rmvb 01;35
|
||||||
|
.flc 01;35
|
||||||
|
.avi 01;35
|
||||||
|
.fli 01;35
|
||||||
|
.flv 01;35
|
||||||
|
.gl 01;35
|
||||||
|
.dl 01;35
|
||||||
|
.xcf 01;35
|
||||||
|
.xwd 01;35
|
||||||
|
.yuv 01;35
|
||||||
|
.cgm 01;35
|
||||||
|
.emf 01;35
|
||||||
|
# http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions
|
||||||
|
.ogv 01;35
|
||||||
|
.ogx 01;35
|
||||||
|
# audio formats
|
||||||
|
.aac 00;36
|
||||||
|
.au 00;36
|
||||||
|
.flac 00;36
|
||||||
|
.m4a 00;36
|
||||||
|
.mid 00;36
|
||||||
|
.midi 00;36
|
||||||
|
.mka 00;36
|
||||||
|
.mp3 00;36
|
||||||
|
.mpc 00;36
|
||||||
|
.ogg 00;36
|
||||||
|
.ra 00;36
|
||||||
|
.wav 00;36
|
||||||
|
# http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions
|
||||||
|
.oga 00;36
|
||||||
|
.opus 00;36
|
||||||
|
.spx 00;36
|
||||||
|
.xspf 00;36"#;
|
380
src/dircolors/dircolors.rs
Normal file
380
src/dircolors/dircolors.rs
Normal file
|
@ -0,0 +1,380 @@
|
||||||
|
#![crate_name = "uu_dircolors"]
|
||||||
|
|
||||||
|
// This file is part of the uutils coreutils package.
|
||||||
|
//
|
||||||
|
// (c) Jian Zeng <anonymousknight96@gmail.com>
|
||||||
|
//
|
||||||
|
// For the full copyright and license information, please view the LICENSE
|
||||||
|
// file that was distributed with this source code.
|
||||||
|
//
|
||||||
|
|
||||||
|
extern crate libc;
|
||||||
|
extern crate glob;
|
||||||
|
extern crate getopts;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate uucore;
|
||||||
|
|
||||||
|
use getopts::Options;
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader, Write};
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
static NAME: &'static str = "dircolors";
|
||||||
|
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
mod colors;
|
||||||
|
use colors::INTERNAL_DB;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
enum OutputFmt {
|
||||||
|
Shell,
|
||||||
|
CShell,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! disp_err {
|
||||||
|
($($args:tt)+) => ({
|
||||||
|
pipe_write!(&mut ::std::io::stderr(), "{}: ", NAME);
|
||||||
|
pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
|
||||||
|
pipe_writeln!(&mut ::std::io::stderr(), "Try '{} --help' for more information.", NAME);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn guess_syntax() -> OutputFmt {
|
||||||
|
match env::var("SHELL") {
|
||||||
|
Ok(s) => {
|
||||||
|
if s.is_empty() {
|
||||||
|
return OutputFmt::Unknown;
|
||||||
|
}
|
||||||
|
if let Some(last) = s.rsplit('/').next() {
|
||||||
|
if last == "csh" || last == "tcsh" {
|
||||||
|
OutputFmt::CShell
|
||||||
|
} else {
|
||||||
|
OutputFmt::Shell
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
OutputFmt::Shell
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => OutputFmt::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
|
let mut opts = Options::new();
|
||||||
|
|
||||||
|
opts.optflag("b", "sh", "output Bourne shell code to set LS_COLORS");
|
||||||
|
opts.optflag("",
|
||||||
|
"bourne-shell",
|
||||||
|
"output Bourne shell code to set LS_COLORS");
|
||||||
|
opts.optflag("c", "csh", "output C shell code to set LS_COLORS");
|
||||||
|
opts.optflag("", "c-shell", "output C shell code to set LS_COLORS");
|
||||||
|
opts.optflag("p", "print-database", "print the byte counts");
|
||||||
|
|
||||||
|
opts.optflag("h", "help", "display this help and exit");
|
||||||
|
opts.optflag("", "version", "output version information and exit");
|
||||||
|
|
||||||
|
let matches = match opts.parse(&args[1..]) {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(f) => crash!(1, "Invalid options\n{}", f),
|
||||||
|
};
|
||||||
|
|
||||||
|
if matches.opt_present("help") {
|
||||||
|
println!("Usage: {} [OPTION]... [FILE]
|
||||||
|
Output commands to set the LS_COLORS environment variable.
|
||||||
|
|
||||||
|
Determine format of output:
|
||||||
|
-b, --sh, --bourne-shell output Bourne shell code to set LS_COLORS
|
||||||
|
-c, --csh, --c-shell output C shell code to set LS_COLORS
|
||||||
|
-p, --print-database output defaults
|
||||||
|
--help display this help and exit
|
||||||
|
--version output version information and exit
|
||||||
|
|
||||||
|
If FILE is specified, read it to determine which colors to use for which
|
||||||
|
file types and extensions. Otherwise, a precompiled database is used.
|
||||||
|
For details on the format of these files, run 'dircolors --print-database'.",
|
||||||
|
NAME);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches.opt_present("version") {
|
||||||
|
println!("{} {}", NAME, VERSION);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches.opt_present("csh") || matches.opt_present("c-shell") ||
|
||||||
|
matches.opt_present("sh") || matches.opt_present("bourne-shell")) &&
|
||||||
|
matches.opt_present("print-database") {
|
||||||
|
disp_err!("the options to output dircolors' internal database and\nto select a shell \
|
||||||
|
syntax are mutually exclusive");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches.opt_present("print-database") {
|
||||||
|
if !matches.free.is_empty() {
|
||||||
|
disp_err!("extra operand ‘{}’\nfile operands cannot be combined with \
|
||||||
|
--print-database (-p)",
|
||||||
|
matches.free[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
println!("{}", INTERNAL_DB);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut out_format = OutputFmt::Unknown;
|
||||||
|
if matches.opt_present("csh") || matches.opt_present("c-shell") {
|
||||||
|
out_format = OutputFmt::CShell;
|
||||||
|
} else if matches.opt_present("sh") || matches.opt_present("bourne-shell") {
|
||||||
|
out_format = OutputFmt::Shell;
|
||||||
|
}
|
||||||
|
|
||||||
|
if out_format == OutputFmt::Unknown {
|
||||||
|
match guess_syntax() {
|
||||||
|
OutputFmt::Unknown => {
|
||||||
|
show_info!("no SHELL environment variable, and no shell type option given");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fmt => out_format = fmt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let result;
|
||||||
|
if matches.free.is_empty() {
|
||||||
|
result = parse(INTERNAL_DB.lines(), out_format, "")
|
||||||
|
} else {
|
||||||
|
if matches.free.len() > 1 {
|
||||||
|
disp_err!("extra operand ‘{}’", matches.free[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
match File::open(matches.free[0].as_str()) {
|
||||||
|
Ok(f) => {
|
||||||
|
let fin = BufReader::new(f);
|
||||||
|
result = parse(fin.lines().filter_map(|l| l.ok()),
|
||||||
|
out_format,
|
||||||
|
matches.free[0].as_str())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
show_info!("{}: {}", matches.free[0], e);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match result {
|
||||||
|
Ok(s) => {
|
||||||
|
println!("{}", s);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
Err(s) => {
|
||||||
|
show_info!("{}", s);
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait StrUtils {
|
||||||
|
fn purify(&self) -> &Self;
|
||||||
|
fn split_two(&self) -> (&str, &str);
|
||||||
|
fn fnmatch(&self, pattern: &str) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StrUtils for str {
|
||||||
|
/// Remove comments and trim whitespaces
|
||||||
|
fn purify(&self) -> &Self {
|
||||||
|
let mut line = self;
|
||||||
|
for (n, c) in self.chars().enumerate() {
|
||||||
|
if c != '#' {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if '#' is at the beginning of line
|
||||||
|
if n == 0 {
|
||||||
|
line = &self[..0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore the content after '#'
|
||||||
|
// only if it is preceded by at least one whitespace
|
||||||
|
if self.chars().nth(n - 1).unwrap().is_whitespace() {
|
||||||
|
line = &self[..n];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like split_whitespace() but only produce 2 components
|
||||||
|
fn split_two(&self) -> (&str, &str) {
|
||||||
|
if let Some(b) = self.find(char::is_whitespace) {
|
||||||
|
let key = &self[..b];
|
||||||
|
if let Some(e) = self[b..].find(|c: char| !c.is_whitespace()) {
|
||||||
|
(key, &self[b + e..])
|
||||||
|
} else {
|
||||||
|
(key, "")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
("", "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fnmatch(&self, pat: &str) -> bool {
|
||||||
|
pat.parse::<glob::Pattern>().unwrap().matches(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
enum ParseState {
|
||||||
|
Global,
|
||||||
|
Matched,
|
||||||
|
Continue,
|
||||||
|
Pass,
|
||||||
|
}
|
||||||
|
use std::collections::HashMap;
|
||||||
|
fn parse<T>(lines: T, fmt: OutputFmt, fp: &str) -> Result<String, String>
|
||||||
|
where T: IntoIterator,
|
||||||
|
T::Item: Borrow<str>
|
||||||
|
{
|
||||||
|
// 1440 > $(dircolors | wc -m)
|
||||||
|
let mut result = String::with_capacity(1440);
|
||||||
|
match fmt {
|
||||||
|
OutputFmt::Shell => result.push_str("LS_COLORS='"),
|
||||||
|
OutputFmt::CShell => result.push_str("setenv LS_COLORS '"),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut table: HashMap<&str, &str> = HashMap::with_capacity(48);
|
||||||
|
table.insert("normal", "no");
|
||||||
|
table.insert("norm", "no");
|
||||||
|
table.insert("file", "fi");
|
||||||
|
table.insert("reset", "rs");
|
||||||
|
table.insert("dir", "di");
|
||||||
|
table.insert("lnk", "ln");
|
||||||
|
table.insert("link", "ln");
|
||||||
|
table.insert("symlink", "ln");
|
||||||
|
table.insert("orphan", "or");
|
||||||
|
table.insert("missing", "mi");
|
||||||
|
table.insert("fifo", "pi");
|
||||||
|
table.insert("pipe", "pi");
|
||||||
|
table.insert("sock", "so");
|
||||||
|
table.insert("blk", "bd");
|
||||||
|
table.insert("block", "bd");
|
||||||
|
table.insert("chr", "cd");
|
||||||
|
table.insert("char", "cd");
|
||||||
|
table.insert("door", "do");
|
||||||
|
table.insert("exec", "ex");
|
||||||
|
table.insert("left", "lc");
|
||||||
|
table.insert("leftcode", "lc");
|
||||||
|
table.insert("right", "rc");
|
||||||
|
table.insert("rightcode", "rc");
|
||||||
|
table.insert("end", "ec");
|
||||||
|
table.insert("endcode", "ec");
|
||||||
|
table.insert("suid", "su");
|
||||||
|
table.insert("setuid", "su");
|
||||||
|
table.insert("sgid", "sg");
|
||||||
|
table.insert("setgid", "sg");
|
||||||
|
table.insert("sticky", "st");
|
||||||
|
table.insert("other_writable", "ow");
|
||||||
|
table.insert("owr", "ow");
|
||||||
|
table.insert("sticky_other_writable", "tw");
|
||||||
|
table.insert("owt", "tw");
|
||||||
|
table.insert("capability", "ca");
|
||||||
|
table.insert("multihardlink", "mh");
|
||||||
|
table.insert("clrtoeol", "cl");
|
||||||
|
|
||||||
|
let term = env::var("TERM").unwrap_or("none".to_owned());
|
||||||
|
let term = term.as_str();
|
||||||
|
|
||||||
|
let mut state = ParseState::Global;
|
||||||
|
|
||||||
|
for (num, line) in lines.into_iter().enumerate() {
|
||||||
|
let num = num + 1;
|
||||||
|
let line = line.borrow().purify();
|
||||||
|
if line.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (key, val) = line.split_two();
|
||||||
|
if val.is_empty() {
|
||||||
|
return Err(format!("{}:{}: invalid line; missing second token", fp, num));
|
||||||
|
}
|
||||||
|
let lower = key.to_lowercase();
|
||||||
|
|
||||||
|
if lower == "term" {
|
||||||
|
if term.fnmatch(val) {
|
||||||
|
state = ParseState::Matched;
|
||||||
|
} else if state != ParseState::Matched {
|
||||||
|
state = ParseState::Pass;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if state == ParseState::Matched {
|
||||||
|
// prevent subsequent mismatched TERM from
|
||||||
|
// cancelling the input
|
||||||
|
state = ParseState::Continue;
|
||||||
|
}
|
||||||
|
if state != ParseState::Pass {
|
||||||
|
if key.starts_with(".") {
|
||||||
|
result.push_str(format!("*{}={}:", key, val).as_str());
|
||||||
|
} else if key.starts_with("*") {
|
||||||
|
result.push_str(format!("{}={}:", key, val).as_str());
|
||||||
|
} else if lower == "options" || lower == "color" || lower == "eightbit" {
|
||||||
|
// Slackware only. Ignore
|
||||||
|
} else {
|
||||||
|
if let Some(s) = table.get(lower.as_str()) {
|
||||||
|
result.push_str(format!("{}={}:", s, val).as_str());
|
||||||
|
} else {
|
||||||
|
return Err(format!("{}:{}: unrecognized keyword {}", fp, num, key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match fmt {
|
||||||
|
OutputFmt::Shell => result.push_str("';\nexport LS_COLORS"),
|
||||||
|
OutputFmt::CShell => result.push('\''),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_shell_syntax() {
|
||||||
|
use std::env;
|
||||||
|
let last = env!("SHELL");
|
||||||
|
env::set_var("SHELL", "/path/csh");
|
||||||
|
assert_eq!(OutputFmt::CShell, guess_syntax());
|
||||||
|
env::set_var("SHELL", "csh");
|
||||||
|
assert_eq!(OutputFmt::CShell, guess_syntax());
|
||||||
|
env::set_var("SHELL", "/path/bash");
|
||||||
|
assert_eq!(OutputFmt::Shell, guess_syntax());
|
||||||
|
env::set_var("SHELL", "bash");
|
||||||
|
assert_eq!(OutputFmt::Shell, guess_syntax());
|
||||||
|
env::set_var("SHELL", "bash");
|
||||||
|
assert_eq!(OutputFmt::Shell, guess_syntax());
|
||||||
|
env::set_var("SHELL", "/asd/bar");
|
||||||
|
assert_eq!(OutputFmt::Shell, guess_syntax());
|
||||||
|
env::set_var("SHELL", "foo");
|
||||||
|
assert_eq!(OutputFmt::Shell, guess_syntax());
|
||||||
|
env::set_var("SHELL", "");
|
||||||
|
assert_eq!(OutputFmt::Unknown, guess_syntax());
|
||||||
|
env::remove_var("SHELL");
|
||||||
|
assert_eq!(OutputFmt::Unknown, guess_syntax());
|
||||||
|
|
||||||
|
env::set_var("SHELL", last);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_strutils() {
|
||||||
|
let s = " asd#zcv #hk\t\n ";
|
||||||
|
assert_eq!("asd#zcv", s.purify());
|
||||||
|
|
||||||
|
let s = "con256asd";
|
||||||
|
assert!(s.fnmatch("*[2][3-6][5-9]?sd"));
|
||||||
|
|
||||||
|
let s = "zxc \t\nqwe jlk hjl";
|
||||||
|
let (k, v) = s.split_two();
|
||||||
|
assert_eq!("zxc", k);
|
||||||
|
assert_eq!("qwe jlk hjl", v);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue