├── .dir-locals.el ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Dockerfile ├── LICENSE.md ├── Makefile ├── README.md ├── doc ├── git.md ├── tmux.md ├── troubleshooting.md └── zsh.md ├── emacs ├── early-init.el ├── init.el ├── radian.el ├── use-package-keywords.md └── versions.el ├── git ├── .gitconfig └── .gitexclude ├── scripts ├── build.bash ├── byte-compile.bash ├── check-line-length.bash ├── checkdoc.bash ├── docker-install.bash ├── docker.bash ├── print_env.py ├── symlink-dotfiles.bash └── validate-patches.bash ├── shell ├── shared │ └── .profile └── zsh │ ├── .zprofile │ ├── .zshenv │ └── .zshrc └── tmux └── .tmux.conf /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ((nil 2 | . ((compile-command 3 | . "make -sC \"$(git rev-parse --show-toplevel)\" lint")))) 4 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [master, develop] 5 | pull_request: {} 6 | jobs: 7 | ci: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | emacs_version: [27, 28, 29, 30] 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | - name: CI 16 | env: 17 | VERSION: ${{ matrix.emacs_version }} 18 | run: >- 19 | make docker CMD="make -k link lint" 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /emacs/radian.elc 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VERSION 2 | FROM silex/emacs:$VERSION 3 | 4 | ARG UID 5 | 6 | COPY scripts/docker-install.bash /tmp/ 7 | RUN /tmp/docker-install.bash "$UID" 8 | 9 | USER $UID 10 | WORKDIR /home/docker/radian 11 | 12 | # If we don't do this, then the directory gets created in the 13 | # container filesystem with root ownership :/ 14 | RUN mkdir -p "$HOME/.emacs.d/straight/repos" 15 | 16 | CMD bash 17 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2016–2022 [Radian LLC](https://radian.codes) and 4 | contributors 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := bash 2 | 3 | VERSION ?= 4 | CMD ?= 5 | 6 | longlines_files := $(shell find . -name .git -prune -o -print) 7 | for_checkindent := $(shell find . -name .git -prune -o -name '*.el' -print) 8 | 9 | .PHONY: help 10 | help: ## Show this message 11 | @echo "usage:" >&2 12 | @grep -h "[#]# " $(MAKEFILE_LIST) | \ 13 | sed 's/^/ make /' | \ 14 | sed 's/:[^#]*[#]# /|/' | \ 15 | sed 's/%/LANG/' | \ 16 | column -t -s'|' >&2 17 | 18 | .PHONY: link 19 | link: ## Symlink dotfiles into home directory 20 | @scripts/symlink-dotfiles.bash 21 | 22 | .PHONY: build 23 | build: ## Make sure straight.el dependencies are built 24 | @scripts/build.bash 25 | 26 | .PHONY: compile 27 | compile: ## Byte-compile radian.el 28 | @scripts/byte-compile.bash 29 | 30 | .PHONY: checkdoc 31 | checkdoc: ## Check docstring style in radian.el 32 | @scripts/checkdoc.bash 33 | 34 | .PHONY: longlines 35 | longlines: ## Check for long lines 36 | @scripts/check-line-length.bash 37 | 38 | .PHONY: checkindent 39 | checkindent: ## Ensure that indentation is correct 40 | @tmpdir="$$(mktemp -d)"; for file in $(for_checkindent); do \ 41 | emacs -Q --batch \ 42 | --eval "(setq inhibit-message t)" \ 43 | --eval "(progn \ 44 | (setq straight-safe-mode t) \ 45 | (load (expand-file-name \"init.el\" \ 46 | user-emacs-directory) nil t))" \ 47 | --eval "(find-file \"$$file\")" \ 48 | --eval "(indent-region (point-min) (point-max))" \ 49 | --eval "(write-file \"$$tmpdir/indented.el\")"; \ 50 | (diff <(cat "$$file" | nl -v1 -ba | \ 51 | sed "s/\t/: /" | sed "s|^ *|$$file:|") \ 52 | <(cat "$$tmpdir/indented.el" | nl -v1 -ba | \ 53 | sed "s/\t/: /" | sed "s|^ *|$$file:|") ) \ 54 | | grep -F ">" | grep -o "[a-z].*" | grep . && exit 1 || true; \ 55 | done 56 | 57 | .PHONY: validate 58 | validate: ## Validate el-patches 59 | @scripts/validate-patches.bash 60 | 61 | .PHONY: lint 62 | lint: build compile validate checkdoc longlines checkindent ## Run all linters 63 | 64 | .PHONY: clean 65 | clean: ## Remove build artifacts 66 | @rm -f emacs/radian.elc 67 | 68 | .PHONY: docker 69 | docker: ## Start a Docker shell; e.g. make docker VERSION=27 70 | @scripts/docker.bash "$(VERSION)" "$(CMD)" 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Radian**: dotfiles that marry elegance and practicality. 2 | 3 | ## Summary 4 | 5 | These dotfiles attempt to achieve the following goals: 6 | 7 | * aggressively using best practices, or creating them if none exist 8 | already 9 | * extensively documenting and commenting all code 10 | * remaining as simple as possible while maximizing usability (in 11 | particular, not rebinding keys unnecessarily) 12 | * supporting local configuration without the need to fork this 13 | repository (my local Emacs configuration is almost 750 lines of 14 | code) 15 | 16 | If you are a fan of my Emacs packages (such as 17 | [`straight.el`][straight.el], [`el-patch`][el-patch], ~[Selectrum]~ 18 | (replaced by [Vertico]), [CTRLF], [`prescient.el`][prescient.el], 19 | [Apheleia], [Blackout]) then you will find all of them configured 20 | here. 21 | 22 | Note that there is a `main` branch which is not updated as frequently. 23 | You may be interested in running this branch if you desire more 24 | stability. 25 | 26 | ## Software configured, features 27 | 28 | * [Emacs] (**minimum version supported: 27.1**) 29 | * Next-generation package manager, [`straight.el`][straight.el] 30 | * Clean and DRY package customizations using 31 | [`use-package`][use-package] 32 | * Simpler and less buggy (than [Ivy], [Counsel], [Helm]) file and 33 | command selection using [Vertico] 34 | * More robust and streamlined single-buffer text search (than 35 | [Isearch], [Swiper]) using [CTRLF] 36 | * Sorting by [frecency] and usage on all commands using 37 | [`prescient.el`][prescient.el] 38 | * IDE features for expanding library of programming languages with 39 | [LSP] via [`lsp-mode`][lsp-mode] (Bash, C, C++, CSS, [Flow], [Go], 40 | [Haskell], HTML, [JavaScript], [TypeScript], [JSX]/[TSX], [Flow], 41 | [LaTeX], [Python] with [Poetry] and [Pipenv] virtualenvs 42 | autodetected) 43 | * Automatic asynchronous code reformatting without moving point 44 | using [Black], [Brittany], [Gofmt], and [Prettier] via [Apheleia] 45 | * Informative but minimal mode-line showing file modification 46 | status, buffer name, point position, and active modes (with 47 | optional right-alignment support) 48 | * Extremely clean mode lighters with prettier names thanks to 49 | [Blackout] 50 | * *All* the needless messages have been suppressed; no errors mean 51 | no messages 52 | * Aggressive startup optimization: as fast as 0.33s for a fully 53 | configured graphical frame (by aggressive lazy-loading of 54 | everything; using [`el-patch`][el-patch] to lazy-load packages 55 | that weren't designed to be lazy-loaded; by extensive use of idle 56 | timers; by disabling of heavy autoloads; by asynchronous 57 | byte-compilation of the init-file in a subprocess on successful 58 | init, with the local init-file macroexpanded and embedded directly 59 | into Radian during compilation; and by running all customizations 60 | before the first graphical frame is initialized) 61 | * Aggressively consistent coding style and documentation (init-file 62 | is 37% comments and docstrings), including heavy use of macros to 63 | automate and foolproof common operations 64 | * Future-proof customizations using [`el-patch`][el-patch] 65 | * Delightful color scheme that works in the terminal ([Zerodark]) 66 | * Clipboard, mouse, and PATH integration for macOS and Linux 67 | * Automatic creation and interactive removal of parent directories 68 | when finding and renaming files 69 | * Automatically clone Emacs source when needed by `find-function` 70 | * Extensible system for defining mnemonic key sequences to jump to 71 | dotfiles 72 | * Choose to kill, restart, or spawn new Emacs on `C-x C-c`, based 73 | partly on [`restart-emacs`][restart-emacs] 74 | * Automatic insertion of whitespace and indentation when pressing 75 | newline after inserting a pair of delimiters 76 | * Global auto-fill configured to activate only in comments, 77 | docstrings, and text 78 | * Configured packages: [Atomic Chrome][atomic-chrome] (with 79 | [Firefox] support), [Autorevert], [buffer-move], [Company], 80 | [delete-selection-mode], [Dired], [dumb-jump], [ElDoc], [ESUP], 81 | [Forge], [`git-gutter-fringe.el`][git-gutter-fringe.el], 82 | [git-link], [Helpful], [Macrostep], [Magit], [no-littering], 83 | [Org], [Projectile], [pyvenv], [`rg.el`][rg.el], [Smartparens], 84 | [transpose-frame], [undo-tree], [use-package], [visual-regexp], 85 | [`which-key`][which-key], and more 86 | * Major modes for editing many languages and configuration file 87 | types 88 | * Tested on GitHub Actions with [Docker] configuration included for 89 | all supported Emacs versions 90 | * [Zsh] 91 | * Extremely fast and flexible package manager, [znap] 92 | * No-nonsense prompt showing username, hostname, working 93 | directory, and Git status, colored by exit code 94 | * Less bad default tab-completions 95 | * GUI-like file/directory copy/paste functions on the command line 96 | * Extensive library of clean and consistent [Git] aliases 97 | * Colored man pages 98 | * Configured plugins: [wdx], [zsh-autosuggestions], 99 | [zsh-completions] 100 | * [Tmux] 101 | * Keybindings for inserting new windows and shifting them left and 102 | right 103 | * No-nonsense but stylish status bar à la [powerline] but without 104 | the dependencies 105 | * Spectacular hack to leverage [reattach-to-user-namespace] on 106 | macOS with minimal side effects 107 | * [Git] 108 | * Create a repository and a root commit all at once 109 | * Alias and unalias without messing with `git config` 110 | * More helpful output from `git status`, submodules, and more 111 | 112 | ## Installation 113 | 114 | Setup is in three parts: installing the software, installing the 115 | configuration, and optionally installing local configuration. 116 | 117 | ### Installing software 118 | #### macOS 119 | 120 | * Emacs: `brew install bash python`; `brew cask install emacs`; 121 | (optional for improved startup time) `brew install watchexec` 122 | * For LSP servers, refer to [`lsp-mode` 123 | documentation](https://emacs-lsp.github.io/lsp-mode/page/languages/) 124 | * Zsh: 125 | 126 | $ brew install zsh 127 | $ echo $(which zsh) | sudo tee -a /etc/shells 128 | $ chfn -s $(which zsh) 129 | 130 | * Tmux: `brew install tmux` 131 | * Git: `brew install git` 132 | 133 | #### Ubuntu/Debian 134 | 135 | * Emacs: `apt install emacs python3`; (optional for improved startup 136 | time) `apt install watchexec-cli` 137 | * For LSP servers, refer to [`lsp-mode` 138 | documentation](https://emacs-lsp.github.io/lsp-mode/page/languages/) 139 | * For Magit forge integration, `apt install libsqlite3-dev` 140 | * Zsh: `apt install zsh` 141 | * Tmux: `apt install tmux` 142 | * Git: `apt install git` 143 | 144 | #### Arch/Manjaro Linux 145 | 146 | I use [Yay](https://github.com/Jguer/yay) to install AUR packages. If 147 | you prefer something different, substitute to taste. 148 | 149 | * Emacs: `pacman -S emacs python`; (optional for improved startup 150 | time) `yay -S watchexec` 151 | * For LSP servers, refer to [`lsp-mode` 152 | documentation](https://emacs-lsp.github.io/lsp-mode/page/languages/) 153 | * Zsh: `pacman -S zsh` 154 | * Tmux: `pacman -S tmux` 155 | * Git: `pacman -S git` 156 | 157 | ### Installing configuration 158 | 159 | Use symbolic links: 160 | 161 | ./emacs/init.el => ~/.emacs.d/init.el 162 | ./emacs/early-init.el => ~/.emacs.d/early-init.el 163 | ./emacs/versions.el => ~/.emacs.d/straight/versions/radian.el 164 | ./git/.gitconfig => ~/.gitconfig 165 | ./git/.gitexclude => ~/.gitexclude 166 | ./shell/shared/.profile => ~/.profile 167 | ./shell/zsh/.zshrc => ~/.zshrc 168 | ./shell/zsh/.zprofile => ~/.zprofile 169 | ./tmux/.tmux.conf => ~/.tmux.conf 170 | 171 | Do not attempt to use the `emacs` subdirectory of this repository as 172 | `user-emacs-directory`; it won't work. 173 | 174 | ### Installing local configuration 175 | 176 | * Emacs: `~/.emacs.d/init.local.el` (local configuration) and 177 | `~/.emacs.d/straight/versions/radian-local.el` (optional, local 178 | lockfile for `straight.el`; will be created when you run `M-x 179 | straight-freeze-versions`) 180 | * All shells: `~/.profile.local` 181 | * Zsh: `~/.zshrc.local` 182 | * Tmux: `~/.tmux.local.conf` 183 | * Git: `~/.gitconfig.local` 184 | 185 | I suggest versioning your local dotfiles in a separate repository, and 186 | symlinking them to the appropriate locations. This is what I do. 187 | 188 | Here is what your `init.local.el` should probably look like: 189 | 190 | ;; code that should be run at the very beginning of init, e.g. 191 | 192 | (setq radian-font ...) 193 | (setq radian-font-size ...) 194 | 195 | (radian-local-on-hook before-straight 196 | 197 | ;; code that should be run right before straight.el is bootstrapped, 198 | ;; e.g. 199 | 200 | (setq straight-vc-git-default-protocol ...) 201 | (setq straight-check-for-modifications ...)) 202 | 203 | (radian-local-on-hook after-init 204 | 205 | ;; code that should be run at the end of init, e.g. 206 | 207 | (use-package ...)) 208 | 209 | ;; see M-x customize-group RET radian-hooks RET for which hooks you 210 | ;; can use with `radian-local-on-hook' 211 | 212 | You don't have to worry about byte-compiling your local init-file; 213 | Radian actually macroexpands it and embeds it directly into the 214 | byte-compiled Radian init-file. Using the macro `radian-local-on-hook` 215 | instead of defining functions and adding them to Radian's hooks 216 | manually enables some magic that makes this actually work properly. 217 | 218 | ## Documentation 219 | 220 | There is some very incomplete documentation [here][docs]. 221 | 222 | ## Contributing 223 | 224 | Please feel free to contribute in any way that you would like. If you 225 | find a bug or have a question about how to use Radian, [report 226 | it][issues]. If you want to contribute code, [please do][prs]. (Try to 227 | follow the style of the surrounding code.) 228 | 229 | ### Reading the source code 230 | 231 | Please do! It will probably be informative in one way or another. The 232 | goal is that *absolutely everything* should be either obvious or 233 | commented. 234 | 235 | [apheleia]: https://github.com/radian-software/apheleia 236 | [atomic-chrome]: https://github.com/alpha22jp/atomic-chrome 237 | [autorevert]: https://www.emacswiki.org/emacs/AutoRevertMode 238 | [black]: https://github.com/python/black 239 | [blackout]: https://github.com/radian-software/blackout 240 | [brittany]: https://hackage.haskell.org/package/brittany 241 | [buffer-move]: https://github.com/lukhas/buffer-move 242 | [company-statistics]: https://github.com/company-mode/company-statistics 243 | [company]: http://company-mode.github.io/ 244 | [counsel]: https://github.com/abo-abo/swiper#counsel 245 | [ctrlf]: https://github.com/radian-software/ctrlf 246 | [delete-selection-mode]: https://www.emacswiki.org/emacs/DeleteSelectionMode 247 | [dired]: https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html 248 | [docker]: https://www.docker.com/ 249 | [docs]: doc 250 | [dotman]: https://github.com/raxod502/dotman 251 | [dumb-jump]: https://github.com/jacktasia/dumb-jump 252 | [easypg]: https://www.gnu.org/software/emacs/manual/epa.html 253 | [el-patch]: https://github.com/radian-software/el-patch 254 | [eldoc]: https://www.emacswiki.org/emacs/ElDoc 255 | [emacs]: https://www.gnu.org/software/emacs/ 256 | [esup]: https://github.com/jschaf/esup 257 | [eza]: https://eza.rocks/ 258 | [firefox]: https://www.mozilla.org/en-US/firefox/ 259 | [flow]: https://flow.org/ 260 | [flow]: https://flow.org/ 261 | [flx]: https://github.com/lewang/flx 262 | [forge]: https://github.com/magit/forge 263 | [frecency]: https://en.wikipedia.org/wiki/Frecency 264 | [git-gutter-fringe.el]: https://github.com/syohex/emacs-git-gutter-fringe 265 | [git-link]: https://github.com/sshaw/git-link 266 | [git]: https://git-scm.com/ 267 | [go]: https://golang.org/ 268 | [gofmt]: https://golang.org/cmd/gofmt/ 269 | [haskell]: https://www.haskell.org/ 270 | [helm]: https://github.com/emacs-helm/helm 271 | [helpful]: https://github.com/Wilfred/helpful 272 | [historian]: https://github.com/PythonNut/historian.el 273 | [isearch]: https://www.gnu.org/software/emacs/manual/html_node/emacs/Incremental-Search.html 274 | [issues]: https://github.com/radian-software/radian/issues 275 | [ivy]: https://github.com/abo-abo/swiper#ivy 276 | [javascript]: https://developer.mozilla.org/en-US/docs/Web/JavaScript 277 | [jsx]: https://reactjs.org/docs/introducing-jsx.html 278 | [latex]: https://www.latex-project.org/ 279 | [lsp-mode]: https://github.com/emacs-lsp/lsp-mode 280 | [lsp]: https://langserver.org/ 281 | [macrostep]: https://github.com/joddie/macrostep 282 | [magit]: https://magit.vc/ 283 | [no-littering]: https://github.com/tarsius/no-littering 284 | [org]: http://orgmode.org/ 285 | [pipenv]: https://docs.pipenv.org/en/latest/ 286 | [poetry]: https://poetry.eustace.io/ 287 | [powerline]: https://github.com/powerline/powerline 288 | [prescient.el]: https://github.com/radian-software/prescient.el 289 | [prettier]: https://github.com/prettier/prettier 290 | [projectile]: http://batsov.com/projectile/ 291 | [prs]: https://github.com/radian-software/radian/pulls 292 | [python]: https://www.python.org/ 293 | [pyvenv]: https://github.com/jorgenschaefer/pyvenv 294 | [reattach-to-user-namespace]: https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard 295 | [restart-emacs]: https://github.com/iqbalansari/restart-emacs 296 | [rg.el]: https://github.com/dajva/rg.el 297 | [selectrum]: https://github.com/raxod502/selectrum 298 | [smartparens]: https://github.com/Fuco1/smartparens 299 | [smex]: https://github.com/nonsequitur/smex 300 | [straight.el]: https://github.com/raxod502/straight.el 301 | [swiper]: https://github.com/abo-abo/swiper#swiper 302 | [tmux]: https://tmux.github.io/ 303 | [transpose-frame]: https://www.emacswiki.org/emacs/TransposeFrame 304 | [tsx]: https://www.typescriptlang.org/docs/handbook/jsx.html 305 | [typescript]: https://www.typescriptlang.org/ 306 | [undo-tree]: http://www.dr-qubit.org/undo-tree.html 307 | [use-package]: https://github.com/jwiegley/use-package 308 | [vertico]: https://github.com/minad/vertico 309 | [visual-regexp]: https://github.com/benma/visual-regexp.el 310 | [wdx]: https://github.com/radian-software/wdx 311 | [which-key]: https://github.com/justbur/emacs-which-key 312 | [yasnippet]: https://github.com/joaotavora/yasnippet 313 | [zerodark]: https://github.com/NicolasPetton/zerodark-theme 314 | [znap]: https://github.com/marlonrichert/zsh-snap 315 | [zsh-autosuggestions]: https://github.com/zsh-users/zsh-autosuggestions 316 | [zsh-completions]: https://github.com/zsh-users/zsh-completions 317 | [zsh]: http://zsh.sourceforge.net/ 318 | -------------------------------------------------------------------------------- /doc/git.md: -------------------------------------------------------------------------------- 1 | ## Radian git configuration 2 | 3 | This doc outlines the special features that are added to git by 4 | Radian's `.gitconfig`. 5 | 6 | ### Setup 7 | 8 | * Run `ln -sT /path/to/radian/git/.* ~/` 9 | * If you want to add further overrides or configuration, create 10 | `~/.gitconfig.local`; this file is appended to Radian's `.gitconfig` 11 | and can override values 12 | * You should put your `user.name` and `user.email` in 13 | `~/.gitconfig.local` 14 | * To use your own global gitignore file instead of Radian's, set 15 | `core.excludesfile` in `~/.gitconfig.local` to 16 | `~/.gitexclude.local`. By default `~/.gitexclude` from Radian is 17 | used. 18 | 19 | ### Extra commands 20 | 21 | * `git exec CMD...`: Run `CMD` at the root of the current Git 22 | repository. Just for convenience. The alternative is `(cd "$(git 23 | rev-parse --show-toplevel)" && CMD...)` which is much more annoying. 24 | * `git root`: Show the hash of the oldest revision in the repository 25 | (or at least one of them). Faster than paging through all of `git 26 | log`. 27 | 28 | ### Significant behavior changes 29 | 30 | * Disable most command-line usage hints. 31 | * Disable the macOS Keychain credential caching on macOS. Use the 32 | built-in `git-credential-cache` instead. 33 | * Configure diffs to always be shown using less, even if they fit on a 34 | single page. You must press `q` to exit. Adds consistency. 35 | * Show conflicts using three-way diff style, where you can compare 36 | both parents to the common ancestor (merge base). Improves 37 | comprehensibility of diffs. 38 | * When pushing, default to pushing a matching branch of the same name 39 | to remote. Also when pushing, configure upstream so that pulling 40 | will pull from that same origin branch. Do the same when checking 41 | out a remote branch. Overall, reduces typing. 42 | * Refuse to pull except as fast-forward; require `--rebase` or merge. 43 | 44 | ### Enabled features 45 | 46 | * Rebase autosquash capability 47 | * Diff mnemonic prefixes 48 | * Diff copy detection 49 | * Submodule commit logs in diffs and status 50 | * Mercurial remote protocol 51 | * Slightly more refspec information on pulls 52 | -------------------------------------------------------------------------------- /doc/tmux.md: -------------------------------------------------------------------------------- 1 | ## Radian tmux configuration 2 | 3 | This doc outlines the special features that are added to tmux by 4 | Radian's `.tmux.conf`. 5 | 6 | ### Setup 7 | 8 | * Run `ln -sT /path/to/radian/tmux/.tmux.conf ~/.tmux.conf` 9 | * If you want to add further overrides or configuration, create 10 | `~/.tmux.local.conf`; this file is loaded at the end of Radian's 11 | `.tmux.conf` 12 | * On macOS, install 13 | [reattach-to-user-namespace](https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard) 14 | for clipboard to work properly 15 | 16 | ### Standard fixes 17 | 18 | * Compatibility improvements for terminal keybindings and colors 19 | * Mouse integration 20 | * Fix clipboard integration on macOS 21 | * Decrease lag passing the ESC key to child processes 22 | 23 | ### Behavior changes 24 | 25 | * Default prefix key is backtick (`` ` ``) instead of control-B. This 26 | makes switching windows much faster. 27 | * Number windows and panes from 1 instead of from 0, because with the 28 | new prefix key switching to window 0 is unergonomic. 29 | * Automatically renumber windows when removing one. Windows will 30 | therefore always be numbered 1 through (number of windows), and 31 | won't have gaps. 32 | * Open new windows and panes in the same working directory as the 33 | current one, instead of always in the default. 34 | 35 | ### New keybindings 36 | 37 | * `prefix R` - reload `.tmux.conf` 38 | * `prefix \` - swap the current and marked windows (use `prefix m` to 39 | mark or unmark a window) 40 | * `prefix <` and `prefix >` - swap the current window with the one to 41 | the left or right, respectively 42 | * `prefix I` - prompt for an index (1 or greater) and insert a window 43 | before that numbered window 44 | 45 | ### Appearance tweaks 46 | 47 | * New status bar. It uses nicer colors and different styling to make 48 | it a lot more obvious what window is currently selected. 49 | * Status bar is updated once per second, instead of once per 15 50 | seconds. This means that new-activity indicators will show up in a 51 | more timely manner. 52 | -------------------------------------------------------------------------------- /doc/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | This file collects some useful tips for debugging when there are 4 | issues with Radian. 5 | 6 | ## Failed to byte-compile: Debugger entered 7 | 8 | Radian byte-compiles the init-file asynchronously after a successful 9 | init. If there is an error, the first line of the error message is 10 | printed in the minibuffer. You can get the whole error message by 11 | running `make compile` in the Radian repository, which is the same 12 | thing Radian is doing in the background. 13 | 14 | ## Things break elsewhere in the system when loading Radian Emacs 15 | 16 | By default Radian will source `~/.profile` asynchronously after Emacs 17 | startup to ensure that environment variables are set correctly when 18 | Emacs is started from a desktop environment that doesn't configure 19 | this properly. This is like 20 | [exec-path-from-shell](https://github.com/purcell/exec-path-from-shell), 21 | but way faster. 22 | 23 | If your `~/.profile` is not safe to source multiple times, consider 24 | having it set an environment variable that will cause future 25 | invocations to do nothing. Alternatively, add `(setq radian-env-setup 26 | nil)` to `~/.emacs.d/init.local.el` to disable this feature. 27 | -------------------------------------------------------------------------------- /doc/zsh.md: -------------------------------------------------------------------------------- 1 | ## Radian zsh configuration 2 | 3 | This doc outlines the special features that are added to zsh by 4 | Radian's `.zshrc`. 5 | 6 | ### Setup 7 | 8 | * Run `ln -sT /path/to/radian/*/.* ~/` 9 | * If you want to add further overrides or configuration, create 10 | `~/.zshrc.local` and/or `~/.profile.local`; these are evaluated 11 | after Radian's `~/.zshrc` and `~/.profile` respectively 12 | * Note: `~/.zshrc.local` is loaded early during init, but you can 13 | provide hooks to influence the rest of the load - 14 | `radian_after_init_hook` for overriding things at the end, or 15 | `radian_zinit_hook` for adding plugins 16 | * Suggested usage is to set environment variables in 17 | `~/.profile.local` and only define things needed for interactive 18 | usage (e.g. aliases) in `~/.zshrc.local` 19 | 20 | ### Dependencies 21 | 22 | * zsh (obviously) 23 | * git (to clone zinit) 24 | * eza (optional - colorized ls aliases) 25 | 26 | ### Plugin management 27 | 28 | Radian uses 29 | [zdharma-continuum/zinit](https://github.com/zdharma-continuum/zinit) 30 | as a unified plugin manager for Zsh. The plugin manager is installed 31 | user-locally to `~/.local/share/zinit` on first shell startup as long 32 | as Git is available. 33 | 34 | The following plugins are installed by default: 35 | 36 | * [radian-software/wdx](https://github.com/radian-software/wdx) 37 | * [marlonrichert/zsh-autocomplete](https://github.com/marlonrichert/zsh-autocomplete) 38 | * [zsh-users/zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) 39 | * [zsh-users/zsh-completions](https://github.com/zsh-users/zsh-completions) 40 | 41 | If you want to add further plugins, you can define a 42 | `radian_zinit_hook` function in your `~/.zshrc.local` and include 43 | `zplugin light` lines in there. 44 | 45 | Completions setup is handled automatically, including for user-added 46 | plugins. 47 | 48 | ### Behavior changes - command line 49 | 50 | * Force usage of Emacs keybindings in Zsh line editor regardless of 51 | the setting of `$EDITOR`. Note that Radian does not configure 52 | `$EDITOR`, you can set this in `~/.profile.local` if desired 53 | * Allow comments in the interactive shell (start with `#`) 54 | * Allow escaping single quotes in single-quoted strings, `echo 'It''s 55 | me!'` is shorthand for `echo 'It'"'"'s me!'` and both print `It's 56 | me!` 57 | * Disable flow control (`ctrl+s` and `ctrl+q` have their normal Emacs 58 | meaning rather than freezing and unfreezing command output) 59 | 60 | ### Behavior changes - completion 61 | 62 | * Completions (`TAB`) are displayed in a menu below the command line, 63 | you can cycle through them with `TAB` and `Shift+TAB` or exit the 64 | menu with `ctrl+g` 65 | * Completions are based on path-aware substring matching, so 66 | `~/foo/bar` will expand to any file in `~/foo` that includes 67 | `bar` as a substring in its name; non-path arguments or custom 68 | completions also use substring matching 69 | * Globs (`*`) are case-insensitive, match dotfiles by default, and 70 | sort numerically instead of lexicographically 71 | * History expansion (`!`) is disabled, use `ctrl+r` provided by 72 | zsh-autocomplete 73 | 74 | ### Behavior changes - command history 75 | 76 | * History is effectively unlimited both within a shell session and in 77 | `~/.zsh_history` 78 | * History is shared between all sessions with some limitations for 79 | performance. If you ran a command in one session and you want to get 80 | it in your history for another session, reload zsh config (period + 81 | enter) to get it there. 82 | * Don't save commands to history if they start with a space, use this 83 | for sensitive commands. For other commands, remove superfluous 84 | spaces before saving to history file. 85 | 86 | ### Behavior changes - navigation 87 | 88 | * See [wdx](https://github.com/radian-software/wdx) for an easy way to 89 | navigate to well-known directories on your system. Warp point file 90 | is at `~/.config/wdx/points`, not backed up or replicated by 91 | default. Radian aliases `wd` for wdx. 92 | * When you cd to a directory, its name is resolved to the canonical 93 | form (so, symlinks are expanded). This differs from the traditional 94 | behavior. 95 | * You can cd to a directory (absolute or relative) by entering it as a 96 | command name. This also works for `-`, `-2`, ... `-9`. The latter 97 | are adjusted to index from the most recent end of the directory 98 | stack rather than the beginning, and the directory stack is updated 99 | on every cd by default. Print directory stack with `ds` 100 | 101 | ### Commands and aliases 102 | 103 | * Type `.` and press enter to reload zsh config (`exec zsh`) 104 | * Use `help` as a replacement for `man` that can also look up shell 105 | functions and specific subsections of certain man pages. Man pages 106 | are colored by default 107 | * ls aliases: `l` for `ls -lAhF` and `lt` for `tree -a`, but using eza 108 | or gnu ls if installed. `lt ` for only recursing to the nth 109 | level (ignore `.git`, `.svn`, `node_modules` by default), and `lti 110 | ` for ignoring more patterns. Use `ltli ` to combine 111 | both modes. `lg` for getting a grid instead of a list 112 | * wd aliases: `wd` for `wdx`, `ws` for `wdx set`, `wsf` for `wdx set 113 | -f` 114 | * filesystem clipboard: `copy ...` to record a list of 115 | filenames, then cd somewhere else and `paste []` or `move 116 | []` to execute `cp` or `mv` respectively on the "copied" paths 117 | and/or the path passed to `paste` or `move`. Note that `paste` and 118 | `move` shadow builtin commands, use `command paste` or `command 119 | move` if they are needed. `pasteln` is the same but uses `ln -s` 120 | * `delink ` to replace a symlink with a copy of what it points 121 | to, or `transpose ` to swap two files 122 | (non-atomically) 123 | * `md` is `mkdir -p`, `rd` is `rmdir`, `t` is `trash` (must be 124 | installed separately, there are different distributions) 125 | * emacs aliases: `e`/`ew` for terminal and graphical Emacs. `eq`/`eqw` 126 | for `emacs -Q`. `ue`/`uew` for setting `USER_EMACS_DIRECTORY` to 127 | current directory, for a clean environment. `ec`/`ecw` for 128 | emacsclient 129 | * git aliases: many, covering most of the existing commands and 130 | commonly used flags, especially for `git log` - check the source for 131 | a list 132 | * tmux aliases - `ts` for `tmux new-session`, `ta` for `tmux attach` 133 | * vim aliases - `v` for nvim or vim or vi 134 | 135 | ### Appearance tweaks 136 | 137 | * Modified prompt - includes username and hostname, abbreviated 138 | working directory, shows git info if installed (branch + dirty 139 | status), and is colorized based on the last command's return code 140 | -------------------------------------------------------------------------------- /emacs/early-init.el: -------------------------------------------------------------------------------- 1 | ;; -*- lexical-binding: t -*- 2 | 3 | ;; This file is loaded before package.el is initialized, and before 4 | ;; the first graphical frame is initialized, by Emacs 27 (but not by 5 | ;; any previous version of Emacs). Trivia: I was the person to 6 | ;; implement support for early-init.el, after a protracted argument 7 | ;; between me and most of the rest of the Emacs mailing list. 8 | ;; 9 | ;; If the early init-file is available, we actually execute our entire 10 | ;; init process within it, by just loading the regular init-file. 11 | ;; (That file takes care of making sure it is only loaded once.) 12 | 13 | ;; Load an alternate ~/.emacs.d during regular init. 14 | (unless (getenv "USER_EMACS_DIRECTORY") 15 | 16 | (defun radian--advice-fix-display-graphic-p (func &optional display) 17 | "Fix `display-graphic-p' so it works while loading the early init-file." 18 | (if display 19 | (funcall func display) 20 | ;; `display-graphic-p' lies by returning nil, but 21 | ;; `initial-window-system' tells the truth (it is nil only if we 22 | ;; are actually in a tty environment). 23 | initial-window-system)) 24 | 25 | (advice-add #'display-graphic-p :around 26 | #'radian--advice-fix-display-graphic-p) 27 | 28 | (defun radian--advice-fix-xw-display-color-p (func &optional display) 29 | "Fix `xw-display-color-p' so it works while loading the early init-file." 30 | (if (or display after-init-time) 31 | (funcall func display) 32 | ;; Make an educated guess. 33 | initial-window-system)) 34 | 35 | (advice-add #'xw-display-color-p :around 36 | #'radian--advice-fix-xw-display-color-p) 37 | 38 | (defun radian--advice-disable-x-resource-application () 39 | "Disable `x-apply-session-resources'. 40 | Now, `x-apply-session-resources' normally gets called before 41 | reading the init-file. However if we do our initialization in the 42 | early init-file, before that function gets called, then it may 43 | override some important things like the cursor color. So we just 44 | disable it, since there's no real reason to respect X 45 | resources.") 46 | 47 | (advice-add #'x-apply-session-resources :override 48 | #'radian--advice-disable-x-resource-application) 49 | 50 | ;; Load the regular init-file. 51 | (load 52 | (expand-file-name "init.el" user-emacs-directory) nil 'nomessage 'nosuffix) 53 | 54 | ;; Avoid messing with things more than necessary. 55 | (advice-remove #'display-graphic-p #'radian--advice-fix-display-graphic-p) 56 | (advice-remove #'xw-display-color-p #'radian--advice-fix-xw-display-color-p)) 57 | -------------------------------------------------------------------------------- /emacs/init.el: -------------------------------------------------------------------------------- 1 | ;; -*- lexical-binding: t -*- 2 | 3 | ;; This file wraps the primary Radian configuration (which lives in 4 | ;; radian.el) so that we don't have to wrap the entire file in various 5 | ;; `let' forms, etc. We put as much as possible in radian.el. 6 | 7 | ;; This allows us to instead load a different Emacs configuration by 8 | ;; exporting USER_EMACS_DIRECTORY to another .emacs.d directory. 9 | (let ((alternate-user-emacs-directory (getenv "USER_EMACS_DIRECTORY"))) 10 | 11 | (defvar radian--init-file-loaded-p nil 12 | "Non-nil if the init-file has already been loaded. 13 | This is important for Emacs 27 and above, since our early 14 | init-file just loads the regular init-file, which would lead to 15 | loading the init-file twice if it were not for this variable.") 16 | 17 | (cond 18 | ;; If already loaded, do nothing. But still allow re-loading, just 19 | ;; do it only once during init. 20 | ((and (not after-init-time) radian--init-file-loaded-p)) 21 | 22 | ;; Delegate to another Emacs configuration. (We still don't want to 23 | ;; load it twice.) 24 | (alternate-user-emacs-directory 25 | (setq alternate-user-emacs-directory 26 | (file-name-as-directory alternate-user-emacs-directory)) 27 | (setq user-emacs-directory alternate-user-emacs-directory) 28 | (setq user-init-file (expand-file-name "init.el" user-emacs-directory)) 29 | (load user-init-file 'noerror 'nomessage)) 30 | (t 31 | (setq radian--init-file-loaded-p t) 32 | 33 | (defvar radian-minimum-emacs-version "27.1" 34 | "Radian Emacs does not support any Emacs version below this.") 35 | 36 | (defvar radian-local-init-file 37 | (expand-file-name "init.local.el" user-emacs-directory) 38 | "File for local customizations of Radian.") 39 | 40 | ;; Prevent package.el from modifying this file. 41 | (setq package-enable-at-startup nil) 42 | 43 | ;; Prevent Custom from modifying this file. 44 | (setq custom-file (expand-file-name "custom.el" user-emacs-directory)) 45 | (load custom-file 'noerror 'nomessage) 46 | 47 | ;; Make sure we are running a modern enough Emacs, otherwise abort 48 | ;; init. 49 | (if (version< emacs-version radian-minimum-emacs-version) 50 | (error (concat "Radian Emacs requires at least Emacs %s, " 51 | "but you are running Emacs %s") 52 | radian-minimum-emacs-version emacs-version) 53 | 54 | (let* ((this-file (or user-init-file 55 | (expand-file-name "init.el" user-emacs-directory))) 56 | (link-target 57 | ;; This function returns the target of the link. If the 58 | ;; init-file is not a symlink, then we abort. 59 | ;; 60 | ;; We may be loading init.el in batch mode, in which case 61 | ;; `user-init-file' is nil. In that case, we should have 62 | ;; some backup options to try. 63 | (file-symlink-p this-file))) 64 | 65 | (unless link-target 66 | (error "Init-file %S is not a symlink" this-file)) 67 | 68 | (defvar radian-lib-file (expand-file-name 69 | "radian.el" 70 | (file-name-directory link-target)) 71 | "File containing main Radian configuration. 72 | This file is loaded by init.el.") 73 | 74 | (unless (file-exists-p radian-lib-file) 75 | (error "Library file %S does not exist" radian-lib-file)) 76 | 77 | (defvar radian--finalize-init-hook nil 78 | "Hook run unconditionally after init, even if it fails. 79 | Unlike `after-init-hook', this hook is run every time the 80 | init-file is loaded, not just once.") 81 | 82 | (defvar radian-original-file-name-handler-alist nil 83 | "The value of `file-name-handler-alist' during load time. 84 | `file-name-handler-alist' is set to nil while Radian is loading.") 85 | 86 | (unwind-protect 87 | ;; Load the main Radian configuration code. Disable 88 | ;; `file-name-handler-alist' to improve load time. 89 | ;; 90 | ;; Make sure not to load an out-of-date .elc file. Since 91 | ;; we byte-compile asynchronously in the background after 92 | ;; init succeeds, this case will happen often. 93 | (let* ((radian-original-file-name-handler-alist 94 | file-name-handler-alist) 95 | (file-name-handler-alist nil) 96 | (load-prefer-newer t) 97 | (stale-bytecode t)) 98 | (catch 'stale-bytecode 99 | ;; We actually embed the contents of the local 100 | ;; init-file directly into the compiled radian.elc, so 101 | ;; that it can get compiled as well (and its 102 | ;; macroexpansion can use packages that Radian only 103 | ;; loads at compile-time). So that means we have to go 104 | ;; the slow path if the local init-file has been 105 | ;; updated more recently than the compiled radian.elc. 106 | (when (file-newer-than-file-p 107 | radian-local-init-file 108 | (concat radian-lib-file "c")) 109 | (throw 'stale-bytecode nil)) 110 | (load 111 | (file-name-sans-extension radian-lib-file) 112 | nil 'nomessage) 113 | (setq stale-bytecode nil)) 114 | (when stale-bytecode 115 | ;; Don't bother trying to recompile, unlike in 116 | ;; straight.el, since we are going to handle that 117 | ;; later, asynchronously. 118 | (ignore-errors 119 | (delete-file (concat radian-lib-file "c"))) 120 | (load radian-lib-file nil 'nomessage 'nosuffix))) 121 | (run-hooks 'radian--finalize-init-hook))))))) 122 | 123 | ;; Local Variables: 124 | ;; no-native-compile: t 125 | ;; End: 126 | -------------------------------------------------------------------------------- /emacs/use-package-keywords.md: -------------------------------------------------------------------------------- 1 | Use the following ordering for `use-package` keywords: 2 | 3 | * `:preface` 4 | * `:straight` 5 | * `:no-require` 6 | * `:defines` 7 | * `:functions` 8 | * `:demand` 9 | * `:defer` 10 | * `:after` 11 | * `:commands` 12 | * `:init/el-patch` 13 | * `:init` 14 | * `:magic` 15 | * `:mode` 16 | * `:interpreter` 17 | * `:hook` 18 | * `:bind` 19 | * `:bind*` 20 | * `:bind-keymap` 21 | * `:bind-keymap*` 22 | * `:config/el-patch` 23 | * `:config` 24 | * `:blackout` 25 | -------------------------------------------------------------------------------- /emacs/versions.el: -------------------------------------------------------------------------------- 1 | (("Emacs-wgrep" . "208b9d01cfffa71037527e3a324684b3ce45ddc4") 2 | ("all-the-icons.el" . "ee414384938ccf2ce93c77d717b85dc5538a257d") 3 | ("apache-mode" . "00595893920ce755014d793839086bf15ac90075") 4 | ("apheleia" . "82cbb665bc6a62de59e00aa76dcef29ef3a6c3a2") 5 | ("atomic-chrome" . "072a137a19d7e6a300ca3e87c0e142a7f4ccb5fb") 6 | ("auctex" . "ee58d625501af073bde569718db02d1236162283") 7 | ("blackout" . "7707211370f03f03a2f74df15f42ac24a1e99300") 8 | ("buffer-move" . "e7800b3ab1bd76ee475ef35507ec51ecd5a3f065") 9 | ("cider" . "1cd6ab7b7cb4a7e079a273600c4d28307c3aba40") 10 | ("clojure-mode" . "af0e518a6b86f2c6f32dfb30b99c067071ed5cd4") 11 | ("closql" . "2bff36edd28c9a0d0c25b545b3837fa874376cc5") 12 | ("company-lsp" . "f921ffa0cdc542c21dc3dd85f2c93df4288e83bd") 13 | ("company-mode" . "32f030a4c79bbf082cc21ec21b2cf8ba9dfa22cc") 14 | ("compat" . "2577cc74d996620766adf1c9ec8f44ecbac32e79") 15 | ("crontab-mode" . "7412f3df0958812bfcacd5875a409fa795fa8ecc") 16 | ("ctrlf" . "9b4cf6c79a961f2bfbb949805aa300fcf1eb40a6") 17 | ("dash.el" . "885332bbc4582b08d4f24526250876f3a7569067") 18 | ("dockerfile-mode" . "39a012a27fcf6fb629c447d13b6974baf906714c") 19 | ("dumb-jump" . "ede6a04187e79a29ef31d14760ac0d8d4c5f4cc5") 20 | ("el-get" . "f8f651b448f0b5ba478a92bf1c361ff17b10e8d2") 21 | ("el-patch" . "e10392847cb4d9d32d614a5678007aac4c2cca92") 22 | ("elisp-refs" . "541a064c3ce27867872cf708354a65d83baf2a6d") 23 | ("elisp-ruby-electric" . "decf39c0d66a3fa171e16f4559d3deac89d8386d") 24 | ("elpa" . "9f03484eee87d0b311fbf06de4ce6a96cde160cc") 25 | ("emacs-sqlite3-api" . "a601c9965e4d0178705a64b7d4f88709ca9aea66") 26 | ("emacs-websocket" . "40c208eaab99999d7c1e4bea883648da24c03be3") 27 | ("emacs-which-key" . "1e89fa000e9ba9549f15ef57abccd118d5f2fe1a") 28 | ("emacsmirror-mirror" . "4a348ac4c895dd8b013d7313ff079d0214bcf6ec") 29 | ("emacsql" . "5108c16c5e1d5bfdd41fcc0807241e28886ab763") 30 | ("esup" . "4b49c8d599d4cc0fbf994e9e54a9c78e5ab62a5f") 31 | ("f.el" . "1e7020dc0d4c52d3da9bd610d431cab13aa02d8c") 32 | ("flycheck" . "bec59eeb58f86b10f8235bf94c873f3b0352ac41") 33 | ("forge" . "359e424b968ad6763854bb9b11157caff1e775ca") 34 | ("fringe-helper.el" . "ef4a9c023bae18ec1ddd7265f1f2d6d2e775efdd") 35 | ("ghub" . "e0a65456098c5e0f2cf2724d071e9033f7b0bf3a") 36 | ("git-gutter" . "9afe45b41a82a332606d3e70ef85d323d27b9e4f") 37 | ("git-gutter-fringe" . "648cb5b57faec55711803cdc9434e55a733c3eba") 38 | ("git-link" . "34d4989e3e2434316359ae6a9e8423e9951606d7") 39 | ("git-modes" . "52ea2a1281ea9df9b8732fe2add0e6a0c9c2cd11") 40 | ("go-mode.el" . "6f4ff9ef874d151ed8d297a80f1bf27db5d9dbf0") 41 | ("haskell-mode" . "d23ec34788286405f377ce485d2a17e302d94a4f") 42 | ("hcl-mode" . "37f2cb1bf6fb51fbf99d4fac256298fcd6d1dd24") 43 | ("helpful" . "a32a5b3d959a7fccf09a71d97b3d7c888ac31c69") 44 | ("ht.el" . "1c49aad1c820c86f7ee35bf9fff8429502f60fef") 45 | ("hydra" . "317e1de33086637579a7aeb60f77ed0405bf359b") 46 | ("json-mode" . "77125b01c0ddce537085201098bea9b4b8ba6be3") 47 | ("json-snatcher" . "b28d1c0670636da6db508d03872d96ffddbc10f2") 48 | ("lsp-haskell" . "47a1878cc1aa3a9de30e8db8950ca11139fd13f6") 49 | ("lsp-mode" . "51022dc79486544730de6d7336e3f0a0afe2a5b3") 50 | ("lsp-pyright" . "dd54b3ae7c22d34faaced7b1a89739063c552b1f") 51 | ("lsp-ui" . "a0dde8b52b4411cbac2eb053ef1515635ea0b7ed") 52 | ("lua-mode" . "d074e4134b1beae9ed4c9b512af741ca0d852ba3") 53 | ("macrostep" . "390da223244fda11b7176f4ba8dcbc35c94d1805") 54 | ("magit" . "e2ca80a26e40480b6dda66adad09dd1031e4da3e") 55 | ("markdown-mode" . "0cdebc833ed9b98baf9f260ed12b1e36b0ca0e89") 56 | ("melpa" . "f5f6d68cdd49cea0f9baa7457a945df4ca530a8f") 57 | ("no-littering" . "caf2f7f5cac25fb0053e383f3475120bc696864f") 58 | ("nongnu-elpa" . "fda0e2eb3117a2bdcd6b07c483935628b1417b56") 59 | ("org" . "288e0a11c217991bd69acf2b6f6f720db1fbbf4e") 60 | ("org-contrib" . "3062acd0e350598727f8dac459ae3a5ee05db7c6") 61 | ("osx-trash" . "90f0c99206022fec646206018fcd63d9d2e57325") 62 | ("package-lint" . "17e4ab20dd3e36fa540007b4f4047170c23bdb10") 63 | ("parseclj" . "6af22372e0fe14df882dd300b22b12ba2d7e00b0") 64 | ("parseedn" . "3407e4530a367b6c2b857dae261cdbb67a440aaa") 65 | ("pip-requirements.el" . "216cd1690f80cc965d4ae47b8753fc185f778ff6") 66 | ("pkgbuild-mode" . "9525be8ecbd3a0d0bc7cc27e6d0f403e111aa067") 67 | ("popup-el" . "6a475b0384d24d94f541d535f5597daa8bb508d4") 68 | ("prescient.el" . "7dd5b53886146a507f1388e0b61990f9820f9eb1") 69 | ("projectile" . "0da59734fbc23fc26222a7d03f6671b3116b0b77") 70 | ("protobuf" . "2f6e7055952eeff2fef2f29edb092c97e7949793") 71 | ("queue" . "f986fb68e75bdae951efb9e11a3012ab6bd408ee") 72 | ("restart-emacs" . "1607da2bc657fe05ae01f7fdf26f716eafead02c") 73 | ("rg.el" . "5420dc6ca05c6ab0954113772d784c4c968ca219") 74 | ("rust-mode" . "e54bbae8c4c2af580b5721ad5ac151f2ad19293e") 75 | ("s.el" . "dda84d38fffdaf0c9b12837b504b402af910d01d") 76 | ("seq" . "27a90793a13f149121180e864fa53d68b9eac0b3") 77 | ("sesman" . "7bca68dbbab0af26a6a23be1ff5fa97f9a18e022") 78 | ("smartparens" . "a5c68cac1bea737b482a37aa92de4f6efbf7580b") 79 | ("spinner" . "d4647ae87fb0cd24bc9081a3d287c860ff061c21") 80 | ("ssh-config-mode-el" . "d560a0876a93ad4130baf33dae1b9405ad37a405") 81 | ("straight.el" . "645eeb9841b7eecfbc7bbaaaf883d30e5debe350") 82 | ("swift-mode" . "26ca22a913cd6626fa6d9b187ffe34a82c075202") 83 | ("syntax-subword" . "9aa9b3f846bfe2474370642458a693ac4760d9fe") 84 | ("terraform-mode" . "a645c32a8f0f0d04034262ae5fea330d5c7a33c6") 85 | ("toml-mode.el" . "f6c61817b00f9c4a3cab1bae9c309e0fc45cdd06") 86 | ("transient" . "2dd0102ec3df901d421fc338e5c768467cc54ecf") 87 | ("transpose-frame" . "94c87794d53883a2358d13da264ad8dab9a52daa") 88 | ("treepy.el" . "75fe3ec37e6f9b2bdfd6d0584efd984d0c00a43e") 89 | ("undo-tree" . "5c70aaf206cc369a989cd83c372ba30235c9a935") 90 | ("use-package" . "a6e856418d2ebd053b34e0ab2fda328abeba731c") 91 | ("vertico" . "b413071021a717bc25f730d2f94ce0740a9b8e34") 92 | ("vimrc-mode" . "13bc150a870d5d4a95f1111e4740e2b22813c30e") 93 | ("visual-regexp-steroids.el" . "a6420b25ec0fbba43bf57875827092e1196d8a9e") 94 | ("visual-regexp.el" . "48457d42a5e0fe10fa3a9c15854f1f127ade09b5") 95 | ("web-mode" . "005aa62d6f41fbf9bc045cac3b3b772716ee8ba7") 96 | ("with-editor" . "1b4526453ef6bdee30635f469aa26085c02b1ac1") 97 | ("yaml-mode" . "7b5ce294fb15c2c8926fa476d7218aa415550a2a") 98 | ("yaml.el" . "70c4fcead97e9bd6594e418c922ae769818f4245") 99 | ("yasnippet" . "eb5ba2664c3a68ae4a53bb38b85418dd131b208f") 100 | ("zerodark-theme" . "b463528704f6eb00684c0ee003fbd8e42901cde0")) 101 | :epsilon 102 | -------------------------------------------------------------------------------- /git/.gitconfig: -------------------------------------------------------------------------------- 1 | [advice] 2 | detachedHead = false 3 | pushNonFastForward = false 4 | statusHints = false 5 | [alias] 6 | # Run a command with the repository root as cwd. See 7 | # https://stackoverflow.com/questions/957928#comment9747528_957978. 8 | exec = "!exec " 9 | root = rev-list --max-parents=0 HEAD 10 | [branch] 11 | autoSetupMerge = true 12 | [color] 13 | ui = auto 14 | [core] 15 | autocrlf = false 16 | excludesfile = ~/.gitexclude 17 | # Always use the pager. This is important for Yay, which uses 18 | # 'git diff' to print diffs, which may disappear off the top 19 | # of the screen if the pager doesn't get invoked for each one. 20 | # See . 21 | pager = less -+F 22 | # https://github.blog/2022-06-29-improve-git-monorepo-performance-with-a-file-system-monitor/ 23 | fsmonitor = true 24 | untrackedcache = true 25 | [credential] 26 | helper = 27 | helper = cache --timeout 86400 28 | [diff] 29 | mnemonicprefix = true 30 | renames = copies 31 | submodule = log 32 | [init] 33 | defaultBranch = main 34 | [merge] 35 | conflictstyle = diff3 36 | stat = true 37 | [protocol "hg"] 38 | allow = always 39 | [pull] 40 | ff = only 41 | [push] 42 | autoSetupRemote = true 43 | default = current 44 | [rebase] 45 | autosquash = true 46 | [status] 47 | submodulesummary = true 48 | # .gitconfig.local should be included last. 49 | [include] 50 | path = ~/.gitconfig.local 51 | -------------------------------------------------------------------------------- /git/.gitexclude: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .log 3 | .tern-port 4 | ~ 5 | -------------------------------------------------------------------------------- /scripts/build.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | emacs --batch -l "$HOME/.emacs.d/init.el" 7 | -------------------------------------------------------------------------------- /scripts/byte-compile.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | (emacs --batch \ 7 | --eval "(progn \ 8 | (setq straight-safe-mode t \ 9 | radian-compiling t) \ 10 | (load (expand-file-name \"init.el\" \ 11 | user-emacs-directory) nil t))" \ 12 | --funcall radian-batch-byte-compile 2>&1 \ 13 | | (grep -v "In toplevel form" || true) \ 14 | | (grep -v "In end of data" || true) \ 15 | | (grep -v "Warning: Package cl is deprecated" || true) \ 16 | | (grep -v "variable .image-scaling-factor." || true) \ 17 | | (! grep .)) || (rm -f emacs/radian.elc; false) 18 | -------------------------------------------------------------------------------- /scripts/check-line-length.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | find=( 7 | find . 8 | -name .git -prune -o 9 | -name "*.elc" -o 10 | -type f -print 11 | ) 12 | 13 | readarray -t files < <("${find[@]}" | sort) 14 | 15 | code="$(cat <<"EOF" 16 | 17 | (length($0) >= 80 && $0 !~ /https?:\/\//) \ 18 | { printf "%s:%d: %s\n", FILENAME, NR, $0 } 19 | 20 | EOF 21 | )" 22 | 23 | for file in "${files[@]}"; do 24 | awk "$code" "$file" 25 | done | (! grep .) 26 | -------------------------------------------------------------------------------- /scripts/checkdoc.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | file="emacs/radian.el" 7 | 8 | code="$(cat <&1 | (! grep .) 26 | -------------------------------------------------------------------------------- /scripts/docker-install.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | if (( $# != 1 )); then 7 | echo "usage: docker-install.bash UID" >&2 8 | exit 1 9 | fi 10 | 11 | uid="$1" 12 | 13 | packages=" 14 | 15 | # needed to run build system 16 | make 17 | 18 | # needed for 'make help' 19 | bsdmainutils 20 | 21 | # needed for magit and friends 22 | git 23 | 24 | " 25 | 26 | export DEBIAN_FRONTEND=noninteractive 27 | apt-get update 28 | apt-get install -y $(grep -v "^#" <<< "$packages") 29 | rm -rf /var/lib/apt/lists/* 30 | 31 | useradd --uid="$uid" --create-home docker 32 | 33 | rm "$0" 34 | -------------------------------------------------------------------------------- /scripts/docker.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | tag="${1:-latest}" 7 | 8 | args=(bash) 9 | if [[ -n "$2" ]]; then 10 | args=("${args[@]}" -c "$2") 11 | fi 12 | 13 | docker() { 14 | if [[ "$OSTYPE" != darwin* ]] && [[ "$EUID" != 0 ]]; then 15 | command sudo docker "$@" 16 | else 17 | command docker "$@" 18 | fi 19 | } 20 | 21 | docker build . -t "radian:$tag" \ 22 | --build-arg "UID=$UID" \ 23 | --build-arg "VERSION=$tag" 24 | 25 | repos=".emacs.d/straight/repos" 26 | 27 | # If we don't do this, then the directory gets created in the host 28 | # filesystem with root ownership :/ 29 | mkdir -p "$HOME/${repos}" 30 | 31 | it=() 32 | 33 | if [[ -t 0 ]]; then 34 | it+=(-it) 35 | fi 36 | 37 | docker run "${it[@]}" --rm \ 38 | -v "$PWD:/home/docker/radian" \ 39 | -v "$HOME/${repos}:/home/docker/${repos}" \ 40 | "radian:$tag" "${args[@]}" 41 | -------------------------------------------------------------------------------- /scripts/print_env.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from __future__ import print_function 4 | 5 | import os 6 | import sys 7 | 8 | exec_name = sys.argv[0] 9 | args = sys.argv[1:] 10 | 11 | if len(args) != 1: 12 | print("usage: {} ".format(exec_name), file=sys.stderr) 13 | sys.exit(1) 14 | 15 | delimiter = args[0] 16 | 17 | print(delimiter, end="") 18 | for key, value in os.environ.items(): 19 | if delimiter in key: 20 | print("delimiter in variable name {}".format(repr(key)), 21 | file=sys.stderr) 22 | sys.exit(1) 23 | if delimiter in value: 24 | print("delimiter in value for variable {}: {}" 25 | .format(repr(key), repr(value)), file=sys.stderr) 26 | sys.exit(1) 27 | print(key, end="") 28 | print(delimiter, end="") 29 | print(value, end="") 30 | print(delimiter, end="") 31 | -------------------------------------------------------------------------------- /scripts/symlink-dotfiles.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | # If you pass an argument to this script, it is assumed to be where 7 | # the Radian repository will go. This is used by docker-install.bash, 8 | # which runs this script in a temporary directory rather than from 9 | # Radian. 10 | 11 | script="$(realpath "$0")" 12 | scripts="$(dirname "$script")" 13 | radian="${1:-$(dirname "$scripts")}" 14 | 15 | safe_link() { 16 | if [[ -e "$2" && ! -L "$2" ]]; then 17 | echo "already exists and not a symlink: $2" >&2 18 | exit 1 19 | fi 20 | 21 | ln -sf "$1" "$2" 22 | } 23 | 24 | mkdir -p "$HOME/.emacs.d/straight/versions" 25 | safe_link "$radian/emacs/early-init.el" "$HOME/.emacs.d/early-init.el" 26 | safe_link "$radian/emacs/init.el" "$HOME/.emacs.d/init.el" 27 | safe_link "$radian/emacs/versions.el" \ 28 | "$HOME/.emacs.d/straight/versions/radian.el" 29 | -------------------------------------------------------------------------------- /scripts/validate-patches.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -o pipefail 5 | 6 | emacs --batch \ 7 | --eval "(setq straight-safe-mode t)" \ 8 | --load "$HOME/.emacs.d/init.el" \ 9 | --funcall el-patch-validate-all 2>&1 \ 10 | | (! grep -F invalid) 11 | -------------------------------------------------------------------------------- /shell/shared/.profile: -------------------------------------------------------------------------------- 1 | ## PATH setup 2 | 3 | case "$OSTYPE" in 4 | darwin*) 5 | export PATH= 6 | eval "$(/usr/libexec/path_helper -s)" 7 | ;; 8 | esac 9 | 10 | if [ -f /etc/profile ]; then 11 | . /etc/profile 12 | fi 13 | 14 | ## External configuration 15 | ### ~/.profile.local 16 | 17 | if [ -f ~/.profile.local ]; then 18 | . ~/.profile.local 19 | fi 20 | 21 | ## gpg-agent 22 | 23 | if command -v gpg-connect-agent >/dev/null 2>&1; then 24 | 25 | gpg_restart() { 26 | gpg-connect-agent reloadagent /bye 27 | } 28 | 29 | gpg_forget() { 30 | gpg-connect-agent reloadagent /bye 31 | } 32 | 33 | fi 34 | 35 | ## ssh-agent 36 | 37 | if command -v ssh-agent >/dev/null 2>&1; then 38 | 39 | ssh_connect() { 40 | if [ -n "$HOME" ] && [ -f "$HOME/.ssh/agent-info" ]; then 41 | eval "$(cat "$HOME/.ssh/agent-info")" >/dev/null 42 | fi 43 | } 44 | 45 | ssh_connected() { 46 | ps -p "$SSH_AGENT_PID" 2>&1 | grep -qF ssh-agent 47 | } 48 | 49 | ssh_forget() { 50 | ssh-add -D 51 | } 52 | 53 | ssh_restart() { 54 | if [ -n "$HOME" ]; then 55 | pkill -U "$USER" ssh-agent 56 | mkdir -p "$HOME/.ssh" 57 | ssh-agent ${SSH_AGENT_ARGS:--t 86400} > "$HOME/.ssh/agent-info" 58 | ssh_connect 59 | fi 60 | } 61 | 62 | ssh_connect 63 | if ! ssh_connected; then 64 | ssh_restart 65 | fi 66 | 67 | fi 68 | 69 | export NPM_CONFIG_UPDATE_NOTIFIER=false 70 | export PIP_DISABLE_PIP_VERSION_CHECK=1 71 | -------------------------------------------------------------------------------- /shell/zsh/.zprofile: -------------------------------------------------------------------------------- 1 | # Okay, so here's the deal. Ideally we just want to source ~/.profile 2 | # in ~/.zshenv, which gets sourced in every shell invocation. 3 | # Unfortunately, macOS provides an /etc/profile which sets the default 4 | # PATH, and this file gets sourced *after* ~/.zshenv apparently, which 5 | # means the PATH we just set up in ~/.profile gets messed up. So 6 | # instead we need to use ~/.zprofile, which gets sourced after 7 | # /etc/profile. Unfortunately, ~/.zprofile doesn't get sourced in 8 | # Linux terminal emulators (presumably because they don't start login 9 | # shells, while macOS terminal emulators do for some reason). Thus we 10 | # need to use both, but for efficiency we read and write an 11 | # (unexported) environment variable RADIAN_SKIP_PROFILE to make sure 12 | # that we only source ~/.profile once in any given shell session. 13 | 14 | emulate sh -c '. "$HOME/.profile"' 15 | RADIAN_SKIP_PROFILE=1 16 | -------------------------------------------------------------------------------- /shell/zsh/.zshenv: -------------------------------------------------------------------------------- 1 | # See .zprofile for some explanation of what is going on here. 2 | 3 | if [ -z "$RADIAN_SKIP_PROFILE" ]; then 4 | emulate sh -c '. "$HOME/.profile"' 5 | else 6 | RADIAN_SKIP_PROFILE= 7 | fi 8 | 9 | # https://github.com/marlonrichert/zsh-autocomplete#additional-step-for-ubuntu 10 | skip_global_compinit=1 11 | -------------------------------------------------------------------------------- /shell/zsh/.zshrc: -------------------------------------------------------------------------------- 1 | ## Locate Radian repository 2 | 3 | # Set $RADIAN to the location of the Radian repository, if found. 4 | if [[ -L $0 && -d ${0:A:h}/radian-emacs ]]; then 5 | export RADIAN=${0:A:h} 6 | else 7 | unset RADIAN 8 | fi 9 | 10 | ## External configuration 11 | ### ~/.zshrc.local 12 | 13 | if [[ -f ~/.zshrc.local ]]; then 14 | . ~/.zshrc.local 15 | fi 16 | 17 | ## Set up plugin manager 18 | 19 | if [[ -f ~/.local/share/znap/znap/znap.zsh ]]; then 20 | . ~/.local/share/znap/znap/znap.zsh 21 | elif (( $+commands[git] )); then 22 | mkdir -p ~/.local/share/znap 23 | git clone https://github.com/marlonrichert/zsh-snap.git ~/.local/share/znap/znap 24 | . ~/.local/share/znap/znap/znap.zsh 25 | fi 26 | 27 | ### znap 28 | 29 | if typeset -f znap >/dev/null; then 30 | # Provides the 'wdx' function to set warp points to directories 31 | # and quickly jump to them. 32 | znap source radian-software/wdx 33 | 34 | # If a previous command starts with what you have typed, show it 35 | # in dimmed color after the cursor, and allow completing it. 36 | znap source zsh-users/zsh-autosuggestions 37 | 38 | # Configure tab-completions for many external commands. 39 | znap clone zsh-users/zsh-completions 40 | fpath+=(~[zsh-users/zsh-completions]/src) 41 | 42 | if typeset -f radian_znap_hook > /dev/null; then 43 | radian_znap_hook 44 | fi 45 | fi 46 | 47 | # Disable automatically enabling git-maintenance by znap, because it 48 | # will write it into the Radian .gitconfig and include hardcoded paths 49 | # there. You can enable git-maintenance if you want but it needs to be 50 | # done in the .zshrc.local. 51 | # 52 | # https://github.com/marlonrichert/zsh-snap?tab=readme-ov-file#automatic-git-maintenance 53 | zstyle ':znap:*:*' git-maintenance off 54 | 55 | ## Shell configuration 56 | ### Prompt 57 | 58 | # Enable parameter expansion and other substitutions in the $PROMPT. 59 | setopt prompt_subst 60 | 61 | # Load some associative arrays (color, fg, and bg) that give us 62 | # convenient access to color-changing escape codes. 63 | autoload -U colors && colors 64 | 65 | # Here we define a prompt that displays the current directory and git 66 | # branch, and turns red on a nonzero exit code. Adapted heavily from 67 | # [1], with supporting functions extracted from Oh My Zsh [2] so that 68 | # we don't have to load the latter as a dependency. 69 | # 70 | # [1]: https://github.com/robbyrussell/oh-my-zsh/blob/master/themes/mgutz.zsh-theme 71 | # [2]: https://github.com/robbyrussell/oh-my-zsh/blob/3705d47bb3f3229234cba992320eadc97a221caf/lib/git.zsh 72 | 73 | # Display the user@hostname. Then change the color and display the 74 | # working directory. 75 | rpp='%{${RADIAN_PROMPT_PREFIX:-}%}%{$fg[yellow]%}{%n@${RADIAN_HOSTNAME:-%m}}' 76 | radian_prompt_prefix="${rpp}"' %(?.%{$fg[blue]%}.%{$fg[red]%})%c' 77 | 78 | # Change the color and then display a '%' or '#', then reset the color 79 | # for the user's input. 80 | radian_prompt_suffix='%(?.%{$fg[blue]%}.%{$fg[red]%}) %# %{$reset_color%}' 81 | 82 | PROMPT= 83 | 84 | if (( $+commands[git] )); then 85 | 86 | # Usage: radian_prompt_git_dirty 87 | # 88 | # Print an asterisk if the working directory is dirty. 89 | function radian_prompt_git_dirty { 90 | emulate -LR zsh 91 | if [[ $(command git status --porcelain 2>/dev/null | tail -n1) ]]; then 92 | echo "*" 93 | fi 94 | } 95 | 96 | # Usage: radian_prompt_git_info 97 | # 98 | # If inside a Git repository, print the branch or abbreviated 99 | # revision of the current HEAD, surrounded by square brackets and 100 | # followed by an asterisk if the working directory is dirty. 101 | function radian_prompt_git_info { 102 | emulate -LR zsh 103 | local ref 104 | ref=$(command git symbolic-ref HEAD 2> /dev/null) || \ 105 | ref=$(command git rev-parse --short HEAD 2> /dev/null) || \ 106 | return 0 107 | echo "[${ref#refs/heads/}$(radian_prompt_git_dirty)]" 108 | } 109 | 110 | # Reset the color and display the Git branch and modification 111 | # status. 112 | PROMPT='%{$reset_color%}$(radian_prompt_git_info)' 113 | 114 | fi 115 | 116 | PROMPT="${radian_prompt_prefix}${PROMPT}" 117 | PROMPT="${PROMPT}${radian_prompt_suffix}" 118 | 119 | ### Command line 120 | 121 | # Force the usage of Emacs keybindings. Otherwise they will be set 122 | # depending on whether the literal string "vi" appears in the value of 123 | # EDITOR, which is a terrible idea for many reasons (not least of 124 | # which being that my EDITOR is Vim while I want to use Emacs 125 | # keybindings in Zsh). 126 | bindkey -e 127 | 128 | # Allow a very fast way (just typing ".") to reload the shell 129 | # configuration. Based on [1]. 130 | # 131 | # [1]: https://unix.stackexchange.com/a/326948/176805 132 | function _accept-line { 133 | emulate -LR zsh 134 | if [[ $BUFFER == "." ]]; then 135 | BUFFER="exec zsh" 136 | fi 137 | zle .accept-line 138 | } 139 | zle -N accept-line _accept-line 140 | 141 | # Allow comments even in the interactive shell (start with #). 142 | setopt interactive_comments 143 | 144 | # Allow escaping a single quote within a singly-quoted string by 145 | # prefixing it with an additional single quote: echo 'It''s me!' 146 | setopt rc_quotes 147 | 148 | # Turn off flow control (which makes it so that ctrl+s and ctrl+q 149 | # freeze and unfreeze command output, respectively). 150 | unsetopt flow_control 151 | 152 | #### Completion 153 | 154 | # For a modern primer on zsh completion system configuration: 155 | # https://thevaluable.dev/zsh-completion-guide-examples/ 156 | 157 | # Display a list of the available candidates instead of just cycling 158 | # through them blindly. 159 | zstyle ':completion:*' menu select 160 | zstyle ':completion:*' matcher-list 'm:{a-z}={A-Za-z}' 161 | 162 | # If there is only one candidate just insert it. 163 | zstyle ':autocomplete:*complete*:*' insert-unambiguous yes 164 | 165 | # Allow usage of shift-tab (backtab) to go backward in the completion 166 | # menu. See . 167 | bindkey '^[[Z' reverse-menu-complete 168 | 169 | #### Globbing 170 | 171 | # This makes globs case-insensitive. 172 | unsetopt case_glob 173 | 174 | # This makes globbing regexes case-insensitive. 175 | unsetopt case_match 176 | 177 | # Allow globs to match dotfiles. 178 | setopt glob_dots 179 | 180 | # Sort numeric filenames numerically, instead of lexicographically. 181 | setopt numeric_glob_sort 182 | 183 | # Disable history expansion, so we can use ! in our commands. 184 | setopt no_bang_hist 185 | 186 | #### Command history 187 | 188 | # Never discard history within a session, or at least not before any 189 | # reasonable amount of time. 190 | HISTSIZE=1000000 191 | 192 | # Save history to disk. The value of this option is the default 193 | # installed by zsh-newuser-install. 194 | HISTFILE=~/.zsh_history 195 | 196 | # Never discard history in the file on disk, either. 197 | SAVEHIST=1000000 198 | 199 | # Don't save commands to the history if they start with a leading 200 | # space. This is useful if you have to pass a password as a parameter 201 | # to a command. 202 | setopt hist_ignore_space 203 | 204 | # All zsh sessions share the same history file. Timestamps are also 205 | # recorded for each command. 206 | setopt share_history 207 | 208 | # Use OS-provided locking mechanisms for the history file, if 209 | # available. The manual says this might improve performance and 210 | # decrease the chance of corruption. 211 | setopt hist_fcntl_lock 212 | 213 | # Remove superfluous whitespace when saving commands to the history. 214 | setopt hist_reduce_blanks 215 | 216 | # When history expansion is used (e.g. sudo !!), do the expansion 217 | # instead of executing the command immediately. This currently has no 218 | # effect since history expansion is disabled. 219 | setopt hist_verify 220 | 221 | # Deduplicate history entries. Helps with retrieving previous 222 | # commands. 223 | setopt hist_ignore_all_dups 224 | 225 | ### Filesystem navigation 226 | 227 | # This makes it so that when you cd to a new directory, the old 228 | # directory is saved in the directory stack (view with dirs or ds). 229 | setopt autopushd 230 | 231 | # This makes it so that "cd -n" gives you the directory you were in n 232 | # cd's ago, instead of the nth directory you have visited in the shell 233 | # session. (You can use "cd +n" to recover the latter behavior.) 234 | setopt pushdminus 235 | 236 | # This makes it so that the working directory path is automatically 237 | # fully resolved. This means that symlink components will be followed, 238 | # and capitalization will be corrected if you are on a 239 | # case-insensitive filesystem. 240 | setopt chaselinks 241 | 242 | # If you just type in a directory name, cd to it (unless it's also a 243 | # valid executable name). 244 | setopt autocd 245 | 246 | ### Help system 247 | 248 | # By default, run-help is an alias to man. We want to turn that off so 249 | # that we can access the function definition of run-help (by default, 250 | # aliases take precedence over functions). But if you re-source this 251 | # file, then the alias might already be removed, so we suppress any 252 | # error that this might throw. 253 | unalias run-help 2>/dev/null || true 254 | 255 | # Now we autoload run-help and several extensions to it which provide 256 | # more precise help for certain external commands. 257 | autoload -Uz run-help 258 | autoload -Uz run-help-git 259 | autoload -Uz run-help-ip 260 | autoload -Uz run-help-openssl 261 | autoload -Uz run-help-p4 262 | autoload -Uz run-help-sudo 263 | autoload -Uz run-help-svk 264 | autoload -Uz run-help-svn 265 | 266 | ## Aliases 267 | ### Filesystem navigation 268 | #### cd 269 | 270 | alias -- -='cd -' 271 | alias -- -1='cd -1' 272 | alias -- -2='cd -2' 273 | alias -- -3='cd -3' 274 | alias -- -4='cd -4' 275 | alias -- -5='cd -5' 276 | alias -- -6='cd -6' 277 | alias -- -7='cd -7' 278 | alias -- -8='cd -8' 279 | alias -- -9='cd -9' 280 | 281 | #### dirs 282 | 283 | # This alias is a convenient way to list the last few directories 284 | # visited, with their numbers. You can then use the 'cd -n' aliases to 285 | # jump to those directories. 286 | alias ds='dirs -v | head -10' 287 | 288 | #### ls, eza 289 | 290 | if (( $+commands[eza] )); then 291 | 292 | function l { 293 | emulate -LR zsh 294 | eza --all --header --long --color-scale=all $@ 295 | } 296 | 297 | function lg { 298 | emulate -LR zsh 299 | l --grid $@ 300 | } 301 | 302 | function lt { 303 | emulate -LR zsh 304 | l --tree --ignore-glob ".git|.svn|node_modules" $@ 305 | } 306 | 307 | function lti { 308 | emulate -LR zsh 309 | l --tree --ignore-glob ".git|.svn|node_modules|$1" ${@:2} 310 | } 311 | 312 | function ltl { 313 | emulate -LR zsh 314 | lt --level $@ 315 | } 316 | 317 | function ltli { 318 | l --tree --level $1 --ignore-glob ".git|.svn|node_modules|$2" ${@:3} 319 | } 320 | 321 | else 322 | # We alias gls to a git command elsewhere, so we use "command" 323 | # here to prevent it from being interpreted as said git command. 324 | if (( $+commands[gls] )); then 325 | alias l='command gls -AlhF --color=auto' 326 | else 327 | alias l='ls -AlhF' 328 | fi 329 | if (( $+commands[tree] )); then 330 | alias lt='tree -a' 331 | alias ltl='tree -aL' 332 | fi 333 | fi 334 | 335 | #### wdx 336 | 337 | if command -v wdx &>/dev/null; then 338 | alias wd='wdx' 339 | alias ws='wdx set' 340 | alias wsf='wdx set -f' 341 | fi 342 | 343 | ### Filesystem management 344 | 345 | #### cp, mv, ln 346 | 347 | # You can "copy" any number of files, then "paste", "move" or 348 | # "pasteln" them to pass them as arguments to cp, mv, or ln 349 | # respectively. Just like a graphical filesystem manager. Each of the 350 | # latter three functions defaults to the current directory as the 351 | # destination. 352 | 353 | # Usage: copy ... 354 | # 355 | # Copy all of the paths provided to the clipboard, stored in the array 356 | # $RADIAN_CLIPBOARD. 357 | function copy { 358 | emulate -LR zsh 359 | RADIAN_CLIPBOARD=() 360 | for target; do 361 | RADIAN_CLIPBOARD+=(${target:a}) 362 | done 363 | } 364 | 365 | # Usage: paste [] 366 | # 367 | # Invoke 'cp -R' on all paths in $RADIAN_CLIPBOARD as well as the 368 | # argument provided, which defaults to the current directory. 369 | function paste { 370 | emulate -LR zsh 371 | cp -R $RADIAN_CLIPBOARD ${1:-.} 372 | } 373 | 374 | # Usage: move [] 375 | # 376 | # Invoke 'mv' on all paths in $RADIAN_CLIPBOARD as well as the 377 | # argument provided, which defaults to the current directory. 378 | function move { 379 | emulate -LR zsh 380 | mv $RADIAN_CLIPBOARD ${1:-.} 381 | } 382 | 383 | # Usage: pasteln [] 384 | # 385 | # Invoke 'ln -s' on all paths in $RADIAN_CLIPBOARD as well as the 386 | # argument provided, which defaults to the current directory. 387 | function pasteln { 388 | emulate -LR zsh 389 | ln -s $RADIAN_CLIPBOARD ${1:-.} 390 | } 391 | 392 | # Usage: delink 393 | # 394 | # Resolve the symlink at the given path and replace it with a copy of 395 | # the file it points to. 396 | function delink { 397 | emulate -LR zsh 398 | if [[ -z $1 ]]; then 399 | echo >&2 "usage: delink " 400 | return 1 401 | fi 402 | for link; do 403 | if [[ -L $link ]]; then 404 | if [[ -e $link ]]; then 405 | target=${link:A} 406 | if rm $link; then 407 | if cp -R $target $link; then 408 | echo >&2 "Copied $target to $link" 409 | else 410 | ln -s $target $link 411 | fi 412 | fi 413 | else 414 | echo >&2 "Broken symlink: $link" 415 | fi 416 | else 417 | echo >&2 "Not a symlink: $link" 418 | fi 419 | done 420 | } 421 | 422 | # Usage: transpose 423 | # 424 | # Swap the files or directories at the two provided paths. Not atomic. 425 | # Both paths must exist. 426 | function transpose { 427 | emulate -LR zsh 428 | if (( $# != 2 )); then 429 | echo >&2 "usage: transpose " 430 | return 1 431 | fi 432 | for arg in $1 $2; do 433 | if [[ ! -e $arg && ! -L $arg ]]; then 434 | echo >&2 "no such file or directory: $arg" 435 | return 1 436 | fi 437 | if [[ -e $path.tmp || -L $path.tmp ]]; then 438 | echo >&2 "already exists: $path.tmp" 439 | return 1 440 | fi 441 | done 442 | mv $1 $1.tmp 443 | mv $2 $2.tmp 444 | mv $1.tmp $2 445 | mv $2.tmp $1 446 | } 447 | 448 | #### mkdir 449 | 450 | alias md='mkdir -p' 451 | 452 | function mcd { 453 | emulate -LR zsh 454 | mkdir -p $@ 455 | cd ${@[$#]} 456 | } 457 | 458 | compdef _mkdir mcd 459 | 460 | #### rmdir 461 | 462 | alias rd='rmdir' 463 | 464 | ### Help system 465 | 466 | alias help=run-help 467 | 468 | ### Utilities 469 | #### Docker 470 | 471 | if (( $+commands[docker] )); then 472 | alias dr='docker run -it --rm' 473 | fi 474 | 475 | #### Emacs 476 | 477 | if (( $+commands[emacs] )); then 478 | alias e='emacs -nw' 479 | alias eq='emacs -nw -Q' 480 | alias ew='emacs' 481 | alias eqw='emacs -Q' 482 | alias ue='e --init-directory=$PWD' 483 | alias uew='ew --init-directory=$PWD' 484 | fi 485 | 486 | if (( $+commands[emacsclient] )); then 487 | alias ec='emacsclient --alternate-editor= -nw' 488 | alias ecw='emacsclient --alternate-editor=' 489 | fi 490 | 491 | #### fd 492 | 493 | if (( $+commands[fdfind] )); then 494 | alias fd='fdfind' 495 | fi 496 | 497 | #### Git 498 | 499 | if (( $+commands[git] )); then 500 | alias g=git 501 | 502 | alias ge='git help' 503 | alias ghi='git help init' 504 | alias ghst='git help status' 505 | alias ghsh='git help show' 506 | alias ghl='git help log' 507 | alias gha='git help add' 508 | alias ghrm='git help rm' 509 | alias ghmv='git help mv' 510 | alias ghr='git help reset' 511 | alias ghcm='git help commit' 512 | alias ghcp='git help cherry-pick' 513 | alias ghrv='git help revert' 514 | alias ght='git help tag' 515 | alias ghn='git help notes' 516 | alias ghsta='git help stash' 517 | alias ghd='git help diff' 518 | alias ghbl='git help blame' 519 | alias ghb='git help branch' 520 | alias ghco='git help checkout' 521 | alias ghlsf='git help ls-files' 522 | alias ghx='git help clean' 523 | alias ghbs='git help bisect' 524 | alias ghm='git help merge' 525 | alias ghrb='git help rebase' 526 | alias ghsm='git help submodule' 527 | alias ghcl='git help clone' 528 | alias ghre='git help remote' 529 | alias ghf='git help fetch' 530 | alias ghu='git help pull' 531 | alias ghp='git help push' 532 | 533 | alias gi='git init' 534 | 535 | alias gst='git status' 536 | 537 | alias gsh='git show' 538 | alias gshs='git show --stat' 539 | 540 | for nograph in "" n; do 541 | local graph_flags= 542 | if [[ -z $nograph ]]; then 543 | graph_flags=" --graph" 544 | fi 545 | for all in "" a; do 546 | local all_flags= 547 | if [[ -n $all ]]; then 548 | all_flags=" --all" 549 | fi 550 | for oneline in "" o; do 551 | local oneline_flags= 552 | if [[ -n $oneline ]]; then 553 | oneline_flags=" --oneline" 554 | fi 555 | for diff in "" s p ps sp; do 556 | local diff_flags= 557 | case $diff in 558 | s) diff_flags=" --stat";; 559 | p) diff_flags=" --patch";; 560 | ps|sp) diff_flags=" --patch --stat";; 561 | esac 562 | for search in "" g G S; do 563 | local search_flags= 564 | case $search in 565 | g) search_flags=" --grep";; 566 | G) search_flags=" -G";; 567 | S) search_flags=" -S";; 568 | esac 569 | alias="gl${nograph}${all}${oneline}${diff}${search}=" 570 | alias+="git log --decorate" 571 | alias+="${graph_flags}${all_flags}" 572 | alias+="${oneline_flags}${diff_flags}${search_flags}" 573 | alias $alias 574 | done 575 | done 576 | done 577 | done 578 | done 579 | 580 | alias ga='git add' 581 | alias gap='git add --patch' 582 | alias gaa='git add --all' 583 | 584 | alias grm='git rm' 585 | 586 | alias gmv='git mv' 587 | 588 | alias gr='git reset' 589 | alias grs='git reset --soft' 590 | alias grh='git reset --hard' 591 | alias grp='git reset --patch' 592 | 593 | alias gc='git commit --verbose' 594 | alias gca='git commit --verbose --amend' 595 | alias gcaa='git commit --verbose --amend --all' 596 | alias gcf='git commit -C HEAD --amend' 597 | alias gcfa='git commit -C HEAD --amend --all' 598 | alias gce='git commit --verbose --allow-empty' 599 | alias gcm='git commit -m' 600 | alias gcma='git commit --all -m' 601 | alias gcam='git commit --amend -m' 602 | alias gcama='git commit --amend --all -m' 603 | alias gcem='git commit --allow-empty -m' 604 | 605 | alias gcn='git commit --no-verify --verbose' 606 | alias gcna='git commit --no-verify --verbose --amend' 607 | alias gcnaa='git commit --no-verify --verbose --amend --all' 608 | alias gcnf='git commit --no-verify -C HEAD --amend' 609 | alias gcnfa='git commit --no-verify -C HEAD --amend --all' 610 | alias gcne='git commit --no-verify --verbose --allow-empty' 611 | alias gcnm='git commit --no-verify -m' 612 | alias gcnma='git commit --no-verify --all -m' 613 | alias gcnam='git commit --no-verify --amend -m' 614 | alias gcnama='git commit --no-verify --amend --all -m' 615 | alias gcnem='git commit --no-verify --allow-empty -m' 616 | 617 | alias gcp='git cherry-pick' 618 | alias gcpc='git cherry-pick --continue' 619 | alias gcpa='git cherry-pick --abort' 620 | 621 | alias grv='git revert' 622 | alias grva='git revert --abort' 623 | alias grvm='git revert -m' 624 | 625 | alias gt='git tag' 626 | alias gtd='git tag --delete' 627 | 628 | alias gn='git notes' 629 | alias gna='git notes add' 630 | alias gne='git notes edit' 631 | alias gnr='git notes remove' 632 | 633 | alias gsta='git stash save' 634 | alias gstau='git stash save --include-untracked' 635 | alias gstap='git stash save --patch' 636 | alias gstl='git stash list' 637 | alias gsts='git stash show --text' 638 | alias gstss='git stash show --stat' 639 | alias gstaa='git stash apply' 640 | alias gstp='git stash pop' 641 | alias gstd='git stash drop' 642 | 643 | alias gd='git diff --minimal' 644 | alias gds='git diff --minimal --stat' 645 | alias gdc='git diff --minimal --cached' 646 | alias gdcs='git diff --minimal --cached --stat' 647 | alias gdn='git diff --minimal --no-index' 648 | 649 | alias gbl='git blame' 650 | 651 | alias gb='git branch' 652 | alias gbsu='git branch --set-upstream-to' 653 | alias gbusu='git branch --unset-upstream' 654 | alias gbd='git branch --delete' 655 | alias gbdd='git branch --delete --force' 656 | 657 | alias gco='git checkout' 658 | alias gcot='git checkout --track' 659 | alias gcop='git checkout --patch' 660 | alias gcob='git checkout -B' 661 | 662 | alias glsf='git ls-files' 663 | 664 | alias gx='git clean' 665 | alias gxu='git clean -ffd' 666 | alias gxi='git clean -ffdX' 667 | alias gxa='git clean -ffdx' 668 | 669 | alias gbs='git bisect' 670 | alias gbss='git bisect start' 671 | alias gbsg='git bisect good' 672 | alias gbsb='git bisect bad' 673 | alias gbsr='git bisect reset' 674 | 675 | alias gm='git merge' 676 | alias gma='git merge --abort' 677 | 678 | alias grb='git rebase' 679 | alias grbi='git rebase --interactive' 680 | alias grbc='git rebase --continue' 681 | alias grbs='git rebase --skip' 682 | alias grba='git rebase --abort' 683 | 684 | alias gsm='git submodule' 685 | alias gsma='git submodule add' 686 | alias gsms='git submodule status' 687 | alias gsmi='git submodule init' 688 | alias gsmd='git submodule deinit' 689 | alias gsmu='git submodule update --recursive' 690 | alias gsmui='git submodule update --init --recursive' 691 | alias gsmf='git submodule foreach' 692 | alias gsmy='git submodule sync' 693 | 694 | alias gcl='git clone --recursive' 695 | alias gcls='git clone --depth=1 --single-branch --no-tags' 696 | 697 | alias gre='git remote' 698 | alias grel='git remote list' 699 | alias gres='git remote show' 700 | 701 | alias gf='git fetch' 702 | alias gfa='git fetch --all' 703 | alias gfu='git fetch --unshallow' 704 | alias gfp='git fetch --prune' 705 | 706 | alias gu='git pull' 707 | alias gur='git pull --rebase --autostash' 708 | alias gum='git pull --no-rebase' 709 | alias gup='git pull --prune' 710 | 711 | alias gp='git push' 712 | alias gpa='git push --all' 713 | alias gpf='git push --force-with-lease' 714 | alias gpff='git push --force' 715 | alias gpu='git push --set-upstream' 716 | alias gpd='git push --delete' 717 | alias gpt='git push --tags' 718 | fi 719 | 720 | #### Tmux 721 | 722 | if (( $+commands[tmux] )); then 723 | alias ta='tmux attach' 724 | function ts { 725 | tmux attach -t ${1:-tmux} 2>/dev/null || tmux new-session -s ${1:-tmux} 726 | } 727 | fi 728 | 729 | #### Trash 730 | 731 | if (( $+commands[trash] )); then 732 | alias t='trash' 733 | fi 734 | 735 | #### Vi, Vim, Neovim 736 | 737 | if (( $+commands[nvim] )); then 738 | alias v='nvim' 739 | elif (( $+commands[vim] )); then 740 | alias v='vim' 741 | elif (( $+commands[vi] )); then 742 | alias v='vi' 743 | fi 744 | 745 | ## External command configuration 746 | ### man 747 | 748 | # We define a function that wraps man to provide some basic 749 | # highlighting for man pages. This makes them a little easier on the 750 | # eyes. (This is done by binding some environment variables that less 751 | # looks at.) See [1]. 752 | # 753 | # [1]: https://github.com/robbyrussell/oh-my-zsh/blob/3ebbb40b31fa1ce9f10040742cdb06ea04fa7c41/plugins/colored-man-pages/colored-man-pages.plugin.zsh 754 | function man { 755 | env \ 756 | LESS_TERMCAP_mb=$(printf "\e[1;31m") \ 757 | LESS_TERMCAP_md=$(printf "\e[1;31m") \ 758 | LESS_TERMCAP_me=$(printf "\e[0m") \ 759 | LESS_TERMCAP_ue=$(printf "\e[0m") \ 760 | LESS_TERMCAP_us=$(printf "\e[1;32m") \ 761 | man $@ 762 | } 763 | 764 | ## External configuration hook 765 | 766 | if typeset -f radian_after_init_hook > /dev/null; then 767 | radian_after_init_hook 768 | fi 769 | 770 | ## Closing remarks 771 | 772 | # Local Variables: 773 | # outline-regexp: "##+" 774 | # End: 775 | -------------------------------------------------------------------------------- /tmux/.tmux.conf: -------------------------------------------------------------------------------- 1 | ## Unbreak things 2 | 3 | # Prevent tmux from messing up keybindings and colors. 4 | # This is witchcraft, I have no explanation for the following commands. 5 | set-option -g xterm-keys on 6 | set-window-option -g xterm-keys on 7 | set-option -g default-terminal "xterm-256color" 8 | 9 | # Prevent tmux from waiting half a second before processing the ESC key, see: 10 | # http://unix.stackexchange.com/a/25638/176805 11 | set-option -s escape-time 0 12 | 13 | # Enable proper mouse support: 14 | # http://www.hamvocke.com/blog/a-guide-to-customizing-your-tmux-conf/ 15 | set-option -g mouse on 16 | 17 | # The following line prevents a weird OS X problem that otherwise 18 | # keeps the "open" command from working (and has several other 19 | # undesirable properties; see issue #120). For more details on the 20 | # issue, see [1]-[5]. 21 | # 22 | # The exact version of the solution below is the only way I have found 23 | # to satisfy all of the following properties: 24 | # 25 | # * It fixes the problem, i.e. "open" works correctly. 26 | # 27 | # * When opening a new window in tmux, the window name is correctly 28 | # set to zsh initially. It does not briefly flash 29 | # "reattach-to-user-namespace", and it does not display 30 | # "/usr/local/bin/zsh" either. 31 | # 32 | # * The "automatic-rename" property is still set to "on" in new tmux 33 | # windows, meaning that if you run another program, the window name 34 | # will change to reflect that (unless you manually rename the 35 | # window). 36 | # 37 | # * Exiting the shell (e.g. with Control+D) will immediately kill the 38 | # tmux window instead of dropping you into another shell. 39 | # 40 | # * It works for all shells, and doesn't hardcode any particular one. 41 | # 42 | # * It still works when reattach-to-user-namespace is unavailable. 43 | # 44 | # Yes, it's horrible. I think we can all agree on that, no need to 45 | # point it out. 46 | # 47 | # Unfortunately, tmux appears to be remarkably unintelligent when it 48 | # comes to determining the string to show as the window title. 49 | # Basically, about as unintelligent as shebang parsing, and anyone 50 | # involved in the virtualenv-can't-handle-spaces fiasco will know 51 | # that's pretty darn unintelligent. In particular, it grabs characters 52 | # literally from the beginning of the command string until it hits a 53 | # space, then discards until the first slash, if there is one. This 54 | # means it's impossible to quote the executable name, so if your shell 55 | # has spaces in its name, you're screwed. Making this whole fiasco 56 | # work for paths with double quotes in it is an exercise in futility, 57 | # I think. 58 | # 59 | # [1]: http://superuser.com/q/834525/326239 60 | # [2]: http://www.economyofeffort.com/2013/07/29/reattach-to-user-namespace-the-fix-for-your-tmux-in-os-x-woes/ 61 | # [3]: https://www.elmund.io/osx/2015/07/10/open-command-in-osx-tmux/ 62 | # [4]: https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard 63 | # [5]: https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard/issues/10 64 | 65 | run-shell '\ 66 | command -v reattach-to-user-namespace >/dev/null && \ 67 | tmux set-option -g default-command \ 68 | "$SHELL -c \"reattach-to-user-namespace -l \\\"$(basename "$SHELL")\\\"\"" \ 69 | || true' 70 | 71 | ## Keybindings 72 | 73 | # Use ` instead of C-b as prefix key, see: 74 | # http://www.hamvocke.com/blog/a-guide-to-customizing-your-tmux-conf/ 75 | unbind-key C-b 76 | set-option -g prefix ` 77 | bind-key ` send-prefix 78 | 79 | # Force tmux to use Emacs keybindings, see: 80 | # http://stackoverflow.com/q/18240683/3538165 81 | # http://stackoverflow.com/a/18247437/3538165 82 | set-option -g status-keys emacs 83 | set-window-option -g mode-keys emacs 84 | 85 | # Turn off repeatability for moving between panes. Otherwise, if you split 86 | # horizontally and switch panes, you will have to wait for the 'repeat period' 87 | # to expire before you can use and to page through shell history. 88 | # 89 | # Doing it this way instead of using 'set-option -g repeat-time 0' makes it 90 | # so that Control+Arrows and Meta+Arrows (for resizing panes) are still 91 | # repeatable. 92 | # 93 | # See: http://superuser.com/a/325579/326239 94 | bind-key Up select-pane -U 95 | bind-key Down select-pane -D 96 | bind-key Left select-pane -L 97 | bind-key Right select-pane -R 98 | 99 | # Keybinding for reloading .tmux.conf. 100 | bind-key R source-file ~/.tmux.conf 101 | 102 | # Keybinding for swapping the current and marked windows. 103 | bind-key '\' swap-window 104 | 105 | # Keybindings for swapping adjacent windows. 106 | bind-key < run-shell "if [ #{window_index} -gt 1 ]; then \ 107 | tmux swap-window -d -t -1; fi" 108 | 109 | bind-key > run-shell "if [ #{window_index} -lt #{session_windows} ]; then \ 110 | tmux swap-window -d -t +1; fi" 111 | 112 | # Keybinding for inserting a window. 113 | # Adapted from http://superuser.com/a/704551/326239 114 | bind-key I command-prompt -p 'Insert window at:' ' \ 115 | run-shell " \ 116 | if tmux select-window -t %1; then \ 117 | tmux new-window -a; \ 118 | tmux swap-window -s %1 -t \$((%1+1)); \ 119 | else \ 120 | tmux new-window; \ 121 | tmux move-window -t %1; \ 122 | fi; \ 123 | tmux select-window -t #{window_id}; \ 124 | tmux select-window -t %1; \ 125 | "' 126 | 127 | ## Status bar 128 | 129 | # The following code is adapted from: 130 | # https://coderwall.com/p/trgyrq/make-your-tmux-status-bar-responsive 131 | # It provides the same appearance as https://github.com/powerline/powerline, 132 | # but sidesteps the environment/configuration hell which that project 133 | # introduces. 134 | 135 | # Format to display on the left-hand side of the status bar. 136 | # Note that the conditional #{?cond,true,false} operator does not do any 137 | # fancy parsing, so you can't have literal commas in the conditions -- 138 | # this will cause the conditions to be split up. So we have to use multiple 139 | # style #[attr=value] directives. 140 | set-option -g status-left '\ 141 | #{?client_prefix,\ 142 | #[fg=colour254]#[bg=colour31],\ 143 | #[fg=colour16]#[bg=colour254]#[bold]}\ 144 | #{=80:session_name}\ 145 | #{?client_prefix,\ 146 | #[fg=colour31],\ 147 | #[fg=colour254]}\ 148 | #[bg=colour234,nobold] ' 149 | 150 | # Maximum length of the format displayed on the left-hand side. 151 | # Since the maximum length of the session name is limited in the above 152 | # format string, this number is unimportant -- it just needs to be a 153 | # bit larger than what is allocated for the session name, to allow for 154 | # the surrounding characters. 155 | set-option -g status-left-length 90 156 | 157 | # Format to display on the right-hand side of the status bar. 158 | set-option -g status-right '' 159 | 160 | # Format to display for the current window. 161 | set-option -g window-status-current-format "\ 162 | #[fg=colour117,bg=colour31] #{window_index}#{window_flags} \ 163 | #[fg=colour231,bold]#{window_name} #[fg=colour31,bg=colour234,nobold] " 164 | 165 | # Format to display for other windows. 166 | set-option -g window-status-format "\ 167 | #[fg=colour244,bg=colour234]#{window_index}#{window_flags} \ 168 | #[fg=colour249]#{window_name} " 169 | 170 | # Background color for parts of the status bar not specified by the above 171 | # formats. For instance, the empty space to the right, and the single 172 | # spaces between instances of window-status-format. 173 | set-option -g status-bg colour234 174 | 175 | # Inhibit the default styling for windows with unseen activity, which 176 | # looks blatantly incorrect with the "powerline" theme we are trying to 177 | # emulate. 178 | set-window-option -g window-status-activity-style none 179 | set-window-option -g window-status-activity-style none 180 | 181 | # Update the status bar every second, instead of the default 15(!) 182 | # seconds. It doesn't look like it's possible to update more than 183 | # once per second, unfortunately. 184 | set-option -g status-interval 1 185 | 186 | ## Appearance 187 | 188 | # Show an indicator in the status bar on windows with unseen activity. 189 | set-option -g monitor-activity on 190 | 191 | # Make the borders of the current pane the same color as the borders 192 | # of other panes. This is because the borders of the marked pane are 193 | # *inverted*, and while different foreground colors in different parts 194 | # of the frame are not too objectionable, different background colors 195 | # look very bad. 196 | set-option -g pane-active-border-style none 197 | 198 | ## Miscellaneous 199 | 200 | # When the current session is killed, switch to another session instead of 201 | # detaching. 202 | set-option -g detach-on-destroy off 203 | 204 | # Show messages until they are dismissed, instead of for 750 milliseconds(!). 205 | # Actually it is only for an hour, because it doesn't seem like you can turn 206 | # off the time limit. 207 | set-option -g display-time 36000000 208 | 209 | # Open new windows in the same directory as the current pane. 210 | bind-key c new-window -c "#{pane_current_path}" 211 | 212 | # Automatically renumber windows when one is deleted, see: 213 | # http://unix.stackexchange.com/a/51879/176805 214 | set-option -g renumber-windows on 215 | 216 | # Number windows and panes from 1, instead of 0; see: 217 | # http://unix.stackexchange.com/a/35932/176805 218 | set-option -g base-index 1 219 | set-window-option -g pane-base-index 1 220 | 221 | # Open new panes in the same directory as the current pane. 222 | bind-key % split-window -h -c "#{pane_current_path}" 223 | bind-key '"' split-window -v -c "#{pane_current_path}" 224 | 225 | # Increase the scrollback buffer size from 2000 to a larger size, but 226 | # not one so large that tmux begins to lag. 227 | set-option -g history-limit 10000 228 | 229 | ## Local overrides 230 | 231 | if-shell "[[ -f ~/.tmux.local.conf ]]" "source ~/.tmux.local.conf" 232 | 233 | # Local Variables: 234 | # outline-regexp: "##+ " 235 | # End: 236 | --------------------------------------------------------------------------------