├── .config ├── fish │ ├── config.fish │ ├── fish_plugins │ └── functions │ │ └── fish_title.fish ├── git │ ├── config │ └── ignore └── nvim │ └── init.lua ├── .git-templates └── hooks │ └── pre-commit ├── .ideavimrc ├── .ignore ├── .local └── share │ └── applications │ └── org.gnome.Terminal.desktop ├── .npmrc ├── .pam_environment ├── LinkHints.json ├── README.md ├── bin ├── backup ├── e ├── git-branches ├── git-done ├── git-main ├── git-pr ├── git-trash ├── pre ├── release ├── tw └── x ├── programs.txt └── vscode ├── keybindings.json └── settings.json /.config/fish/config.fish: -------------------------------------------------------------------------------- 1 | set -g fish_greeting 2 | set -gx LANG "en_US.UTF-8" 3 | fish_hybrid_key_bindings 4 | eval (/opt/homebrew/bin/brew shellenv) 5 | complete -c e -c pre -w rg 6 | zoxide init fish --cmd c | source 7 | fzf_configure_bindings --directory=\ct --git_log=\cg --git_status=\cs --processes=\co 8 | set fzf_preview_dir_cmd eza --all --color=always 9 | set fzf_history_time_format %Y-%m-%d 10 | set tide_git_truncation_length 48 11 | 12 | function __nvm_auto --on-variable PWD 13 | nvm use --silent 2>/dev/null 14 | if test -d .idea || test -d ../.idea 15 | set -x ELM_WATCH_OPEN_EDITOR '/Applications/Rider.app/Contents/MacOS/rider --line "$line" --column "$((column - 1))" "$file"' 16 | else 17 | set -x ELM_WATCH_OPEN_EDITOR 'code --goto "$file:$line:$column"' 18 | end 19 | end 20 | __nvm_auto 21 | 22 | if test (uname) = Linux 23 | abbr pbcopy 'xclip -selection clipboard' 24 | abbr pbpaste 'xclip -selection clipboard -o' 25 | end 26 | abbr pbqr 'pbpaste | qrencode -o - -t UTF8' 27 | 28 | abbr do docker 29 | abbr dc 'docker compose' 30 | abbr l eza 31 | abbr la 'eza --no-user --icons -lah' 32 | abbr R 'less -R' 33 | 34 | set g '' 35 | if test (uname) = Darwin 36 | set g g 37 | end 38 | abbr rm $g'rm -Id' 39 | abbr cp $g'cp -r' 40 | abbr mv $g'mv -i' 41 | abbr mkdir $g'mkdir -p' 42 | 43 | abbr gri 'git rebase -i' 44 | abbr grc 'git rebase --continue' 45 | abbr s 'git status' 46 | abbr d 'git diff' 47 | abbr ds 'git diff --staged' 48 | abbr g git 49 | abbr ga 'git add' 50 | abbr gamd 'git commit -a --amend --no-edit' 51 | abbr gb 'git blame' 52 | abbr gbr 'git branch' 53 | abbr gci 'git commit' 54 | abbr gcl 'git clone' 55 | abbr gl 'git log' 56 | abbr glp 'git log -p' 57 | abbr gm 'git merge' 58 | abbr gp 'git pull' 59 | abbr gr 'git restore' 60 | abbr grs 'git restore --staged' 61 | abbr gs 'git show' 62 | abbr gst 'git stash' 63 | abbr gu 'git push' 64 | abbr gw 'git switch' 65 | abbr --position anywhere mäin '(git main)' 66 | 67 | # Must be last 68 | source ~/.iterm2_shell_integration.fish 69 | -------------------------------------------------------------------------------- /.config/fish/fish_plugins: -------------------------------------------------------------------------------- 1 | jorgebucaran/fisher 2 | jorgebucaran/nvm.fish 3 | ilancosman/tide@v6 4 | patrickf1/fzf.fish 5 | -------------------------------------------------------------------------------- /.config/fish/functions/fish_title.fish: -------------------------------------------------------------------------------- 1 | function fish_title -a command 2 | if test -z "$command" 3 | string replace $HOME '~' $PWD 4 | else 5 | echo -s (basename $PWD) ": $command" 6 | end 7 | end -------------------------------------------------------------------------------- /.config/git/config: -------------------------------------------------------------------------------- 1 | [user] 2 | name = Simon Lydell 3 | email = simon.lydell@gmail.com 4 | [core] 5 | editor = nvim 6 | pager = delta --diff-so-fancy 7 | [interactive] 8 | diffFilter = delta --color-only 9 | singleKey = true 10 | [delta] 11 | features = side-by-side line-numbers decorations navigate 12 | tabs = 2 13 | [diff] 14 | colorMoved = default 15 | colorMovedWS = allow-indentation-change 16 | algoritm = histogram 17 | [branch] 18 | sort = -committerdate 19 | [push] 20 | default = current 21 | autoSetupRemote = true 22 | [log] 23 | date = iso 24 | [init] 25 | defaultBranch = main 26 | templatedir = ~/src/dotfiles/.git-templates 27 | [rebase] 28 | missingCommitsCheck = error 29 | [rerere] 30 | enabled = true 31 | autoupdate = true 32 | [merge] 33 | conflictstyle = zdiff3 34 | [pull] 35 | ff = only 36 | [stash] 37 | showIncludeUntracked = true 38 | showPatch = true 39 | [advice] 40 | statusHints = false 41 | [includeIf "gitdir:~/in/"] 42 | path = ~/in/.gitconfig 43 | -------------------------------------------------------------------------------- /.config/git/ignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | .stuff 4 | .vscode 5 | .ignore 6 | .DS_Store 7 | .node-version 8 | -------------------------------------------------------------------------------- /.config/nvim/init.lua: -------------------------------------------------------------------------------- 1 | -- Copied from: https://lazy.folke.io/installation (Single File Setup) 2 | local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" 3 | if not (vim.uv or vim.loop).fs_stat(lazypath) then 4 | local lazyrepo = "https://github.com/folke/lazy.nvim.git" 5 | local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) 6 | if vim.v.shell_error ~= 0 then 7 | vim.api.nvim_echo({ 8 | { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, 9 | { out, "WarningMsg" }, 10 | { "\nPress any key to exit..." }, 11 | }, true, {}) 12 | vim.fn.getchar() 13 | os.exit(1) 14 | end 15 | end 16 | vim.opt.rtp:prepend(lazypath) 17 | 18 | -- Change from backslash to space. 19 | -- First unmap space, so it never moves forward after a delay. 20 | vim.keymap.set("n", "", "", { silent = true, remap = false }) 21 | vim.g.mapleader = " " 22 | vim.g.maplocalleader = " " 23 | 24 | -- Enable CamelCaseMotion using . 25 | vim.g.camelcasemotion_key = "" 26 | 27 | -- Default indentation settings. 28 | vim.opt.expandtab = true 29 | vim.opt.shiftwidth = 2 30 | vim.opt.tabstop = 2 31 | 32 | -- Enable line numbers. 33 | vim.opt.number = true 34 | 35 | -- Use system clipboard by default. 36 | -- Setting it this weird way is apparently faster: https://github.com/LazyVim/LazyVim/discussions/4112 37 | vim.schedule(function() 38 | vim.opt.clipboard = "unnamedplus" 39 | end) 40 | 41 | -- Indent soft-wrapped lines. 42 | vim.opt.breakindent = true 43 | 44 | -- Case-insensitive searching unless \C or one or more capital letters in the search term. 45 | vim.opt.ignorecase = true 46 | vim.opt.smartcase = true 47 | 48 | -- Put new splits to the right and below the current. 49 | vim.opt.splitright = true 50 | vim.opt.splitbelow = true 51 | 52 | -- Show whitespace. 53 | vim.opt.list = true 54 | vim.opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" } 55 | 56 | -- Clear search highlight. 57 | vim.keymap.set("n", "", "nohlsearch") 58 | 59 | -- Use ctrl+ to switch between splits. 60 | vim.keymap.set("n", "", "") 61 | vim.keymap.set("n", "", "") 62 | vim.keymap.set("n", "", "") 63 | vim.keymap.set("n", "", "") 64 | 65 | -- Show file explorer by pressing `-`. Put the original `-` on `_` instead. 66 | if not vim.g.vscode then 67 | vim.keymap.set("n", "-", "Oil") 68 | end 69 | vim.keymap.set("n", "_", "-") 70 | 71 | -- Go back and forward with backspace. 72 | vim.keymap.set("n", "", "") 73 | vim.keymap.set("n", "", "") 74 | 75 | -- Highlight yanked text. 76 | vim.api.nvim_create_autocmd("TextYankPost", { 77 | callback = function() vim.highlight.on_yank({ timeout = 200 }) end, 78 | }) 79 | 80 | -- VSCode specific. 81 | if vim.g.vscode then 82 | local vscode = require("vscode") 83 | 84 | -- Avoid the Output panel opening when using Sneak. 85 | vim.opt.cmdheight = 4 86 | 87 | -- Go to next and previous error in the current file. 88 | vim.keymap.set({ "n", "x" }, "j", function () 89 | vscode.action("editor.action.marker.next") 90 | end) 91 | vim.keymap.set({ "n", "x" }, "k", function () 92 | vscode.action("editor.action.marker.prev") 93 | end) 94 | 95 | -- Multiple cursors only really works in Insert Mode unfortunately. 96 | -- This makes cmd+d usable from Normal mode (but you can only use insert mode). 97 | -- https://github.com/vscode-neovim/vscode-neovim#vscodewith_insertcallback 98 | vim.keymap.set({ "n", "x", "i" }, "", function() 99 | vscode.with_insert(function() 100 | vscode.action("editor.action.addSelectionToNextFindMatch") 101 | end) 102 | end) 103 | end 104 | 105 | -- The lazy.nvim docs recommend configuring stuff before loading the plugins where possible. 106 | require("lazy").setup({ 107 | spec = { 108 | { 109 | -- Colorscheme loaded as described in https://lazy.folke.io/spec/examples 110 | "Mofiqul/vscode.nvim", 111 | lazy = false, 112 | priority = 1000, 113 | cond = not vim.g.vscode, 114 | config = function() 115 | vim.cmd([[colorscheme vscode]]) 116 | end, 117 | }, 118 | 119 | -- Using this for its expand/shrink selection commands. 120 | { 121 | "nvim-treesitter/nvim-treesitter", 122 | build = ":TSUpdate", 123 | config = function () 124 | local configs = require("nvim-treesitter.configs") 125 | 126 | configs.setup({ 127 | ensure_installed = { "bash", "css", "csv", "diff", "dockerfile", "elm", "fish", "gleam", "haskell", "html", "javascript", "jsdoc", "json", "lua", "luadoc", "make", "markdown", "markdown_inline", "python", "regex", "sql", "tsv", "tsx", "typescript", "vim", "vimdoc", "xml", "yaml" }, 128 | highlight = { 129 | enable = not vim.g.vscode, 130 | }, 131 | incremental_selection = { 132 | enable = true, 133 | keymaps = { 134 | init_selection = "h", 135 | node_incremental = "h", -- higher 136 | node_decremental = "l", -- lower 137 | }, 138 | }, 139 | }) 140 | end, 141 | }, 142 | 143 | -- Motions for “falling down or up”. Like W and B, but vertically. 144 | -- Originally from Vim Mode Plus for Atom. 145 | { 146 | "pchampio/vim-edgemotion", 147 | config = function() 148 | vim.keymap.set("n", "ö", "(edgemotion-j)") 149 | vim.keymap.set("n", "Ö", "(edgemotion-k)") 150 | end, 151 | }, 152 | 153 | -- Don’t move the cursor after yanking. 154 | { 155 | "svban/YankAssassin.nvim", 156 | opts = { 157 | auto_normal = true, 158 | auto_visual = true, 159 | }, 160 | }, 161 | 162 | -- File explorer. 163 | { 164 | "stevearc/oil.nvim", 165 | opts = { 166 | view_options = { 167 | show_hidden = true, 168 | }, 169 | }, 170 | cond = not vim.g.vscode, 171 | }, 172 | 173 | -- Add (ys), remove (ds) and change (cs) parentheses and similar around things. 174 | -- In visual mode: S. 175 | { "kylechui/nvim-surround", opts = {} }, 176 | 177 | -- Changes s to a two-letter f. 178 | "justinmk/vim-sneak", 179 | 180 | -- Swap two pieces of text, with cx. 181 | -- In visual mode: X. 182 | "tommcdo/vim-exchange", 183 | 184 | -- Makes { and } work even if a blank line contains spaces. 185 | "dbakker/vim-paragraph-motion", 186 | 187 | -- Makes ga print unicode info about the character under the cursor. 188 | "tpope/vim-characterize", 189 | 190 | -- Guesses indentation settings. 191 | "tpope/vim-sleuth", 192 | 193 | -- Camel case motions: w/b/e/ge 194 | "bkad/CamelCaseMotion", 195 | }, 196 | }) 197 | 198 | ----- Yank and paste with indent handling ----- 199 | 200 | local function get_smallest_indent(lines) 201 | smallest_indent = nil 202 | for _, line in ipairs(lines) do 203 | match = line:match("^%s*%S") 204 | if match then 205 | indent = match:sub(1, -2) 206 | if smallest_indent then 207 | if #indent < #smallest_indent then 208 | smallest_indent = indent 209 | end 210 | else 211 | smallest_indent = indent 212 | end 213 | end 214 | end 215 | return smallest_indent 216 | end 217 | 218 | local function get_indent_for_cursor_column(cursor_indentation) 219 | -- The indent char to use once the cursor indentation runs out: 220 | -- The last char of the indentation, or a space or tab depending on options. 221 | local last_indentation_char = cursor_indentation:sub(-1) 222 | if last_indentation_char == "" then 223 | if vim.opt.expandtab then 224 | last_indentation_char = " " 225 | else 226 | last_indentation_char = "\t" 227 | end 228 | end 229 | 230 | local tabstop = vim.o.tabstop 231 | 232 | -- By default, `virtcol` returns the virtual column at the _end_ of tabs. 233 | -- By passing the second argument, it returns both the start and end. 234 | -- We’re interested in the start. 235 | local cursor = vim.fn.virtcol(".", 1)[1] - 1 236 | 237 | local indentation_index = 1 238 | local indent_length = 0 239 | local indent = "" 240 | 241 | while indent_length < cursor do 242 | -- If we’re still in the cursor indentation, take the next char from there. 243 | local char = last_indentation_char 244 | if indentation_index <= #cursor_indentation then 245 | char = cursor_indentation:sub(indentation_index, indentation_index) 246 | indentation_index = indentation_index + 1 247 | end 248 | 249 | if char == "\t" then 250 | -- If a tab fits, use it. 251 | if indent_length + tabstop <= cursor then 252 | indent = indent .. char 253 | indent_length = indent_length + tabstop 254 | else 255 | -- Otherwise fill the rest with spaces. 256 | indent = indent .. string.rep(" ", cursor - indent_length) 257 | indent_length = indent_length + cursor - indent_length 258 | end 259 | else 260 | -- All other whitespace is assumed to be of length 1. 261 | indent = indent .. char 262 | indent_length = indent_length + 1 263 | end 264 | end 265 | 266 | return indent 267 | end 268 | 269 | -- Yank and remove the shortest indent from each line. 270 | local function yank() 271 | -- Get the start and end of the motion range. 272 | local start_pos = vim.api.nvim_buf_get_mark(0, "[") 273 | local end_pos = vim.api.nvim_buf_get_mark(0, "]") 274 | 275 | -- Retrieve the text in the selected range. 276 | local lines = vim.api.nvim_buf_get_lines(0, start_pos[1] - 1, end_pos[1], false) 277 | 278 | local regtype = vim.fn.getregtype() 279 | 280 | -- Don’t change indentation in any way if the text is characterwise and just one line. 281 | if #lines <= 1 and regtype == "v" then 282 | return 283 | end 284 | 285 | local indent = get_smallest_indent(lines) 286 | if not indent then 287 | return 288 | end 289 | 290 | for i, line in ipairs(lines) do 291 | if regtype == "v" and i == 1 then 292 | lines[i] = line:sub(start_pos[2] + 1) 293 | elseif regtype == "v" and i == #lines then 294 | lines[i] = line:sub(#indent + 1, end_pos[2] + 1) 295 | else 296 | lines[i] = line:sub(#indent + 1) 297 | end 298 | end 299 | 300 | -- Overwrite the register we just yanked into (this runs after all yanks – also deletes). 301 | vim.fn.setreg(vim.v.register, lines, regtype) 302 | end 303 | 304 | -- Paste and re-indent each line. 305 | local function paste(command, linewise_at_column) 306 | local pasted = vim.fn.getreg(vim.v.register, 1, 1) 307 | 308 | local regtype = "" 309 | if linewise_at_column then 310 | regtype = "V" 311 | else 312 | regtype = vim.fn.getregtype() 313 | end 314 | 315 | -- Don’t change indentation in any way if the text is characterwise and just one line. 316 | if #pasted <= 1 and regtype == "v" then 317 | vim.cmd('normal! "' .. vim.v.register .. command) 318 | return 319 | end 320 | 321 | -- These correspond to the first or last line depending on whether you selected up or down. 322 | local v_start = vim.fn.getpos("v")[2] 323 | local v_end = vim.fn.getpos(".")[2] 324 | local selection = vim.api.nvim_buf_get_lines(0, math.min(v_start, v_end) - 1, math.max(v_start, v_end), true) 325 | 326 | local selection_indent = "" 327 | if linewise_at_column and vim.api.nvim_get_mode().mode == "n" then 328 | selection_indent = get_indent_for_cursor_column(selection[1]:match("^%s*")) 329 | else 330 | selection_indent = get_smallest_indent(selection) or selection[1]:match("^%s*") or "" 331 | end 332 | 333 | local pasted_indent = get_smallest_indent(pasted) or "" 334 | 335 | local new_pasted = {} 336 | for i, line in ipairs(pasted) do 337 | if line == "" then 338 | new_pasted[i] = line 339 | elseif i == 1 and regtype == "v" then 340 | new_pasted[i] = line:sub(#pasted_indent + 1) 341 | else 342 | new_pasted[i] = selection_indent .. line:sub(#pasted_indent + 1) 343 | end 344 | end 345 | 346 | -- Temporarily set the register with the re-indented text and execute the command. 347 | vim.fn.setreg(vim.v.register, new_pasted, regtype) 348 | vim.cmd('normal! "' .. vim.v.register .. command) 349 | vim.fn.setreg(vim.v.register, pasted, regtype) 350 | -- Note: Since we always reset the register after the command, we change the 351 | -- default behavior of `p`, which otherwise replaces the default register with 352 | -- the text that was pasted over. 353 | end 354 | 355 | vim.api.nvim_create_autocmd('TextYankPost', { callback = yank }) 356 | vim.keymap.set({"n", "v"}, "p", function () paste("p") end) 357 | vim.keymap.set({"n", "v"}, "gp", function () paste("gp") end) 358 | vim.keymap.set({"n", "v"}, "P", function () paste("P") end) 359 | vim.keymap.set({"n", "v"}, "gP", function () paste("gP") end) 360 | -- Paste anything as linewise, at the cursor column if in Normal mode: 361 | vim.keymap.set("n", "p", function () paste("p", true) end) 362 | vim.keymap.set("n", "P", function () paste("P", true) end) 363 | -- Yank without losing selection: 364 | vim.keymap.set("v", "y", "ygv") 365 | -------------------------------------------------------------------------------- /.git-templates/hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | keyword='NOCOMMIT' 4 | additions="$(git diff --staged --diff-filter=ACM | grep '^+')" 5 | 6 | if echo "$additions" | grep --quiet "$keyword"; then 7 | echo "Error: $keyword found in added lines!" 8 | # Print file names with offending lines, and the offending lines. 9 | echo "$additions" \ 10 | | grep "$keyword\|^+++" \ 11 | | grep --before-context=1 --color=always "$keyword" 12 | exit 1 13 | fi 14 | -------------------------------------------------------------------------------- /.ideavimrc: -------------------------------------------------------------------------------- 1 | " Plugins: 2 | set surround 3 | set commentary 4 | set exchange 5 | set highlightedyank 6 | set sneak 7 | " Makes { and } work even if a blank line contains spaces. 8 | set vim-paragraph-motion 9 | 10 | " Plugins, maybe remove: 11 | set ReplaceWithRegister 12 | 13 | " Settings: 14 | set clipboard+=unnamedplus,ideaput 15 | set ignorecase 16 | set smartcase 17 | set incsearch 18 | set hlsearch 19 | set visualbell 20 | set noerrorbells 21 | 22 | " Change from backslash to space. 23 | " First unmap space, so it never moves forward after a delay. 24 | nnoremap 25 | let mapleader = " " 26 | 27 | " Mappings: 28 | 29 | " Quick macro playback: Record qith qq, play back with Q. 30 | " Note: In Neovim, Q replays the latest recorded macro by default. 31 | nnoremap Q @q 32 | 33 | " I usually show file explorer by pressing `-` (not available in IdeaVim). Put the original `-` on `_` instead. 34 | nnoremap _ - 35 | 36 | " Make Y work more like C and D (as in Neovim). 37 | nnoremap Y y$ 38 | 39 | " Clear search highlight. 40 | nnoremap :noh 41 | 42 | " Hover (like in VSCode). 43 | map gh (ShowHoverInfo) 44 | 45 | " Enable “IdeaVim: Track Action IDs” in the command palette to find action names. 46 | " Find references (like in VSCode). 47 | map gH (FindUsages) 48 | 49 | " Expand and shrink selection. 50 | map h (EditorSelectWord) 51 | map l (EditorUnSelectWord) 52 | 53 | " Go to next and previous error in the current file. 54 | map j (GotoNextError) 55 | map k (GotoPreviousError) 56 | 57 | " Don’t move the cursor when yanking in visual mode. 58 | xnoremap y ygv 59 | 60 | " Yank without losing selection. 61 | xnoremap y ygv 62 | 63 | " Poor man’s edgemotion. 64 | nnoremap ö '/^.\{' . (col('.') - 1) . '\}\S/e:nohl' 65 | nnoremap Ö '?^.\{' . (col('.') - 1) . '\}\S?e:nohl' 66 | 67 | " Go back and forward with backspace. 68 | nnoremap 69 | nnoremap 70 | 71 | " Camel case motions. 72 | map w [w 73 | map b [b 74 | map e ]w 75 | map ge ]b 76 | -------------------------------------------------------------------------------- /.ignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | node_modules/ 3 | elm-stuff/ 4 | fixtures/ 5 | *.min.* 6 | yarn.lock 7 | package-lock.json -------------------------------------------------------------------------------- /.local/share/applications/org.gnome.Terminal.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | # VERSION=3.36.2 3 | Name=Terminal 4 | Comment=Use the command line 5 | Keywords=shell;prompt;command;commandline;cmd; 6 | TryExec=gnome-terminal 7 | Exec=gnome-terminal --window --maximize 8 | Icon=org.gnome.Terminal 9 | Type=Application 10 | Categories=GNOME;GTK;System;TerminalEmulator; 11 | StartupNotify=true 12 | X-GNOME-SingleWindow=false 13 | OnlyShowIn=GNOME;Unity; 14 | Actions=new-window;preferences; 15 | X-Ubuntu-Gettext-Domain=gnome-terminal 16 | 17 | [Desktop Action new-window] 18 | Name=New Window 19 | Exec=gnome-terminal --window 20 | 21 | [Desktop Action preferences] 22 | Name=Preferences 23 | Exec=gnome-terminal --preferences 24 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | prefix=${HOME}/.npm-global 2 | save-prefix='' 3 | scripts-prepend-node-path=false 4 | -------------------------------------------------------------------------------- /.pam_environment: -------------------------------------------------------------------------------- 1 | PATH DEFAULT=/home/linuxbrew/.linuxbrew/bin:${PATH}:/home/@{PAM_USER}/.npm-global/bin 2 | FZF_DEFAULT_COMMAND=rg --hidden --files 3 | FZF_CTRL_T_COMMAND=rg --hidden --files 4 | -------------------------------------------------------------------------------- /LinkHints.json: -------------------------------------------------------------------------------- 1 | { 2 | "chars": "ehstirnoamupcwlfgdy", 3 | "logLevel": "warn", 4 | "normal.alt-H": "EnterHintsMode_ManyClick", 5 | "normal.alt-R": "EnterHintsMode_Select", 6 | "normal.alt-T": "EnterHintsMode_ManyTab", 7 | "normal.alt-h": "EnterHintsMode_Click", 8 | "normal.alt-r": "EnterHintsMode_ForegroundTab", 9 | "normal.alt-t": "EnterHintsMode_BackgroundTab" 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lydell’s dotfiles 2 | 3 | ## Setup 4 | 5 | I used to use some clever git trickery to track files at their actual 6 | locations, but these days I just copy files back and forth from this repo. 7 | I find that easier since mac and linux differ slightly. 8 | 9 | ## License 10 | 11 | All files are in the public domain. 12 | -------------------------------------------------------------------------------- /bin/backup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rsync --archive ~/ "/media/$USER/backup/$(uname --nodename)/home" \ 4 | --delete --backup \ 5 | --progress --human-readable \ 6 | --exclude /.atom/ \ 7 | --exclude /.cache/ \ 8 | --exclude /.elm/ \ 9 | --exclude /.fzf/ \ 10 | --exclude /.gem/ \ 11 | --exclude /.node-gyp/ \ 12 | --exclude /.npm/ \ 13 | --exclude /.npm-global/ \ 14 | --exclude /.python/ \ 15 | --exclude /.python2/ \ 16 | --exclude /.stack/ \ 17 | --exclude /.thumbnails/ \ 18 | --exclude /.tmp/ \ 19 | --exclude /.vim/ \ 20 | --exclude /old/ \ 21 | --exclude /programs/ \ 22 | --exclude /tmp/ \ 23 | --exclude /VirtualBox\ VMs/ \ 24 | --exclude .stack-work/ \ 25 | --exclude .venv/ \ 26 | --exclude bower_components/ \ 27 | --exclude CACHE/ \ 28 | --exclude elm-stuff/ \ 29 | --exclude node_modules/ \ 30 | --exclude __pycache__/ \ 31 | "$@" 32 | -------------------------------------------------------------------------------- /bin/e: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cmd="rg --hidden --max-columns $(( $(tput cols) - 27 )) --max-columns-preview --multiline-dotall --auto-hybrid-regex" 4 | 5 | # To use rg with a pager: `rg args... -p | less -RFX` 6 | # Automatically pipe into `less` if `-p` is used (but not if `--null` is used, 7 | # to avoid invoking `less` from `pre`). Use the long flag, `--pretty`, to skip 8 | # piping to `less`. 9 | seenP='' 10 | seenNull='' 11 | for arg in "$@"; do 12 | if test "$arg" == '--'; then 13 | break 14 | elif test "$arg" == '-p'; then 15 | seenP='true' 16 | elif test "$arg" == '--null'; then 17 | seenNull='true' 18 | fi 19 | done 20 | 21 | if test -n "$seenP" -a -z "$seenNull"; then 22 | $cmd "$@" | less -RFX 23 | else 24 | $cmd "$@" 25 | fi 26 | -------------------------------------------------------------------------------- /bin/git-branches: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | git submodule foreach 'printf "%-30s %s\n" "$name" "$(git symbolic-ref --short HEAD)"' | grep -v Entering 6 | -------------------------------------------------------------------------------- /bin/git-done: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | default_branch=master 6 | 7 | if test "$(git branch --list main)" != ''; then 8 | default_branch=main 9 | fi 10 | 11 | current_branch="$(git branch --show-current)" 12 | 13 | if test "$current_branch" = "$default_branch"; then 14 | echo "Already on $default_branch" 15 | exit 0 16 | fi 17 | 18 | git switch "$default_branch" 19 | git branch -D "$current_branch" 20 | git pull 21 | -------------------------------------------------------------------------------- /bin/git-main: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | if test "$(git branch --list main)" != ''; then 6 | echo main 7 | else 8 | echo master 9 | fi 10 | -------------------------------------------------------------------------------- /bin/git-pr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | open "https://github.com/$(git config remote.origin.url | cut -f2 -d: | cut -f1 -d.)/pull/new/$(git symbolic-ref --quiet --short HEAD)" 6 | -------------------------------------------------------------------------------- /bin/git-trash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | root="$(git rev-parse --show-toplevel)" 6 | trash="$root/.stuff/trash" 7 | modified="$(git ls-files --modified --exclude-standard -- "$@")" 8 | untracked="$(git ls-files --others --exclude-standard -- "$@")" 9 | 10 | if test -z "$modified" -a -z "$untracked"; then 11 | echo "Nothing to trash" 12 | else 13 | mkdir -p "$trash" 14 | if test -n "$modified"; then 15 | printf "%s\n%s" "$modified" "$trash/" | tr '\n' '\0' | xargs -0 rsync -axRI 16 | printf "%s" "$modified" | tr '\n' '\0' | xargs -0 git restore 17 | echo "$modified" 18 | fi 19 | if test -n "$untracked"; then 20 | printf "%s\n%s" "$untracked" "$trash/" | tr '\n' '\0' | xargs -0 rsync --remove-source-files -axRI 21 | echo "$untracked" 22 | fi 23 | fi 24 | -------------------------------------------------------------------------------- /bin/pre: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | seenReplace='' 4 | 5 | for arg in "$@"; do 6 | if test "$arg" == '--replace' -o "$arg" == '-r'; then 7 | seenReplace='true' 8 | break 9 | fi 10 | done 11 | 12 | if test -z "$seenReplace"; then 13 | echo 'You must specify the --replace or -r argument!' 14 | exit 1 15 | fi 16 | 17 | currentFile='' 18 | didChange='' 19 | 20 | ( 21 | e \ 22 | --context 999999 \ 23 | --with-filename --heading --null \ 24 | --color=never --no-line-number \ 25 | --max-columns=0 \ 26 | "$@" 27 | echo -e '\n\0' 28 | ) | 29 | { 30 | while IFS= read -r -d '' part; do 31 | if test -n "$currentFile"; then 32 | echo "$currentFile" 33 | (sed '$d' | sed '$d') <<< "$part" > "$currentFile" 34 | didChange='true' 35 | fi 36 | currentFile="$(tail -n 1 <<< "$part")" 37 | done 38 | 39 | if test -z "$didChange"; then 40 | echo "No files were changed." 41 | exit 1 42 | fi 43 | } 44 | -------------------------------------------------------------------------------- /bin/release: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | name="$(basename "$PWD")" 4 | version="v$1" 5 | message="$name $version" 6 | git commit -am "$message" && git tag "$version" -am "$message" 7 | -------------------------------------------------------------------------------- /bin/tw: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | dir="$HOME/.config/tworld" 4 | tworld --no-passwords --quiet \ 5 | --data-dir="$dir/data" \ 6 | --levelset-dir="$dir/sets" \ 7 | --save-dir="$dir/save" 8 | -------------------------------------------------------------------------------- /bin/x: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | if test "$#" = 0; then 6 | echo "Usage: x CMD ARGS..." 7 | exit 0 8 | fi 9 | 10 | cmd_name="$1" 11 | shift 12 | 13 | dir="$(pwd)" 14 | path="" 15 | 16 | while true; do 17 | path="$path:$dir/node_modules/.bin" 18 | dir="$(dirname "$dir")" 19 | if test "$dir" = '/'; then 20 | break 21 | fi 22 | done 23 | 24 | PATH="${path:1}:$PATH" "$cmd_name" "$@" 25 | -------------------------------------------------------------------------------- /programs.txt: -------------------------------------------------------------------------------- 1 | # apt 2 | chromium-browser 3 | gnome-session 4 | sudo update-alternatives --config gdm3.css 5 | gnome-tweaks 6 | xclip 7 | 8 | # ubuntu-make 9 | snap install ubuntu-make --classic 10 | umake web firefox-dev --lang en-US 11 | 12 | # deb 13 | vscode 14 | 15 | # brew 16 | bat 17 | eza 18 | fish 19 | font-meslo-lg-nerd-font 20 | fzf 21 | git-delta 22 | htop 23 | httpie 24 | imagemagick 25 | jless 26 | jo 27 | jq 28 | neovim 29 | node 30 | optipng 31 | python 32 | ripgrep 33 | shellcheck 34 | tokei 35 | yarn 36 | zoxide 37 | 38 | # brew cask 39 | bitwarden 40 | firefox-developer-edition 41 | iterm2 42 | krisp 43 | rectangle 44 | scroll-reverser 45 | sensiblesidebuttons 46 | visual-studio-code 47 | zsa-wally 48 | 49 | # npm 50 | fx 51 | neovim 52 | npm-home 53 | npm-upgrade 54 | serve 55 | svgo 56 | 57 | # vscode 58 | change-case 59 | Error Lens 60 | ESlint 61 | Fish 62 | GitLens 63 | Prettier 64 | ShellCheck 65 | VSCode NeoVim 66 | 67 | # gnome 68 | Unite 69 | Vitals 70 | -------------------------------------------------------------------------------- /vscode/keybindings.json: -------------------------------------------------------------------------------- 1 | [ 2 | // Close tabs to the right. 3 | { 4 | "key": "shift+alt+u", 5 | "command": "workbench.action.closeEditorsToTheRight" 6 | }, 7 | 8 | // Expand and shrink selection. 9 | { 10 | "key": "cmd+[Quote]", 11 | "command": "editor.action.smartSelect.expand", 12 | "when": "editorTextFocus" 13 | }, 14 | { 15 | "key": "shift+cmd+[Quote]", 16 | "command": "editor.action.smartSelect.shrink", 17 | "when": "editorTextFocus" 18 | }, 19 | 20 | // GitHub CoPilot: Trigger on demand, and alt+right to accept partially (like Fish). 21 | { 22 | "key": "shift+cmd+[Period]", 23 | "command": "editor.action.inlineSuggest.trigger" 24 | }, 25 | { 26 | "key": "alt+right", 27 | "command": "editor.action.inlineSuggest.acceptNextWord", 28 | "when": "inlineSuggestionVisible && !editorReadonly" 29 | }, 30 | 31 | // Pass cmd+d (multiple cursors) to Neovim: 32 | // https://github.com/vscode-neovim/vscode-neovim#vscodewith_insertcallback 33 | { 34 | "command": "vscode-neovim.send", 35 | "key": "cmd+d", 36 | "when": "editorTextFocus && neovim.mode != insert", 37 | "args": "", 38 | }, 39 | ] 40 | -------------------------------------------------------------------------------- /vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.language": "en,sv-SE", 3 | "editor.acceptSuggestionOnCommitCharacter": false, 4 | "editor.accessibilitySupport": "off", 5 | "editor.inlineSuggest.enabled": true, 6 | "editor.minimap.autohide": true, 7 | "editor.renderFinalNewline": "off", 8 | "editor.stickyScroll.enabled": true, 9 | "files.autoSave": "onFocusChange", 10 | "files.insertFinalNewline": true, 11 | "git.openRepositoryInParentFolders": "never", 12 | "window.zoomLevel": 1.5, 13 | "workbench.activityBar.location": "top", 14 | "workbench.editor.limit.enabled": true, 15 | 16 | "window.autoDetectColorScheme": true, 17 | "workbench.preferredDarkColorTheme": "Default Dark+", 18 | "workbench.preferredLightColorTheme": "Default Light+", 19 | 20 | "elmLand.feature.offlinePackageDocs": "Imports only", 21 | "gitlens.codeLens.enabled": false, 22 | "haskell.manageHLS": "GHCup", 23 | "prettier.requireConfig": true, 24 | "typescript.tsserver.experimental.enableProjectDiagnostics": true, 25 | 26 | "github.copilot.editor.enableAutoCompletions": false, 27 | "github.copilot.enable": { 28 | "*": true, 29 | "plaintext": false, 30 | "markdown": true, 31 | "scminput": false, 32 | "yaml": true 33 | }, 34 | 35 | "extensions.experimental.affinity": { 36 | "asvetliakov.vscode-neovim": 1 37 | }, 38 | 39 | "editor.formatOnSave": true, 40 | "editor.defaultFormatter": "esbenp.prettier-vscode", 41 | "editor.codeActionsOnSave": { 42 | "source.fixAll.eslint": "explicit" 43 | }, 44 | "[elm]": { 45 | "editor.defaultFormatter": "elm-land.elm-land" 46 | }, 47 | "[fish]": { 48 | "editor.defaultFormatter": "bmalehorn.vscode-fish" 49 | }, 50 | "[gleam]": { 51 | "editor.defaultFormatter": "gleam.gleam" 52 | }, 53 | "[haskell]": { 54 | "editor.defaultFormatter": "haskell.haskell" 55 | }, 56 | } 57 | --------------------------------------------------------------------------------