eza
eza copied to clipboard
feat: Support configuration file
In checking out LSD earlier today before I eventually found my way here. one of the first things that sticks out is their support for a config file (I believe they use yaml)
I think it's a decent longer term goal, as it allows for sharing of "themes" between users and doesn't require ENV VAR="ga;23", etc etc
If that is something the project is interested in, the first thing would probably be to decide on what format and therefore what crates to use.
I'd say using serde and either TOML (because it's what cargo uses) or YAML (because it's more expressive but still simple).
I prefer YAML tbh.
There was a previous issue about this, but I'd be fine with writing this from scratch, after a bit more discussion about the details.
E.g. I'd want to consider whether it was time to bring https://github.com/eza-community/eza/issues/68 back up.
What do you think about removing ENV_VAR support in favor of a config file?
Perhaps either the default installation behavior, or probably more realistically just a (--dump-config ?) command, could be checking if they exist, and generating the initial/default config based on them.
definitely yaml or toml would be the obvious choice, and then I guess the choice of crate is even more obvious(serde). so YAML++
What do you think about removing ENV_VAR support in favor of a config file?
I'd probably not want to remove it but rather support both, letting env vars override config options.
Also, I'm definitely in favor of serde.
Would the preferred behavior be that the user can configure their default output completely in the config file?
So instead of putting together an alias
for their preferred output eza --icons --git -l -a etc
, and then setting ENV VAR's to adjust the details of the color output, etc... Al the options for eza's default output would be configured in ~/.config/eza.yaml
(or somewhere similar). Meaning that command line arguments when specifically passed, would override the output section of the config file.
The colors/modifications currently done in the ENV VAR's would stay the same, as they override anyway.
Does this sound like the right track?
Another train of thought would be the either config file itself passed as an argument eza --config ~/.config/eza.yaml
, or just reloaded each time changes are made. Idk there has to be some performance issues I'm not considering, I"m just thinking out loud at this point.
Having a default behavior defined in the config file would probably make sense, but I think it would come a bit later.
Idk there has to be some performance issues
I've benchmarked loading a yaml config file before in seidr:
Even if 80.596 µs is intolerable, people could just not use a config file, and I'm pretty sure the check for its existence wouldn't be an issue.
Having the ability to override the default config location is ofc pretty useful, so I'd definetly want to include that.
That is surprisingly fast.. I didn't think that it would be performance prohibitive necessarily, but that simplifies it for sure. At that point no need to worry about caching/user reloading :+1:
I was drafting some of this up to see what it would look like, definitely going to be tricky to integrate, but I am new to the code base. Seeing as you have self assigned it, just let me know if there is something I can contribute.
Config options/syntax there are probably a couple different approaches?
display:
icons: auto
colors: auto
sort:
- git-ignore
- only-dirs
Or:
args:
- icons
- colors
- no-permissions
- grid
colors:
git-ignore: "red; bold"
empty-dir: "green; bold"
I like that Eza/Exa is kind of an opinionated replacement for LS, I think the overwhelming majority of users are heavy terminal/CLI people who are going to be looking for things like icon support. The config should make it easy to comment out a couple lines and have their output looking good.
Just to put a pin in this for when I (or some other person doing flake stuff in the far future) gets to it, https://github.com/serde-rs/serde/issues/2538 exists, this might cause issues for our lovely flake (or iterations on it, if we move from naersk to crane or something).
Potential starting points for fixes:
- https://github.com/DBCDK/rust-modules/commit/6e265de7fdd24ef87c31216f42ed14f24f00af26
- https://github.com/serde-rs/serde/issues/2538#issuecomment-1682694271
- Maybe we can pin to a older version, would suck because security
welp
Also, I'm definitely in favor of serde.
I'm still in favor of serde, it's so powerful that it's definitely worth this hassle. Not a lot more hassle thou, but this is fine.
I'm not experienced enough to weigh in on a choice but I thought id mention KDL in case it's a suitable option. Zellij and Pop_OS are two notable projects I know of that use it.
I'm not experienced enough to weigh in on a choice but I thought id mention KDL in case it's a suitable option. Zellij and Pop_OS are two notable projects I know of that use it.
I'm glad for the suggestion, but on first inspection, I'm not sure any of the 3 options for libraries are at a scale or maturity where I'd feel comfortable introducing them at the moment.
That said, I'll try to keep tabs on it and see if other rust projects start using it.
KDL is a document language with
XML
-like semantics
They kinda lost me right there..
But in all seriousness, it does look interesting. Especially because Zellij and Pop_OS went with them.
I am surprised I hadn't heard of this problem with serde. Seems odd that something like that could even occur, you would think everyone would know that it would be an issue... Definitely something to keep an eye on
Just to put a pin in this for when I (or some other person doing flake stuff in the far future) gets to it, https://github.com/serde-rs/serde/issues/2538 exists, this might cause issues for our lovely flake (or iterations on it, if we move from naersk to crane or something).
https://github.com/serde-rs/serde/releases/tag/v1.0.184
Restore from-source serde_derive build on all platforms — eventually we'd like to use a first-class precompiled macro if such a thing becomes supported by cargo / crates.io
Looks like it might not be a problem
I'd like to see a config file implemented as well. In the meantime, this is my hack.
Step 1 — Add argument handler script.
Step 1 runs a script to pass eza
the options stored in the opts
array and any command-line arguments passed to the script. The $@
syntax passes all command-line arguments passed to the script as separate arguments to eza.
- Create the script:
touch ~/.bin/eza
- Add the following code:
#!/usr/bin/env zsh
set -euo pipefail
readonly file="$HOME/.ezarc"
readonly opts=("${(f):-$(<"$file")}")
/usr/local/bin/eza "${opts[@]}" "$@"
- Make it executable.
chmod +x ~/.bin/eza
Step 2 — Load default arguments into your config file.
- Create the config file:
touch ~/.ezarc
- Add your preferred default arguments (one per line). E.g.:
--all
--colour=always
--git
--git-ignore
--group-directories-first
--icons
--long
--time-style=iso
Step 3 – Update ~/.zshrc
or ~/.zsh_aliases
(optional). E.g.:
- Add or update aliases. If you were using
exa
, all you need to do is changeexa
toeza
.
# aliases
## global aliases
alias -g ldd='eza -D --sort=mod' # list directories, sort, descending, MODIFIED
alias -g ldn='eza -Dr' # list directories, sort, descending, NAME
alias -g lsD='eza -r --sort=mod' # sort, ascending, MODIFIED
alias -g lsN='eza -r' # sort, ascending, name
alias -g lsS='eza -r --sort=size' # sort, ascending, size
alias -g lsd='eza --sort=mod' # sort, descending, MODIFIED
alias -g lsn='eza' # sort, descending, NAME
alias -g lss='eza --sort=size' # sort, descending, SIZE
alias -g lst='eza --tree --level=2' # sort, descending, NAME && show directory tree
- Save your work and source your
~/.zshrc
and/or~/.zsh_aliases
again and you're good-to-go.
Copy-pasting what I wrote at the time in https://github.com/ogham/exa/issues/511#issuecomment-812936674, whit a few modifications.
Here’s a suggested, hypothetical config file, inspired by ui_styles.rs/default_theme.rs:
~/.config/exa/exa.toml
# The [colors] table has all that’s possible to configure with EXA_COLORS
# and filekinds too, in a much more readable way!!
[colors.ui]
punctuation = "black bold"
# date = ""
# inode = ""
# blocks = ""
# header = ""
# link_path = ""
# control_char = ""
# broken_path = ""
[colors.filetypes]
# file = ""
# directory = ""
# executable = ""
# pipe = ""
# socket = ""
# block_device = ""
# char_device = ""
# symlink = ""
# broken_symlink = ""
[colors.filekinds]
temp = "white"
# build = "yellow bold"
image = "purple"
video = "purple bold"
music = "cyan"
lossless = "cyan bold"
crypto = "green bold"
document = "green"
# compressed = "red"
compiled = "yellow"
[colors.perms]
# ur = ""
# uw = ""
# ux_file = ""
# ux_other = ""
# gr = ""
# gw = ""
# gx = ""
# or = ""
# ow = ""
# ox = ""
# special_user_file = ""
# special_other = ""
# extended_attribute = ""
[colors.sizes]
# the two first are default, and overridden by the more specific variants.
# nums = ""
# units = ""
num-byte = "green"
num-kilo = "green bold"
num-mega = "yellow"
num-giga = "red"
num-huge = "purple"
unit-byte = "green"
unit-kilo = "green bold"
unit-mega = "yellow"
unit-giga = "red"
unit-huge = "purple"
# major = ""
# minor = ""
[colors.users]
# user-you = ""
# user-other = ""
# group-yours = ""
# group-other = ""
[colors.links]
# normal = ""
# multi = ""
[colors.git]
# new = ""
# modified = ""
# deleted = ""
# renamed = ""
# changed = ""
## The [[ and ]] signals that colors.custom is an array of table.
[[colors.custom]]
patterns = ["*.md", "*.rst"]
style = "yellow bold"
[[colors.custom]]
patterns = [".py"]
style = "red underline"
## Everything else that was controlled by environment variables.
# Maybe some of them are more useful as environment variable tho,
# e.g. icon_spacing may depend on the terminal which could have a different setup…
[options]
# columns =
strict = true
# grid_rows
# icon_spacing
Also:
- I believe a config file shouldn’t try to do what’s already doable with shell aliases
- Maybe we can use redirect people to use
LS_COLORS
and https://github.com/sharkdp/vivid for files
I believe a config file shouldn’t try to do what’s already doable with shell aliases
I think I've heard a lot that some people do desire the ability to make a default command.
EDIT: nvm I am was too fast to think about what I was saying >_<
I believe a config file shouldn’t try to do what’s already doable with shell aliases
That's a pretty puzzling position to take, tbh... Shell aliases are rather a hacky way to alter the default behaviour of another program, unless it is is very specifically related to it working properly with that shell.
With that said even then I think you'd normally resort to environment variables first if an option...
It is of course rather a matter of opinion but I've personally never really liked relying on aliasing from my shell. Mostly just my taste in organisation, but there are the rare odd corner cases which cause trouble long after you have forgotten you've aliased a command...
I personally think most programs should have robust options for configuring all their default params, and I would almost always favour a hierarchy following something like the de facto standard:
-
/etc/foo/
for default/example config files from the project itself or your distro dev/packagers -
/etc/foo/conf.d/
for system-wide config overrides by the sysadmin that will be persist across upstream changes -
$XDG_CONFIG_HOME/foo/
for per-user global configuration files - environment variables as set by various profile/init files of shells etc.
- flags passed directly to a specific invocation of the program
As I say, this is certainly somewhat opinion based, but it is also a clear hierarchy heading from global -> specific behaviour at each step.
With that said even then I think you'd normally resort to environment variables first if an option...
This reminds me that I made the .theme file work this way, I think ENV variables should take priority even from just a backwards-compatability perspective.
Also, currently just have $XDG_CONFIG_HOME/eza/theme.yml
for theme/icons support drafted up. Do we think everyone would like to see a system-wide option available? For configuration only, or theme as well?
That's a pretty puzzling position to take, tbh... Shell aliases are rather a hacky way to alter the default behaviour of another program, unless it is is very specifically related to it working properly with that shell.
This reminds me that I made the .theme file work this way, I think ENV variables should take priority even from just a backwards-compatability perspective.
Well traditionally, basic shell utilities like ls
are configurable mostly via command line flags and environment variables. I personally feel like using aliases to set default flags or alternate command/shorcuts is easy and standard, but that environment variables are easy to forget and a bad way to configure complicated thing like theming (and as such should be overridden by config files, in my opinion).
I guess a few behavior things could be configured in a config file but then it raises the question of: how useful is it to be able to control behavior in another way vs added complexity, when there’s already a feature that does just that pretty well.
But ultimately I don’t really care if users can configure their theming easily in a config file.
A note on aliases:
I recently made the transition to shell abbreviations
and I think they're quite nice.
The difference between alias and abbreviation is that the latter will be replaced by the full command after pressing enter/space. Nothing is hidden or abstracted from either the user or the shell history. It also helps the user to learn and remember commands they've abbreviated, so the use of abbreviations is not hampering your ability to proficiently operate outside of your machine.
That being said, it would not be ideal to flood the terminal with an abbreviation that turns the characters ll
into a 200 character long theme definition, so the ideal still demands some other way to define certain defaults.
My 2c is that a config file certainly worth having, because the environment is fairly fluid while a config file is reliably static. Subshells, exec() calls, certain ssh/other remote sessions, etc can interfere with the variables available to the eza process.
Plus, sample config file with lots of comments also doubles as quick documentation reference- I always appreciate it when projects do that.
I personally vote toml > yaml. For whatever reason, I find yaml really difficult to make visual sense of. Moreover- users are going to be sharing configs via copy/paste. Be it reporting bugs here in github issues, asking for help over chat programs, "show off your config" discussion threads.
Whitespace is highly susceptible to being mangled in a lot of copy/paste contexts, so avoiding the whitespace sensitive yaml in this context would be prudent.
Also just to make sure we're all on the same page, I feel features like abbreviations are better left to the shell, there is some level of separation of concerns here that would make sense to uphold, it wouldn't ultimately be eza's job to recreate a fully featured terminal experience in place of the actual shell that's normally tasked with providing these features.
The above is not meant to suggest eza should handle abbreviations, it's a continuation of the conversation around aliases, and how a config file is beneficial even while aliases/abbreviations exist.