#+TITLE: Software I use #+HTML_HEAD: Below is a list of desktop software I [[https://uses.tech/][use]] in 2025. This list excludes software I use only for professional work. I prefer software that is [[https://en.wikipedia.org/wiki/Free_and_open-source_software][free and open source]], has trustworthy non-pseudonymous maintainers, has been reviewed and packaged by the developers of multiple reputable operating systems, has effective supply chain security, has relatively few dependencies, runs daemons only if necessary, has relatively low CPU and memory usage (like [[file:my-memory-usage][this]]), has low input latency, is highly customizable (such as command-line software with many options), and uses [[https://sive.rs/plaintext][plain text files]] for configuration and data storage. My favorite sites for finding software are [[https://wiki.archlinux.org/title/List_of_applications][ArchWiki]], [[https://suckless.org/rocks/][suckless.org/\NoBreak{}rocks]], and [[https://popcon.debian.org/][Debian Popularity Contest]]. ArchWiki has comprehensive lists of software that don't include a lot of questionable programs like some large software directories do, and I like how most of the lists are split into command-line and GUI software because I usually want the former. [[https://suckless.org/rocks/][suckless.org/\NoBreak{}rocks]] has the highest signal-to-noise ratio of any software directory I've used. Debian Popularity Contest provides helpful statistics, especially the statistics for the [[https://popcon.debian.org/main/][main subsections]] sorted by the "vote" field. * Overview - [[file:#operating-system][Operating system]]: Fedora - [[file:#display-manager][Display manager]]: none - [[file:#desktop-environment][Desktop environment]]: none - [[file:#window-manager][Window manager]]: Openbox - [[file:#taskbar][Taskbar]]: none - [[file:#desktop-notification-daemon][Desktop notifications]]: Dunst - [[file:#application-launcher][Application launcher]]: none - [[file:#terminal-emulator][Terminal emulator]]: xterm - [[file:#command-shell][Command shell]]: Bash - [[file:#process-viewer][Process viewer]]: top - [[file:#posix-utilities][POSIX utilities]]: GNU coreutils, etc. - [[file:#file-manager][File manager]]: none - [[file:#file-watcher][File watcher]]: inotifywait - [[file:#file-search][File search]]: fd, ripgrep, etc. - [[file:#search-and-replace][Search and replace]]: ripgrep, Emacs - [[file:#editor][Text editor]]: Emacs - [[file:#note-taking][Note-taking]]: Emacs, Org - [[file:#spreadsheets][Spreadsheets]]: Emacs, Org - [[file:#calculator][Calculator]]: Emacs Calc - [[file:#task-management][Task management]]: Emacs, Org - [[file:#calendar][Calendar]]: Emacs, Org - [[file:#email][Email]]: Emacs, mu4e - [[file:#batch-renaming][Batch renaming]]: Emacs, Wdired - [[file:#version-control][Version control]]: Git, Emacs, Magit - [[file:#web-development][Web development]]: Emacs, etc. - [[file:#web-browser][Web browser]]: Firefox - [[file:#password-manager][Password manager]]: pass - [[file:#audio-player][Audio player]]: mpg123 - [[file:#video-player][Video player]]: mpv - [[file:#screenshots][Screenshots]]: scrot, Firefox - [[file:#image-editors][Image editors]]: GIMP, ImageMagick - [[file:#image-viewer][Image viewer]]: feh - [[file:#pdf-viewers][PDF viewers]]: zathura, Evince - [[file:#printing][Printing]]: CUPS - [[file:#backups][Backups]]: rsync, etc. - [[file:#hypervisor][Hypervisor]]: QEMU * [[file:#operating-system][Operating system]] :PROPERTIES: :CUSTOM_ID: operating-system :END: The desktop operating system I use is [[https://fedoraproject.org/][Fedora Linux]]. I like that Fedora developers [[https://fedoraproject.org/wiki/Security_Features_Matrix][prioritize security]], such as enabling [[https://github.com/SELinuxProject/selinux][SELinux]] by default and writing [[https://src.fedoraproject.org/rpms/unzip/tree/rawhide][security patches]] when necessary (patches that [[https://gitlab.archlinux.org/archlinux/packaging/packages/unzip/-/blob/main/PKGBUILD][other operating systems benefit from]], but sometimes [[https://www.reddit.com/r/archlinux/comments/4tqvpo/whats_the_consensus_on_security_with_arch_linux/d5kke7o/][months later]]). [[https://packages.fedoraproject.org/][Fedora's package repository]] has recent versions of nearly all of the software I want, which allows me to avoid installing software from source to the extent I did in the past and avoid less secure packages I might be tempted to install if I were to use a different operating system, such as [[https://www.reddit.com/r/archlinux/comments/3yiq4s/is_the_aur_safe_to_use/cydr9ss/][AUR packages]], [[https://news.ycombinator.com/item?id=41131320][Homebrew packages]], [[https://news.ycombinator.com/item?id=34105784][Nix packages]], [[https://help.ubuntu.com/stable/ubuntu-help/addremove-ppa.html.en#:~:text=Third-party%20software%20repositories%20are%20not%20checked%20for%20security][PPA packages]], [[https://help.ubuntu.com/community/Repositories#Universe][Ubuntu universe packages]], [[https://backports.debian.org/FAQ/#:~:text=Is%20there%20security%20support%20for%20packages%20from%20backports.debian.org?][Debian backports]], and [[https://docs.flathub.org/docs/for-users/verification/][unverified Flatpaks]]. I use the [[https://alt.fedoraproject.org/][Fedora Everything installer]] to perform minimal installations of Fedora that exclude a desktop environment and other GUI software. Afterward, I configure my system and install packages using an idempotent system configuration script I wrote named /[[../scripts/configure][configure]]/, which I run daily. * [[file:#display-manager][Display manager]] :PROPERTIES: :CUSTOM_ID: display-manager :END: I don't use a display manager (a.k.a. login manager) because I think they're unnecessary. Instead, after my system boots, I log in via the [[https://en.wikipedia.org/wiki/Linux_console][Linux console]] and run [[https://gitlab.freedesktop.org/xorg/app/xinit][startx]] to start the window manager specified in [[../dotfiles/.xinitrc][my xinit config]]. * [[file:#desktop-environment][Desktop environment]] :PROPERTIES: :CUSTOM_ID: desktop-environment :END: I don't use a desktop environment for a few reasons. First, desktop environments include a lot of GUI software, while I mostly use command-line software and [[file:#editor][Emacs]]. Second, I enjoy seeking out optimal software, so I'm not interested in collections of GUI software chosen by other people. Lastly, the desktop environments I've evaluated have too many daemons; for example, my PC with Fedora 42 and no desktop environment had only [[file:my-processes][XX userspace processes]] after running startx with [[../dotfiles/.xinitrc][my xinit config]], while a virtual machine I created with Fedora 42 and [[https://www.gnome.org/][GNOME]] had a whopping [[file:gnome-processes][114 userspace processes]] by default. * [[file:#window-manager][Window manager]] :PROPERTIES: :CUSTOM_ID: window-manager :END: I use an [[https://www.x.org/][X11]] window manager named [[http://openbox.org/][Openbox]]. The last time Openbox had a stable release was in [[https://github.com/Mikachu/openbox/tags][2015]], but it does everything I need it to do, it works perfectly, and it's highly configurable (see [[../dotfiles/.config/openbox/rc.xml][my Openbox config]]). Openbox is a stacking window manager. I prefer stacking window managers to tiling window managers because I usually have only three GUI apps running --- a terminal emulator, text editor, and web browser --- and all three benefit from being maximized to full screen. For example, I like having a wide tab bar in my web browser, and I frequently use my terminal emulator and text editor to display files with long lines, such as log files and [[file:#spreadsheets][plain text spreadsheets]]. I haven't fully evaluated any [[https://wayland.freedesktop.org/][Wayland]] compositors that support stacking window management (such as [[https://labwc.github.io/][labwc]], [[https://wayfire.org/][Wayfire]], and [[https://hikari.acmelabs.space/][hikari]]) because I'm so satisfied with Openbox. * [[file:#taskbar][Taskbar]] :PROPERTIES: :CUSTOM_ID: taskbar :END: I don't use a taskbar (a.k.a. status bar) because I think they're unnecessary and a poor use of screen real estate. When I want to view a list of open windows, I do so by pressing Alt+Tab, which is bound to [[http://openbox.org/help/Actions#NextWindow][Openbox's window switcher]] via [[../dotfiles/.config/openbox/rc.xml][my Openbox config]]. When I want to view other information that is commonly displayed on taskbars, I use a key binding specified in [[../dotfiles/.config/openbox/rc.xml][my Openbox config]] to run my Bash script named /[[../scripts/status][status]]/, which displays the time, date, CPU usage, and memory usage as a desktop notification. * [[file:#desktop-notification-daemon][Desktop notifications]] :PROPERTIES: :CUSTOM_ID: desktop-notification-daemon :END: # CUSTOM_ID is `desktop-notification-daemon`, not `desktop-notifications`, # because Fanboy's Annoyance List blocks the latter: # https://github.com/easylist/easylist/blob/master/fanboy-addon/fanboy_notifications_general_hide.txt I use a desktop notification daemon named [[https://dunst-project.org/][Dunst]]. It works great and it's adequately configurable (see [[../dotfiles/.config/dunst/dunstrc][my Dunst config]]). * [[file:#application-launcher][Application launcher]] :PROPERTIES: :CUSTOM_ID: application-launcher :END: I don't use an application launcher because I think they're unnecessary. Instead, I start GUI apps using key bindings specified in [[../dotfiles/.config/openbox/rc.xml][my Openbox config]] and using aliases specified in [[../dotfiles/.bashrc][my Bash config]]. * [[file:#terminal-emulator][Terminal emulator]] :PROPERTIES: :CUSTOM_ID: terminal-emulator :END: The terminal emulator I use is [[https://invisible-island.net/xterm/][xterm]]. I like that xterm has lower input latency than other terminal emulators (see benchmarks [[https://beuke.org/terminal-latency/][here]], [[https://tomscii.sig7.se/2021/01/Typing-latency-of-Zutty][here]], and [[https://lwn.net/Articles/751763/][here]]). Also, I like that xterm has low memory usage because I always have multiple instances running. I prefer to have multiple terminal windows rather than use a tabbed terminal emulator because I usually have only a few apps running and it's quicker for me to Alt+Tab to a specific terminal window than it is to Alt+Tab to a tabbed terminal emulator and select a specific tab. I configure xterm using [[../dotfiles/.config/Xresources][my X resources]], which are loaded by [[https://gitlab.freedesktop.org/xorg/app/xrdb][xrdb]] via [[../dotfiles/.xinitrc][my xinit config]]. If I were to switch from Openbox to a Wayland compositor, I'd probably replace xterm with [[https://codeberg.org/dnkl/foot][foot]]. * [[file:#command-shell][Command shell]] :PROPERTIES: :CUSTOM_ID: command-shell :END: The command shell I use is [[https://www.gnu.org/software/bash/][Bash]]. The main reason I use Bash instead of an alternative like [[https://www.zsh.org/][Zsh]] or [[https://fishshell.com/][Fish]] is that there is an excellent linter for shell scripts named [[https://www.shellcheck.net/][ShellCheck]] that supports Bash scripts but [[https://github.com/koalaman/shellcheck/issues/809][not Zsh scripts]] and [[https://github.com/koalaman/shellcheck/issues/209][not Fish scripts]]. I would hate to write [[../scripts/][my shell scripts]] without ShellCheck (or using a more verbose language like Python), and I dislike having to mentally compartmentalize the features of multiple shells when switching between one shell for interactive use and a different shell for scripting. A second reason I don't use Zsh or Fish is that many people seem to prefer those shells for their history and completion functionality, and I don't need those features. For example, I don't need advanced history features because I save useful commands to a text file named [[../dotfiles/.local/share/selectcmd.dat][selectcmd.dat]] from which I select commands using my Bash function named _selectcmd (defined in [[../dotfiles/.bashrc][my Bash config]]), which I execute via a [[https://tiswww.case.edu/php/chet/readline/rltop.html][Readline]] key binding. Also, I don't need advanced features for completing command options because I select option-heavy commands using _selectcmd. Lastly, I don't need advanced features for completing paths because I select most paths using a fuzzy finder named [[https://github.com/junegunn/fzf][fzf]]. Another reason I use Bash is that it's adequately configurable (see [[../dotfiles/.bashrc][my Bash config]]). In comparison, [[https://fishshell.com/docs/current/design.html#configurability-is-the-root-of-all-evil][Fish's docs state that configurability is the root of all evil]], and [[https://github.com/fish-shell/fish-shell/issues/1363][Fish's autosuggestions couldn't be disabled]] until [[https://github.com/fish-shell/fish-shell/pull/8376][2021]], over nine years after they were [[https://github.com/fish-shell/fish-shell/commit/067dff84891b2c0fc45c5e1bbe1e6f04fdd6040e][introduced]]. * [[file:#process-viewer][Process viewer]] :PROPERTIES: :CUSTOM_ID: process-viewer :END: The process viewer I use is [[https://gitlab.com/procps-ng/procps][procps /top/]] (not to be confused with the [[https://web.archive.org/web/20170521033224/https://www.unixtop.org/][original /top/]] by [[https://csprofiles.rice.edu/2019/09/05/lefebvre/][William LeFebvre]] or [[https://en.wikipedia.org/wiki/Top_(software)#Implementations][other implementations]]). A popular alternative to /top/ is [[https://htop.dev/][htop]], which I used for several years mostly because it seemed that everyone was using it. For example, [[https://formulae.brew.sh/formula/htop][htop is used by macOS users]] and [[https://formulae.brew.sh/formula/procps][procps /top/ isn't]]. I stopped using htop because /top/ does everything I need it to do, it's installed by default on Fedora, and it's lightweight while being adequately configurable. * [[file:#posix-utilities][POSIX utilities]] :PROPERTIES: :CUSTOM_ID: posix-utilities :END: I use implementations of [[https://pubs.opengroup.org/onlinepubs/9799919799/idx/utilities.html][POSIX utilities]] that are installed by default on Fedora, including [[https://www.gnu.org/software/coreutils/][GNU coreutils]] and [[https://www.gnu.org/software/bash/manual/html_node/Builtin-Index.html][Bash builtins]]. Occasionally I extend the functionality of POSIX utilities by writing Bash scripts, such as /[[../scripts/relocate][relocate]]/ and /[[../scripts/remove][remove]]/. Sometimes I use alternatives to POSIX utilities (see [[file:#file-search][file search]]). I don't use alternatives whose primary purpose seems to be outputting more colors (such as /[[https://github.com/sharkdp/bat][bat]]/, [[https://eza.rocks/][eza]], and [[https://github.com/lsd-rs/lsd][LSD]]) because I prefer [[https://groups.google.com/g/golang-nuts/c/hJHCAaiL0so/m/kG3BHV6QFfIJ][fewer colors]]. * [[file:#file-manager][File manager]] :PROPERTIES: :CUSTOM_ID: file-manager :END: I don't use a file manager because I think they're unnecessary. Instead, I manage files using command-line tools. * [[file:#file-watcher][File watcher]] :PROPERTIES: :CUSTOM_ID: file-watcher :END: I use a file watcher named [[https://man.archlinux.org/man/inotifywait.1][inotifywait]], which is from a set of [[https://docs.kernel.org/filesystems/inotify.html][inotify]]-based utilities named [[https://github.com/inotify-tools/inotify-tools][inotify-tools]]. I like that inotifywait can execute shell functions (not just programs) in response to file changes, which is a feature that [[https://github.com/eradman/entr/issues/6][some file watchers lack]]. * [[file:#file-search][File search]] :PROPERTIES: :CUSTOM_ID: file-search :END: When I write a Bash script that needs to find one or more files, and performance isn't a factor, I use [[https://www.gnu.org/software/findutils/][GNU /find/]] or [[https://www.gnu.org/software/grep/][GNU grep]] because I try to use standard utilities as much as possible when writing Bash scripts. When I search for files interactively, or when performance is otherwise a factor, I use [[https://github.com/sharkdp/fd][fd]] or [[https://github.com/BurntSushi/ripgrep][ripgrep]] because they're faster than GNU /find/ and GNU grep (see benchmarks in [[https://github.com/sharkdp/fd#benchmark][fd's docs]] and [[https://github.com/BurntSushi/ripgrep#quick-examples-comparing-tools][ripgrep's docs]]). Another benefit of fd and ripgrep is that they both exclude files listed in .ignore files (see [[https://github.com/sharkdp/fd#excluding-specific-files-or-directories][fd's docs]] and [[https://github.com/BurntSushi/ripgrep/blob/master/GUIDE.md#automatic-filtering][ripgrep's docs]]). When I use fd interactively, I mostly use it via a fuzzy finder named [[https://github.com/junegunn/fzf][fzf]]. And when I use fzf in [[file:#editor][Emacs]], I do so using a package named [[https://github.com/bling/fzf.el][fzf.el]]. When I search for PDFs, I sometimes use [[https://pdfgrep.org/][pdfgrep]]. * [[file:#search-and-replace][Search and replace]] :PROPERTIES: :CUSTOM_ID: search-and-replace :END: When I need to find and replace text in multiple files, I use [[https://github.com/BurntSushi/ripgrep][ripgrep]] via my Bash script named /[[../scripts/replace][replace]]/. My script previously used [[https://www.gnu.org/software/grep/][GNU grep]] for searching and [[https://www.gnu.org/software/sed/][GNU sed]] for replacing. I switched to ripgrep because [[https://github.com/BurntSushi/ripgrep#quick-examples-comparing-tools][GNU grep is slower]], [[https://www.gnu.org/software/sed/manual/html_node/Multiline-techniques.html][GNU sed's multiline replacements]] are less ergonomic, and [[https://www.gnu.org/software/sed/manual/html_node/Regexp-Addresses.html][GNU sed's regular expressions require more escaping]]. When I need to find and replace text in only one file, I use [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Replace.html][Emacs]]. * [[file:#editor][Text editor]] :PROPERTIES: :CUSTOM_ID: editor :END: # CUSTOM_ID is `editor`, not `text-editor`, because the `manage` script removes # IDs that start with `text`. The text editor I use is [[https://www.gnu.org/software/emacs/][Emacs]]. It's my all-time favorite app. I use Emacs for note-taking, spreadsheets, calculations, to-do lists, calendar, email, batch renaming, version control, static site generation, programming, and, most importantly, tweaking [[../dotfiles/][my Emacs config]]. Some people assume the only reason Emacs users choose Emacs for non-programming activitites is because we already use it for programming. But as I mention in the next section, I started using Emacs for note-taking, not programming. * [[file:#note-taking][Note-taking]] :PROPERTIES: :CUSTOM_ID: note-taking :END: The software I use for note-taking is Emacs with an Emacs package named [[https://orgmode.org/][Org]] (a.k.a. Org mode). Org files are text files written using a [[https://orgmode.org/features.html][feature-rich lightweight markup language]] that is similar to Markdown but much more powerful. For example, as I mention in the next section, Org supports plain text spreadsheets, which is an awesome feature. My dissatisfaction with other note-taking solutions is what caused me to start using Emacs and Org years ago. I now have several thousand Org files (such as @@html:uses/index.org@@). * [[file:#spreadsheets][Spreadsheets]] :PROPERTIES: :CUSTOM_ID: spreadsheets :END: The software I use for spreadsheets is Emacs with [[https://orgmode.org/][Org]]. [[https://orgmode.org/manual/The-Spreadsheet.html][Org spreadsheets]] are plain text, and as a result, they lack many features of other spreadsheet formats. But my personal spreadsheets include small data sets on which I perform basic calculations, and Org is perfect for such spreadsheets. I like that Org allows me to insert spreadsheets into my Org files that also include my notes. Before I started using Org, I had to keep my notes and spreadsheets in separate files, edit those files using different apps, and include refererences to spreadsheet files in my notes. * [[file:#calculator][Calculator]] :PROPERTIES: :CUSTOM_ID: calculator :END: The calculator I use is an Emacs package named [[https://www.gnu.org/software/emacs/manual/calc.html][Calc]] (not to be confused with [[http://www.isthe.com/chongo/tech/comp/calc/][calc]] by [[https://en.wikipedia.org/wiki/Landon_Curt_Noll][Landon Curt Noll]]). * [[file:#task-management][Task management]] :PROPERTIES: :CUSTOM_ID: task-management :END: The software I use for task management is Emacs with [[https://orgmode.org/][Org]]. [[https://orgmode.org/manual/TODO-Items.html][Org to-do lists]] are plain text, and yet Org supports every task management feature I want. One feature I use a lot is the [[https://orgmode.org/manual/Repeated-tasks.html][.+]] repeater, which repeats a task a specified amount of time after it was completed (not scheduled to be completed). Surprisingly, very few of the task management apps I've evaluated have this feature. I use an Emacs package named [[https://github.com/akhramov/org-wild-notifier.el][org-wild-notifier]] to get task notifications. I prefer org-wild-notifier to the similar package named [[https://github.com/spegoraro/org-alert][org-alert]] because the latter [[https://github.com/spegoraro/org-alert/issues/34][sends notifications nonstop for day-wide tasks]] until such tasks are marked as completed, which is crazy. * [[file:#calendar][Calendar]] :PROPERTIES: :CUSTOM_ID: calendar :END: The software I use for my calendar is [[https://orgmode.org/][Org]]. It collects the scheduled tasks from the to-do lists in a user's Org files and displays the scheduled tasks in an [[https://orgmode.org/manual/Agenda-Views.html][agenda view]] that is like a calendar. I love using Org for my calendar and to-do lists because it allows me to manage my scheduled and unscheduled tasks together in the same files using the same software. * [[file:#email][Email]] :PROPERTIES: :CUSTOM_ID: email :END: The email client I use is an Emacs package named [[https://www.djcbsoftware.nl/code/mu/][mu4e]]. Like most Emacs packages, mu4e is satisfyingly configurable (see [[../dotfiles/.config/emacs/lisp/init-mu4e.el][my mu4e config]]). Another benefit of mu4e is that it uses [[https://en.wikipedia.org/wiki/Maildir][maildir]], my favorite email storage format. Each message in a maildir directory is stored in its own text file, and I prefer this because my favorite solution for local [[file:#backups][backups]] is rsync with hard links for deduplication, which doesn't work well with large, frequently modified files, such as [[https://en.wikipedia.org/wiki/Mbox][mbox]] files. I send [[https://useplaintext.email/][plain text emails]], and most email clients insert newlines into plain text emails before sending them to prevent lines from being longer than [[https://datatracker.ietf.org/doc/html/rfc5322#section-2.1.1][78 characters]]. Such newlines cause [[https://www.arp242.net/email-wrapping.html][undesirable line wrapping]] on screens that are too narrow for 78-character lines. One solution is [[https://joeclark.org/ffaq.html][format=flowed]] (see [[https://datatracker.ietf.org/doc/html/rfc3676][RFC 3676]]). Unfortunately, [[https://www.fastmail.com/blog/format-flowed/][format=flowed is supported by only a few email clients]]. The solution I use is to configure mu4e to allow lines in emails to be up to [[https://datatracker.ietf.org/doc/html/rfc5322#section-2.1.1][998 characters]], which is longer than any paragraph I would write. * [[file:#batch-renaming][Batch renaming]] :PROPERTIES: :CUSTOM_ID: batch-renaming :END: The software I use for batch file renaming is Emacs with a mode named [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Wdired.html][Wdired]], which I strongly prefer to the dedicated batch renamers I've used. * [[file:#version-control][Version control]] :PROPERTIES: :CUSTOM_ID: version-control :END: I use [[https://git-scm.com/][Git]] via an Emacs package named [[https://magit.vc/][Magit]]. I'm a command-line enthusiast, but I prefer Magit to the Git CLI because it's much easier to [[https://magit.vc/manual/magit/Staging-and-Unstaging.html][stage and unstage hunks using Magit]]. I wasn't satisfied with Magit's performance out of the box, but it's worked great after I added [[https://magit.vc/manual/magit/Performance.html][performance-related settings]] to [[../dotfiles/.config/emacs/lisp/init-magit.el][my Magit config]]. * [[file:#web-development][Web development]] :PROPERTIES: :CUSTOM_ID: web-development :END: I create personal web pages using [[https://orgmode.org/manual/HTML-Export.html][Org files]] (such as @@html:uses/index.org@@), Bash scripts (such as [[../scripts/mkindex][mkindex]]), and plain old HTML files. I format my HTML and CSS using a Node.js package named [[https://prettier.io/][Prettier]] via an Emacs package named [[https://github.com/lassik/emacs-format-all-the-code][format-all]] that integrates code formatters into Emacs. I like that [[https://www.npmjs.com/package/prettier?activeTab=dependencies][Prettier has zero dependencies]], unlike nearly every other Node.js package I've used. I lint my CSS using a Node.js package named [[https://stylelint.io/][Stylelint]] via an Emacs package named [[https://www.flycheck.org/][Flycheck]] that integrates linters into Emacs. I don't lint my HTML in Emacs, but I do validate it during the build process using a Java program named [[https://validator.github.io/validator/][Nu HTML Checker]] (a.k.a. v.Nu and [[https://repology.org/project/vnu/versions][vnu]]), which is the only HTML5 validator recommended by the [[https://whatwg.org/validator/][WHATWG]] and [[https://validator.w3.org/docs/install.html][W3C]]. Nu HTML Checker supports CSS too, but I use it only for HTML because it doesn't recognize certain valid CSS, such as [[https://github.com/validator/validator/issues/1634][nested CSS]] and the [[https://github.com/validator/validator/issues/1725][oklch() function]]. I minify my HTML using a Go program named /[[https://github.com/tdewolff/minify/tree/master/cmd/minify][minify]]/, and I minify my CSS using a Node.js package named [[https://lightningcss.dev/][Lightning CSS]]. /minify/ supports CSS too, but not as well as Lightning CSS does. For example, [[https://github.com/tdewolff/minify/issues/136][/minify/ doesn't concatenate imported stylesheets]] like [[https://lightningcss.dev/bundling.html#%40import][Lightning CSS does]], and [[https://github.com/tdewolff/minify/issues/602#issuecomment-1704864515][/minify/ doesn't support nested CSS]]. But /minify/ is great for HTML, and I prefer it to other HTML minifiers I've used. For example, the Rust program [[https://github.com/wilsonzlin/minify-html][minify-html]] can [[https://github.com/wilsonzlin/minify-html/issues?q=is:issue+invalid][produce invalid HTML]], and the Node.js package [[https://github.com/terser/html-minifier-terser][html-minifier-terser]] has most of its features disabled by default, which required me to specify a whopping 19 options in every build script in which I used it. I deploy personal web pages to [[https://pages.cloudflare.com/][Cloudflare Pages]]. Cloudflare has a command-line tool named [[https://github.com/cloudflare/workers-sdk/tree/main/packages/wrangler][Wrangler]] that provides a dev server for [[https://developers.cloudflare.com/pages/functions/local-development/][local development]]. Unfortunately, the dev server can use hundreds of megabytes of memory because Wrangler is written in TypeScript. Instead of using Wrangler, I use a web server written in C named [[https://unix4lyfe.org/darkhttpd/][darkhttpd]], which is very lightweight and meets my dev server requirements (such as caching being disabled) with only a few command-line arguments, not a whole config file like most web servers I've used. * [[file:#web-browser][Web browser]] :PROPERTIES: :CUSTOM_ID: web-browser :END: The main web browser I use is [[https://www.mozilla.org/en-US/firefox/][Firefox]]. It has great privacy features, such as [[https://support.mozilla.org/en-US/kb/enhanced-tracking-protection-firefox-desktop][Strict Enhanced Tracking Protection]]; it supports [[https://ublockorigin.com/][uBlock Origin]] (not the inferior [[https://github.com/uBlockOrigin/uBOL-home][uBlock Origin Lite]]); and it's more customizable than other browsers, including [[https://www.google.com/chrome/][Chrome]] and [[https://www.chromium.org/][Chromium]], which don't even allow users to [[https://issues.chromium.org/issues/40426341][remove the "Close tab" button]]. I configure Firefox primarily via the files [[../dotfiles/.mozilla/firefox/j8lriz5r.4/user.js][user.js]], [[../dotfiles/.mozilla/firefox/j8lriz5r.4/chrome/userChrome.css][userChrome.css]], and [[../dotfiles/.mozilla/firefox/j8lriz5r.4/chrome/userContent.css][userContent.css]]. I configure Firefox via its GUI only when necessary. I've used dozens of browser extensions over the years, including some I thought were essential, such as [[https://github.com/piroor/treestyletab][Tree Style Tab]], [[https://tab-session-manager.sienori.com/][Tab Session Manager]], and [[https://github.com/rNeomy/auto-tab-discard][Auto Tab Discard]]. But I now try to minimize the number of extensions I use to avoid issues relating to security, privacy, and performance. The only extension I currently use is [[https://ublockorigin.com/][uBlock Origin]]. * [[file:#password-manager][Password manager]] :PROPERTIES: :CUSTOM_ID: password-manager :END: I use a command-line password manager named /[[https://www.passwordstore.org/][pass]]/. It stores passwords in text files that are encrypted by [[https://gnupg.org/][GnuPG]]. I run /pass/ via my Bash scripts [[../scripts/pass-generate][pass-generate]], [[../scripts/pass-show][pass-show]], [[../scripts/pass-edit][pass-edit]], and [[../scripts/pass-use][pass-use]]. * [[file:#audio-player][Audio player]] :PROPERTIES: :CUSTOM_ID: audio-player :END: I rarely listen to music because it hinders my concentration, but I do listen to [[https://boxfansound.com/][my favorite white noise MP3]] using a command-line audio player named [[https://mpg123.org/][mpg123]]. I start and stop mpg123 using my Bash script named /[[../scripts/toggle][toggle]]/, which I run via a key binding specified in [[../dotfiles/.config/openbox/rc.xml][my Openbox config]]. * [[file:#video-player][Video player]] :PROPERTIES: :CUSTOM_ID: video-player :END: I rarely download video files, but when I do, I play them using a command-line video player named [[https://mpv.io/][mpv]]. I like that [[https://mpv.io/manual/master/#on-screen-controller][mpv has a seekbar]], unlike other command-line video players I've used, such as [[https://mplayerhq.hu/][MPlayer]] and [[https://ffmpeg.org/ffplay.html][ffplay]]. * [[file:#screenshots][Screenshots]] :PROPERTIES: :CUSTOM_ID: screenshots :END: The screenshot software I use includes [[https://support.mozilla.org/en-US/kb/take-screenshots-firefox][Firefox's screenshot feature]] and a command-line tool named [[https://github.com/resurrecting-open-source-projects/scrot][scrot]]. * [[file:#image-editors][Image editors]] :PROPERTIES: :CUSTOM_ID: image-editors :END: The image editors I use are [[https://www.gimp.org/][GIMP]] and [[https://imagemagick.org/][ImageMagick]]. Most of my image editing involves prototyping modifications to photos and screenshots in GIMP and then reimplementing and finalizing my changes using ImageMagick commands in Bash scripts. Using scripts for image editing allows me to easily tweak an image later --- sometimes years later --- by quickly editing and rerunning the associated script. * [[file:#image-viewer][Image viewer]] :PROPERTIES: :CUSTOM_ID: image-viewer :END: I tested 27 image viewers that support Linux and my favorite is [[https://feh.finalrewind.org/][feh]]. I like that feh can bind keys to shell commands, it supports XCF files, it has low memory usage, and it uses plain text config files (see [[../dotfiles/][my feh config]]). * [[file:#pdf-viewers][PDF viewers]] :PROPERTIES: :CUSTOM_ID: pdf-viewers :END: I read PDFs using [[https://pwmt.org/projects/zathura/][zathura]]. I like that zathura makes maximum use of screen real estate by not having a menu bar or toolbar; it remembers the last viewed page of each PDF, unlike a surprising number of PDF viewers I've used; and it uses a plain text config file (see [[../dotfiles/.config/zathura/zathurarc][my zathura config]]). I use a PDF viewer named [[https://apps.gnome.org/Evince/][Evince]] to search in PDFs because it provides a clickable list of search results, a great feature that's missing in zathura and most PDF viewers I've used. I don't use Evince for reading because in order for it to remember the last viewed page of each PDF, it needs [[https://gitlab.gnome.org/GNOME/gvfs][GVfs]], which I avoid installing because it requires multiple daemons. An Evince fork named [[https://apps.gnome.org/Papers/][Papers]] is planned to replace Evince, but I currently prefer Evince because Papers uses 100-200% more memory and its search results have excessive line height resulting in 34% fewer results being displayed before scrolling. I wanted to use an Emacs-based PDF viewer named [[https://github.com/vedang/pdf-tools][pdf-tools]] because I love using Emacs, but memory usage was [[https://github.com/politza/pdf-tools/issues/177][far]] [[https://github.com/politza/pdf-tools/issues/385][too]] [[https://old.reddit.com/r/emacs/comments/8uu7hb/question_pdftools_use_alot_of_ram/][high]]. * [[file:#printing][Printing]] :PROPERTIES: :CUSTOM_ID: printing :END: [[https://openprinting.github.io/cups/][CUPS]] * [[file:#backups][Backups]] :PROPERTIES: :CUSTOM_ID: backups :END: [[https://rsync.samba.org/][rsync]] with hard links for file deduplication [[https://www.gnu.org/software/xorriso/][xorriso]] * [[file:#hypervisor][Hypervisor]] :PROPERTIES: :CUSTOM_ID: hypervisor :END: I use a command-line hypervisor named [[https://www.qemu.org/][QEMU]]. I use QEMU to play with operation systems; evaluate programs and review their dependencies on a clean system; and test [[../scripts/configure][my system configuration script]].