/darallium/です!ご覧いただきありがとうございます. 😊
「CLI初心者でも感動するような,それでいて汎用性・拡張性の高いCLIツール」を紹介する7日間の2日目の記事です 🙇
本日は「CLIツールそのもののの強化」をテーマに,lsd, ripgrep, difftasticを紹介します
lsd
lsd とは,Rustで書かれた「lsの完全上位互換」ツールである.一般に,fishを使うかある程度凝らなければいけない.lsのカラーリング,nerdfontなどを用いて視覚的にファイルを管理できる.
installation
dependencies
- cargo
mac, windows, linux
$ cargo install --git https://github.com/Peltoche/lsd.git --branch master
下記のように公式ドキュメントにはエイリアスを張る例もあるが,筆者はお勧めしない.
alias ls = 'lsd'
alias l='lsd -l'
alias la='lsd -a'
alias lla='lsd -la'
alias lt='lsd --tree'
※注意: 公式のreleaseは古いのでmasterブランチからbuildすること.
できること
とりあえず色んなディレクトリでlsd
して遊んでみるとよいだろう.コマンドライン引数はlsと同一なのでいろいろ試してみよう.デフォルトでもnerdfontフォントが貼ってあるので楽しめるだろう.
configをいじってみる
cliツールの醍醐味であるconfigをいじって自分好みのlasを作ってみよう.今回はサンプルを変更する形で自分好みのテーマを作ってみることを目標とする
デフォルトコンフィグを読み込む
以下に公式によるサンプルの改変を添付する.公式サンプルは動かないのである.ファイルの配置先は,linux,macOSユーザーの場合~/.config/lsd/
,windowsユーザーの場合%appdata%\lsd\
である.ファイル名はすべて固定であることに注意.
config.yaml
# == Classic ==
# This is a shorthand to override some of the options to be backwards compatible
# with `ls`. It affects the "color"->"when", "sorting"->"dir-grouping", "date"
# and "icons"->"when" options.
# Possible values: false, true
classic: false
# == Blocks ==
# This specifies the columns and their order when using the long and the tree
# layout.
# Possible values: permission, user, group, context, size, date, name, inode, links, git
blocks:
- permission
- user
- group
- size
- date
- name
# == Color ==
# This has various color options. (Will be expanded in the future.)
color:
# When to colorize the output.
# When "classic" is set, this is set to "never".
# Possible values: never, auto, always
when: auto
# How to colorize the output.
# When "classic" is set, this is set to "no-color".
# Possible values: default, custom
# When "custom" is set, lsd will look in the config directory for `colors.yaml`.
theme: custom
# == Date ==
# This specifies the date format for the date column. The freeform format
# accepts a strftime like string.
# When "classic" is set, this is set to "date".
# Possible values: date, relative, '+<date_format>'
# `date_format` will be a `strftime` formatted value. e.g. `date: '+%d %b %y %X'` will give you a date like this: 17 Jun 21 20:14:55
date: date
# == Dereference ==
# Whether to dereference symbolic links.
# Possible values: false, true
dereference: false
# == Display ==
# What items to display. Do not specify this for the default behavior.
# Possible values: all, almost-all, directory-only
# display: all
# == Icons ==
icons:
# When to use icons.
# When "classic" is set, this is set to "never".
# Possible values: always, auto, never
when: always
# Which icon theme to use.
# Possible values: fancy, unicode
theme: fancy
# Separator between icon and the name
# Default to 1 space
separator: " "
# == Ignore Globs ==
# A list of globs to ignore when listing.
# ignore-globs:
# - .git
# == Indicators ==
# Whether to add indicator characters to certain listed files.
# Possible values: false, true
indicators: false
# == Layout ==
# Which layout to use. "oneline" might be a bit confusing here and should be
# called "one-per-line". It might be changed in the future.
# Possible values: grid, tree, oneline
layout: grid
# == Recursion ==
recursion:
# Whether to enable recursion.
# Possible values: false, true
enabled: false
# How deep the recursion should go. This has to be a positive integer. Leave
# it unspecified for (virtually) infinite.
# depth: 3
# == Size ==
# Specifies the format of the size column.
# Possible values: default, short, bytes
size: default
# == Permission ==
# Specify the format of the permission column
# Possible value: rwx, octal
permission: rwx
# == Sorting ==
sorting:
# Specify what to sort by.
# Possible values: extension, name, time, size, version
column: name
# Whether to reverse the sorting.
# Possible values: false, true
reverse: false
# Whether to group directories together and where.
# When "classic" is set, this is set to "none".
# Possible values: first, last, none
dir-grouping: none
# == No Symlink ==
# Whether to omit showing symlink targets
# Possible values: false, true
no-symlink: false
# == Total size ==
# Whether to display the total size of directories.
# Possible values: false, true
total-size: false
# == Hyperlink ==
# Attach hyperlink to filenames
# Possible values: always, auto, never
hyperlink: never
# == Symlink arrow ==
# Specifies how the symlink arrow display, chars in both ascii and utf8
symlink-arrow: ⇒
# == Header ==
# Whether to display block headers.
# Possible values: false, true
header: false
# == Literal ==
# Whether to show quotes on filenames.
# Possible values: false, true
literal: false
# == Truncate owner ==
# How to truncate the username and group names for a file if they exceed a certain
# number of characters.
truncate-owner:
# Number of characters to keep. By default, no truncation is done (empty value).
after:
# String to be appended to a name if truncated.
marker: ""
colors.yaml
user: 230
group: 187
permission:
read: dark_green
write: dark_yellow
exec: dark_red
exec-sticky: 5
no-access: 245
octal: 6
acl: dark_cyan
context: cyan
date:
hour-old: 40
day-old: 42
older: 36
size:
none: 245
small: 229
medium: 216
large: 172
inode:
valid: 13
invalid: 245
links:
valid: 13
invalid: 245
tree-edge: 245
git-status:
default: 245
unmodified: 245
ignored: 245
new-in-index: dark_green
new-in-workdir: dark_green
typechange: dark_yellow
deleted: dark_red
renamed: dark_green
modified: dark_yellow
conflicted: dark_red
icons.yaml
name:
a.out:
Api:
.asoundrc:
.atom:
.ash:
.ash_history:
authorized_keys:
assets:
.android:
.audacity-data:
backups:
.bash_history:
.bash_logout:
.bash_profile:
.bashrc:
bin:
.bpython_history:
build:
bspwmrc:
build.ninja:
.cache:
cache:
cargo.lock:
cargo.toml:
.cargo:
.ccls-cache:
changelog:
.clang-format:
composer.json:
composer.lock:
conf.d:
config.ac:
config.el:
config.mk:
.config:
config:
configure:
content:
contributing:
copyright:
cron.daily:
cron.d:
cron.deny:
cron.hourly:
cron.monthly:
crontab:
cron.weekly:
crypttab:
.cshrc:
csh.cshrc:
csh.login:
csh.logout:
css:
custom.el:
.dbus:
desktop:
docker-compose.yml:
dockerfile:
doc:
dist:
documents:
.doom.d:
downloads:
.ds_store:
.editorconfig:
.electron-gyp:
.emacs.d:
.env:
environment:
.eslintrc.json:
.eslintrc.js:
.eslintrc.yml:
etc:
favicon.ico:
favicons:
fstab:
.fastboot:
.gitattributes:
.gitconfig:
.git-credentials:
.github:
gitignore_global:
.gitignore:
.gitlab-ci.yml:
.gitmodules:
.git:
.gnupg:
go.mod:
go.sum:
go.work:
gradle:
gradle.properties:
gradlew:
gradlew.bat:
group:
gruntfile.coffee:
gruntfile.js:
gruntfile.ls:
gshadow:
gulpfile.coffee:
gulpfile.js:
gulpfile.ls:
heroku.yml:
hidden:
home:
hostname:
hosts:
.htaccess:
htoprc:
.htpasswd:
.icons:
icons:
id_dsa:
id_ecdsa:
id_rsa:
.idlerc:
img:
include:
init.el:
.inputrc:
inputrc:
.java:
jenkinsfile:
js:
.jupyter:
kbuild:
kconfig:
kdeglobals:
kdenliverc:
known_hosts:
.kshrc:
libexec:
lib32:
lib64:
lib:
license.md:
licenses:
license.txt:
license:
localized:
lsb-release:
.lynxrc:
.mailcap:
mail:
magic:
maintainers:
makefile.ac:
makefile:
manifest:
md5sum:
meson.build:
metadata:
metadata.xml:
media:
.mime.types:
mime.types:
module.symvers:
.mozilla:
music:
muttrc:
.muttrc:
.mutt:
.mypy_cache:
neomuttrc:
.neomuttrc:
netlify.toml:
.nix-channels:
.nix-defexpr:
.node-gyp:
node_modules:
.node_repl_history:
npmignore:
.npm:
nvim:
obj:
os-release:
package.json:
package-lock.json:
packages.el:
pam.d:
passwd:
pictures:
pkgbuild:
.pki:
portage:
profile:
.profile:
public:
__pycache__:
pyproject.toml:
.python_history:
.pypirc:
rc.lua:
readme:
.release.toml:
requirements.txt:
robots.txt:
root:
rubydoc:
runtime.txt:
.rustup:
rustfmt.toml:
.rvm:
sass:
sbin:
scripts:
scss:
sha256sum:
shadow:
share:
.shellcheckrc:
shells:
.spacemacs:
.sqlite_history:
src:
.ssh:
static:
std:
styles:
subgid:
subuid:
sudoers:
sxhkdrc:
template:
tests:
tigrc:
timezone:
tox.ini:
.trash:
ts:
.tox:
unlicense:
url:
user-dirs.dirs:
vagrantfile:
vendor:
venv:
videos:
.viminfo:
.vimrc:
vimrc:
.vim:
vim:
.vscode:
webpack.config.js:
.wgetrc:
wgetrc:
.xauthority:
.Xauthority:
xbps.d:
xbps-src:
.xinitrc:
.xmodmap:
.Xmodmap:
xmonad.hs:
xorg.conf.d:
.xprofile:
.Xprofile:
.xresources:
.yarnrc:
yarn.lock:
zathurarc:
.zcompdump:
.zlogin:
.zlogout:
.zprofile:
.zsh_history:
.zshrc:
.trash:
.cargo:
.emacs.d:
a.out:
extension:
1:
2:
3:
4:
5:
6:
7:
7z:
8:
a:
ai:
ape:
apk:
ar:
asc:
asm:
asp:
avi:
avro:
awk:
bak:
bash_history:
bash_profile:
bashrc:
bash:
bat:
bin:
bio:
bmp:
bz2:
cc:
cfg:
cjs:
class:
cljs:
clj:
cls:
cl:
coffee:
conf:
cpp:
cp:
cshtml:
csh:
csproj:
css:
cs:
csv:
csx:
cts:
c++:
c:
cue:
cxx:
cypher:
dart:
dat:
db:
deb:
desktop:
diff:
dll:
dockerfile:
doc:
docx:
download:
ds_store:
dump:
ebook:
ebuild:
eclass:
editorconfig:
egg-info:
ejs:
elc:
elf:
elm:
el:
env:
eot:
epub:
erb:
erl:
exe:
exs:
ex:
fish:
flac:
flv:
font:
fpl:
fsi:
fs:
fsx:
gdoc:
gemfile:
gemspec:
gform:
gif:
git:
go:
gradle:
gsheet:
gslides:
guardfile:
gv:
gz:
hbs:
heic:
heif:
heix:
hh:
hpp:
hs:
html:
htm:
h:
hxx:
ico:
image:
img:
iml:
info:
in:
ini:
ipynb:
iso:
j2:
jar:
java:
jinja:
jl:
jpeg:
jpg:
jsonc:
json:
js:
jsx:
key:
ksh:
kt:
kts:
kusto:
ldb:
ld:
less:
lhs:
license:
lisp:
list:
localized:
lock:
log:
lss:
lua:
lz:
mgc:
m3u8:
m3u:
m4a:
m4v:
magnet:
malloy:
man:
markdown:
md:
mjs:
mkd:
mk:
mkv:
ml:
mli:
mll:
mly:
mobi:
mov:
mp3:
mp4:
msi:
mts:
mustache:
nix:
npmignore:
odp:
ods:
odt:
ogg:
ogv:
old:
opus:
orig:
org:
otf:
o:
part:
patch:
pdb:
pdf:
pem:
phar:
php:
pkg:
pl:
plist:
pls:
plx:
pm:
png:
pod:
pp:
ppt:
pptx:
procfile:
properties:
prql:
ps1:
psd:
pub:
slt:
pxm:
pyc:
py:
rakefile:
rar:
razor:
rb:
rdata:
rdb:
rdoc:
rds:
readme:
rlib:
rl:
rmd:
rmeta:
rpm:
rproj:
rq:
rspec_parallel:
rspec_status:
rspec:
rss:
rs:
rtf:
rubydoc:
r:
ru:
sass:
scala:
scpt:
scss:
shell:
sh:
sig:
slim:
sln:
so:
sqlite3:
sql:
srt:
styl:
stylus:
sublime-menu:
sublime-package:
sublime-project:
sublime-session:
sub:
s:
svg:
svelte:
swift:
swp:
sym:
tar:
taz:
tbz:
tbz2:
tex:
tgz:
tiff:
timestamp:
toml:
torrent:
trash:
ts:
tsx:
ttc:
ttf:
t:
twig:
txt:
unity:
unity32:
video:
vim:
vlc:
vue:
wav:
webm:
webp:
whl:
windows:
wma:
wmv:
woff2:
woff:
wpl:
xbps:
xcf:
xls:
xlsx:
xml:
xul:
xz:
yaml: y
yml: y
zip:
zig:
zshrc:
zsh-theme:
zsh:
zst:
filetype:
dir:
file:
pipe:
socket:
executable:
symlink_dir:
symlink_file:
device_char:
device_block:
special:
改変してみる
上記になることを目標として遊んでみよう.
git
手始めにgitステータスを表示してみよう.config.yaml
のblocks
にgit
を追加してみよう.config.yaml
のblocks
節の順序が表示順序に作用するため,お好みの位置に挿入してみよう.
日付
次に,日付の表示を変えてみよう.デフォのlsは冗長というか,日本人フレンドリーではないと感じたことはないだろうか? その場合はconfig.yaml
のdate
を+%m/%d %yth %T
にしてみると良いのではないだろうか.また,時間の差分が必要だと思う人がいるかもしれない.その場合はdate
をrelative
にするとよい.
他に,config.yaml
のlayout
をtree
にすると階層表示してくれる.その場合は参照する階層の上限を定めてみるとよいだろう.recursion
のenabled
をtrue
にしてdepth
を3
だか 2
だかにしてみるとどうだろうか.
アイコン
アイコンを変えてみよう.icons.yaml
で設定できる.name
filetype
extension
の3項目でアイコンを設定できる.
filetype
は,/dev/sdaやフォルダなど特殊なものを設定できる.name
は固有な名前を設定できる..bashrc
などが該当するだろう.extension
は拡張子だ..yaml
に( 一一)
を割り当ててみるとyamlを眺める顔が毎日見られるだろう.個人的なおすすめは,ジャンルごとにアイコンを設定し,それがそれとわかるアルファベットを先頭につけることだ.例えばdocxをdx📝
にしている.人によってはpowerlineなどを使って遊んでみても楽しいだろう.
カラースキーム
ここまでは表示するものを選択してきたが,ここからは表示様式を選んでみよう.カラースキームである.colors.yaml
をいじいじして遊ぼう.githubでlsd colors.yaml
で検索してみるとわかるが,このツールのカラースキームはほとんど存在しない.以下によさげなのがあったので添付しておく.ぜひ読者諸君の中にカラースキーム職人がいることを願う..
https://github.com/dna5rm/dna5rm/blob/master/.config/lsd/colors.yaml
difftastic
difftastic とは,Rustで書かれた「diffの完全上位互換」ツールである.diffコマンドには行ごとにしか比較できないという弱点がある.difftasticはそこに注目し,言語のsyntaxを考慮して差分を表示する.
残念ながら設定できる項目はまだ多くないが,alt cliツールという趣旨のもと紹介させていただく.
installation
dependencies
- cargo
mac
$ brew install difftastic
windows
linux
$ cargo install --locked difftastic
チュートリアル
gitでコンフリクトを起こしたファイルにdifft <file>
2つのファイルをdifft <fileA> <fileB>
,2つの似通ったフォルダにdifft dirA/ dirB/
してみよう.
外部ツールとの連携
difftasticはdiffの強化版であるから,git diff
の差分表示ツールとして使用すると強力なのは容易に推察できるだろう.
$ git config --global -e
でgitのconfigureを開き,以下を追記しよう.
[diff]
tool = difftastic
[difftool "difftastic"]
cmd = difft "$LOCAL" "$REMOTE"
[difftool]
prompt = false
これでgit diftool
でdifftasticが開く.
bat
bat とは,Rustで書かれた「catの人にやさしい版」ツールである.catコマンドはお手軽に扱えるが,シンタックスハイライトもないため若干見づらい.長いファイルだと結局less
に頼ることにもなる.これらの問題点を解決するのがbat
だ.
dependencies
- cargo
- [windows] Visual C++ Redistributable windows
- [windows] Chocolatey
installation
linux/macOS
$ <yarn/apt/apk/pacman/yarn/etc/etc.,> install bat
※aptやapk, pacman, yarnなどたくさんのパッケージマネージャから導入できるが,bat
コマンドは名前が衝突しやすいためbatcat
という名前に変更されることがある.困ったら,batcatでインストールされてしまう問題は,エイリアスを張って解決しよう.
※,cargo install
を推奨しない.cargo install
はLinux OSバージョンの相性に関係なくインストールする.一部のコマンドが動かなくなるのだ.
windows
choco install bat
wingetでもbatはインストールすることができるが,lessが存在しないのでページャー機能が使えない.これでbatの機能がほとんど使えないので,lessが存在するchocolatelyからインストールしよう.Git for windowsを入れるなどして,less
が存在する場合はwinget install bat
でも問題はない.
チュートリアル
色んなファイルをbat
してみよう.
表示を調整しよう
batコマンドは,設定に依ってかなり使用感が変わる.例えばファイル名を表示しなかったり,ページャーを使用したり…
まずは,bat
コマンドのデフォルト設定をいじることから始めよう.
$ bat --generate-config-file
をすることで,親切なことにコンフィグファイルを生成することができる.linuxでは~/.config/bat/config
windowsでは %appdata%\bat\config
に生成されるだろう.
生成されたコンフィグファイルを開くと,すべてコメントアウトされているのに気づくだろう.このコマンドでは,必要な部分を設定すれば残りはビルトイン設定が反映される.設定項目は,コマンドライン引数を指定すればよい.
--style="numbers,changes,grid,snip,header"
を指定することで,上記の画像と同じ見た目にできる.
カラーテーマをいじってみよう
batはユーザが非常に多く,またthemeが多く公開されている.今回は自分でカラーテーマを作成するのではなく,カラーテーマを導入することを目的としてみる.
今回インストールするカラーテーマは筆者が大好きなcatppucinからお借りさせていただく.bat
のテーマは,windowsは%appdata%\bat\theme\
,linuxは~/.config/bat/theme/
であるから,Catppuccin-macchiato.tmThemeを配置しよう.
$ bat cache --build
を実行して,キャッシュをbatに組み込もう.
configファイルのthemeにCatppuccin-macchiatoを指定すれば,デフォルトテーマの設定ができる.
あとがき
lsdはlsを人が見やすい形に成形することができる.difftasticは,diffを文法ベースで差分を解析することができる.batはファイルを人が見やすい形にハイライトすることができる.これらのツールは必ずないとこまるツール群ではないが,導入することで圧倒的に作業効率を上げてくれるものだ.これらを組み合わせることで,「エディタを開くほどでもないけど...」「わざわざエクスプローラを開くのはめんどうだが...」「結局何が違うのかは,本文を読まなければいけない」など,タスクをこなすには過剰なソフトウェアを起動することを減らせるだろう.
最近のトレンドとして複雑なツールをRust製TUIに置き換えるというものがある.今回は「結局シェルって不便じゃないか」という問題の解決の一つとして「今までよりも強力なシェルツール」を紹介した.読者の皆様方も良ければ環境ガチャガチャの喜びを楽しんでほしい.
ここまでお読み頂きありがとうございました。
references
https://github.com/sharkdp/bat/tree/master
https://difftastic.wilfred.me.uk/
https://github.com/lsd-rs/lsd/