Compare commits

...

82 Commits

Author SHA1 Message Date
316eefe916 kitty:get_cwd: Use KITTY_LISTEN_ON for socket path
Also verify that the socket exists before using it.
2025-12-11 15:27:39 +01:00
3a821d832b kitty:get_cwd: Use the match flag for performance
Instead of requesting the full tree as a JSON and extracting the focused
window with `jq`, use `kitten-@-ls`'s `--match` flag. This further
improves the performance.

Also remove the commented code using recursive descent because it is not
up-to-date anymore.
2025-12-11 15:27:38 +01:00
b291163a80 kitty:get_cwd: Make faster by not using kitten
kitten-@-ls(1) is unfortunately a bit slow (100ms) which is noticeable
when launching new windows using `get_cwd`. Make `get_cwd` faster (down
to 25ms) by communicating directly with the socket instead of using
`kitten`.
2025-12-11 15:27:23 +01:00
2e2bad65a2 polybar: Change while read loop to an xargs pipe 2025-12-10 14:27:53 +01:00
c46b1c5ea1 i3: Add bindings to switch forward & backward
After unplugging an external monitor I sometimes still have old
workspaces that I can't access through their index.
2025-12-10 14:20:40 +01:00
5f40b97e9a i3: Workspace 0 should be 10 2025-12-10 14:19:48 +01:00
5599ce14d7 i3: Normal numeric workspaces on multi outputs
Use normal workspace numbers with the output name as workspace name, but
strip the name in polybar.

See https://github.com/polybar/polybar/pull/3230 for strip-wsnames.
2025-12-04 14:31:05 +01:00
4008bb543b vim:looks: Don't hardcode the colorscheme colors 2025-11-25 18:06:24 +01:00
d0abb14567 vim: Highlight trailing spaces in colorscheme red 2025-11-25 18:06:13 +01:00
9e18be760c vim:setts: Use the number column for the signcolumn 2025-11-25 17:27:48 +01:00
04d3d6e87f vim:plugs:nrrwrgn: Add padding to small windows 2025-11-25 17:19:34 +01:00
526a37301a vim:plugs:ctags: Don't index venv and __pycache__ 2025-11-25 17:11:14 +01:00
7dc9efc0e4 vim:gitcommit: Fold unstaged and untracked files 2025-11-25 17:09:24 +01:00
9bc8b4b93f vim:ftplug:man: Only trigger one timer
Stop an already running timer similar to how it is done already when
highlighting the selection.
2025-11-25 16:07:52 +01:00
ead724b75b vim:ftplug:man: Fix WinResized support check
The check if the WinResized event is supported was broken from the
beginning on since I used `has()` instead of `exists()`.

Fixes: 558bb0582e (man.vim: Check if WinResized is supported,
       2025-01-29)
2025-11-25 15:56:21 +01:00
1c5beed613 git🐮 Fix stderr redirection
I also swapped the printf and the redirection since I think I prefer it
this way.
2025-09-21 01:34:48 +02:00
2dd1a80036 git🐮 Fix parameter quoting
The parameter expansion outside of the single quotes (or inside, however
you want to see it) was not quoted.
2025-09-21 01:30:56 +02:00
4f2a74e546 less: Remap ^E to edit current screen in vim 2025-09-19 01:47:39 +02:00
cb1821ba33 less: Remap ^Y to copying the whole file 2025-09-19 01:44:23 +02:00
5128d15251 less: Strip all ANSI sequences, not just SGR
Kitty's shell integration uses OSC sequences to mark the prompt and
output in the scrollback buffer. When opening that in vim through less I
want these to be gone as well.
2025-09-19 01:36:54 +02:00
2b31632914 bin:no-ansi: Add a label to each pattern 2025-09-19 01:14:09 +02:00
27791acf50 bin:no-ansi: Correct allowed byte ranges
Correct the allowed byte ranges of the APC, DCS, OSC, PM & SOS
sequences. All but the SOS sequence allow additionally the bytes in the
range `0x8 - 0xD` and SOS may be followed by any sequence of bytes
except for SOS and ST (i.e. `\eX` & `\e\\`).

Link: https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf#page=27
2025-09-19 00:51:47 +02:00
8aa76b3ee6 bin:no-ansi: Don't just match CSI sequences
Try to match all ANSI escape sequences, not just CSI (i.e. `\e[`) - also
the ones that are followed by additional bytes (e.g. CSI, OSC).
2025-09-19 00:26:36 +02:00
6b866f5474 bin:no-ansi*: Use printf for escape byte
I dislike having the raw escape byte in these scripts. Unfortunately
`sed` does not support interpreting it via an escape sequence, so use
printf for that. To remain POSIX compatible use `\033` and not `\e` or
`\x1b` since I couldn't find these in the printf(1p) manpage.
Unfortunately this brings a second layer of escaping.
2025-09-19 00:13:28 +02:00
4f6929bcce less: Keep position when editing in vim via e/E 2025-09-18 23:19:07 +02:00
2495d835b4 kitty: Slightly decrease click_interval to 0.4
Kitty's source code makes me believe that this is always 0.5s on X11.
This decreases the delay when opening links.

Link: https://github.com/kovidgoyal/kitty/blob/3482d084aef1/glfw/x11_window.c#L2360-L2363
2025-09-18 12:56:10 +02:00
dda2ff640e kitty: Increase font size by one point to 12 2025-09-18 12:26:36 +02:00
87398bf712 vim:keys: Use getreginfo() instead of getregtype()
The result from getreginfo can be passed directly to setreg making this
a bit neater. Taken from the neovim defaults (ironically not from
v_star-default).

Link: https://github.com/neovim/neovim/blob/08847a9ea15a/runtime/lua/vim/_defaults.lua#L73-L79
2025-09-18 01:08:18 +02:00
0a5b6d0767 vim:keys: Only map v_* & v_# if they don't exist
I learned just now that neovim added mappings for these by default in
v0.8.0. But instead of checking for neovim, check for the existence of
mappings in case vim adds these in the future too.
2025-09-18 01:07:34 +02:00
5b8f54b0cb vim:keys: Fix newline and tab search for v_*
Multiline search didn't work previously when searching with v_* and tabs
were ignored when searching with v_<leader>*.
2025-09-17 23:01:11 +02:00
ef5b2911bf vim:coc: Select first item before confirming
I believe I had the problem in the past that the completion wouldn't
automatically select the first entry but simply display the menu. Thus
it would simply insert a new line when pressing return to accept it.

Unfortunately I didn't commit it back then and I can't reproduce it now.
But it doesn't not hurt so I commit it to be safe.
2025-09-17 21:55:00 +02:00
768cb4ed4a vim:keys: Add mapping for git-commit-last-msg 2025-09-17 21:46:43 +02:00
f2ce78b6b3 vim:fzf: Use location list instead of the quickfix
Since the quickfix is a global list I can't keep multiple ripgrep
searches open at once. The location list is window-local thus solving
this issue.
2025-09-17 21:44:46 +02:00
a3d2bf985c i3: Use back_and_forth instead of i3-msg+jq 2025-09-17 17:35:19 +02:00
e8c5ec93f1 i3: Re-add stacking and tabbed layout bindings
I removed these in 69d0290afd (i3: Remove bindings for stacked and
tabbed layout, 2023-04-20) since I never need them and I always forgot
how to switch back when I pressed these accidentally.

Bring these back as comments, since the comment above still mentions
these and since I can imagine a rare situation where I might want one
these and simply want to comment them in.
2025-09-17 17:30:51 +02:00
ae52ba20d2 vim: Disable 'cindent' in non-code filetypes 2025-09-17 16:49:34 +02:00
ea2867fc9f dircolors: Color pdfs like images and videos 2025-09-17 16:44:48 +02:00
7f83427749 hooks:pre-commit: Broken link detection on delete
Until now the hook only checked newly added symlinks. This patch is a
first draft of also checking the worktree and index for any dangling
symlinks after staging a deletion.

The whole thing probably breaks when file-names contain newlines and
maybe also a mix of quotes. I plan on making this more robust in the
future but see no urgency for it since this repository has pretty simple
filenames.
2025-09-15 17:40:35 +02:00
8a4029121e hooks:pre-commit: Explicitly propagate pipe error
The `die` in the pipe does not exit the whole script but only the pipe.
This currently works because the pipe is the last thing being executed.
If something would come after the pipe, the hook would happily continue
executing. Properly propagate the exit to prevent this in the future.
2025-09-15 17:34:01 +02:00
7c184ed11e git🐮 Fix GIT_DIR for submodules via git alias
Git sets some environment variables when executing a shell command.
Specifically it sets GIT_DIR when called inside a submodule. This makes
git inside the subshell target the main worktree instead of the
temporary one.
2025-09-15 14:24:36 +02:00
8e8ef29b37 git🐮 Use %s to print worktree path
Don't pass the worktree path directly into the format string - just to
be safe.
2025-09-15 13:49:34 +02:00
d8859bc709 git🐮 Keep as much relative offset as possible 2025-09-15 13:49:34 +02:00
65d99c40e8 git🐮 Keep relative path offset 2025-09-15 13:49:33 +02:00
d28ef61694 git🐮 Rename temporary worktree directory
Shorten the "worktree" and place the random bytes at the end for better
sorting.
2025-09-15 13:23:01 +02:00
d5a95f9ce5 git🐮 Fix name of submodules
Previously git-checkout-worktree would use the name of the superproject
instead of the submodule for the temporary directory.
2025-09-15 13:19:28 +02:00
723899d70f git: Add empty line before include section
I want the section at the very end and this broke the alphabetic
sorting.
2025-09-12 17:06:01 +02:00
126ccb0c7a git: Fix option capitalization
Semantically this changes nothing, but the name with a capital `S` is
used by git-config(1).
2025-09-12 17:04:49 +02:00
dadf344f2b git: Explicitly set core.whitespace.tabwidth=8 2025-09-12 17:03:53 +02:00
f17cde7943 git: Show all refs as decoration in logs 2025-09-12 16:57:00 +02:00
a89ad407ba git: Make all graph colors bold
This looks a bit better in my opinion.
2025-09-12 16:56:05 +02:00
a26a899213 git: Make all bold colors bright
Make all bold colors (also) bright, since kitty does not render bold
colors in their bright version, but I've gotten used to how this looks.

For the graph I've gotten rid of the boldness and only switched to
bright versions since I think it makes no sense to have different line
weights for the branches (Although I apparently never noticed, so I
can't say that this was misleading in practice).
2025-09-12 16:51:36 +02:00
6db1a710c6 git: Rename zsh-autoload.sh -> external-script.sh
With the last commit 9c1e3f4679 (git:zsh-autoload: Use relative
scripts/ folder, 2025-09-12), `zsh-autoload.sh` could execute any type
of external script. Rename it to a more generic name.
2025-09-12 16:25:39 +02:00
9c1e3f4679 git:zsh-autoload: Use relative scripts/ folder
This makes it a bit more agnostic to the type of scripts being used.
2025-09-12 14:49:59 +02:00
bb7ef3769d git: Add branch-rename
Small script to rename a branch locally and on a given remote.
2025-09-12 14:35:44 +02:00
0534ec493e zsh:alias: Make sizes an anonymous function
This way one can easily redirect stderr for both commands (not just
`sort`) and specify a path. The path defaults to the current directory,
but listing each entry by globbing.
2025-09-07 21:09:11 +02:00
708daa10dc kitty: Disable cursor shell integration
It's super slow and I really don't need it. I'd prefer to have kitty
mess with my shell as little as possible.
2025-09-04 11:14:52 +02:00
6bd13a9b56 kitty: Open url with kitty_mod+f
Similar to zathura's `f` to follow links.
2025-09-04 11:14:45 +02:00
a34cdab694 vim:keys: Revert "Add <leader>g[pP] for system clipboard"
This reverts commit 2bceafeb4e.

`<leader>gp` conflicts with GitGutterPreviewHunk.
2025-09-03 15:01:57 +02:00
456f71d939 vim:keys:TODO: Add <leader>[h 2025-09-03 13:33:09 +02:00
2bceafeb4e vim:keys: Add <leader>g[pP] for system clipboard 2025-09-03 13:18:17 +02:00
af0d9e8fd1 vim:keys: Disable gp mapping for now
It conflicts with the default.
2025-09-03 13:18:17 +02:00
d57fbf0e66 vim:keys: Prepend fzf bindings with f
All fzf related bindings should start with `<leader>f`. This resolves
the clash between `GFiles` and the git actions targeting the full file.
2025-09-03 13:18:16 +02:00
a23159e50d vim:keys: Merge fzf mappings 2025-09-03 13:18:16 +02:00
e8a8f9637a vim:coc: Re-enable backup files
CoC disables backup files due to a problem with a typescript
language-server (it becoming slow when the backup file is written,
triggering a `structureChanged`). But:

1. I want backup files
2. I do not use that language server
3. If I would:
	1. I could disable backup files in a filetype plugin
	2. The linked issue is from 2019 - no idea if this is still
	   present today
4. I don't think this issue is even a thing with a `&backupdir` that
   does not include relative directories (which is the case for me)

So remove the lines disabling backups and go back to vim's defaults:
`nobackup` and `writebackup`.

Link: https://github.com/neoclide/coc.nvim/issues/649
2025-09-03 11:54:50 +02:00
0e5baf5e36 vim:coc: Add coc-go server 2025-09-03 11:36:27 +02:00
fced504674 tmux: Kill dead pane with Escape too 2025-09-03 10:07:53 +02:00
a49cbcae21 git:core.pager: Remove --quit-if-one-screen
The inconsistency annoys me.
2025-09-03 10:02:06 +02:00
9271a293cb git: Enable clone.filterSubmodules
> If a partial clone filter is provided (see --filter in
> git-rev-list(1)) and --recurse-submodules is used, also apply the
> filter to submodules.

I have never used --filter before, but it sounds as if I want this
enabled in the case that I do.
2025-09-03 10:00:48 +02:00
2e4086500d git: Disable rerere
I had this change sitting around so long that I forgot why exactly I
disabled it, but know that some problem arose from rerere. I think that
even though it is super cool, it brings a sneaky new layer of possible
errors. Maybe I'll re-enable it in the future.
2025-09-03 09:53:54 +02:00
ca15f2399e bin:no-ansi: Fix final byte range
Don't know why I put `z`, the range goes until `~` (i.e. 0x7E).
2025-09-01 16:50:03 +02:00
198069fac7 zsh:alias: Add -a to cp
Preserve all attributes (i.e. timestamps, permissions, etc.). This also
implies `--recursive` which I probably could have added already sooner.
2025-08-30 11:48:45 +02:00
4c12418b62 git:track: Fix unnecessary subshell launch
While at it, modify the formatting of the line above slightly.
2025-08-28 12:24:06 +02:00
5767210dce git:track: List remote refs only on request
List only the local heads by default and require the remote refs to be
passed as arguments. For example:

	git track origin

To make this easier, add support of an `--all` flag to list all remote
refs.
2025-08-28 12:24:02 +02:00
ddb279da7b kitty:daemon: Write to log file 2025-08-26 16:54:55 +02:00
07428c661d kitty:daemon: Support optional instance group name 2025-08-26 13:43:03 +02:00
a7e4c2c770 kitty:daemon: Use TMPDIR and support multi-user 2025-08-26 13:41:18 +02:00
c09ed22389 i3: Move kitty daemonization into own script 2025-08-26 13:06:08 +02:00
1f6fb2abf7 zsh:glog: Bind Ctrl-s to toggle-sort
When searching for a specific commit in a long history the chronological
sorting can sometimes be annoying. Map ctrl-s to toggle-sort so that the
best result can be at the top.
2025-08-24 20:57:23 +02:00
b47c91bb5f zsh:glog: Use Ctrl-Alt for preview bindings
This makes it more consistent with the preview scroll bindings.
2025-08-24 20:57:17 +02:00
fec954c30c zsh:glog: Move header into variable 2025-08-24 20:57:10 +02:00
372865f9c4 vim:syn:md: Use lookarounds instead of \zs & \ze
Apparently the `\zs` token does not match characters if they are already
part of a syntax match. For example in `[^0][^1]` only the zero footnote
is matched. Fix this by using a positive lookbehind that does not have
this limitation.

Additionally, use a negative lookahead for the colon to make the pattern
slightly more readable, since it does not need the end-of-line check.
2025-08-12 13:00:41 +02:00
3fb5b5f376 vim:syn:md: Conceal numeric footnotes
Conceal numeric footnotes with superscript numbers. The whole thing is a
bit of a gimmick since only single digit numbers are concealed but I had
this idea for quite some time and wanted to execute it.

When not put into the `after/` directory, the matches are overwritten by
the `markdownFootnote` group.
2025-08-12 12:59:33 +02:00
34 changed files with 538 additions and 156 deletions

View File

@@ -185,3 +185,6 @@ EXEC 01;92
*.opus 00;36
*.spx 00;36
*.xspf 00;36
## Others
*.pdf 01;95

View File

@@ -4,21 +4,22 @@
addIgnoredFile = off
detachedHead = off
[alias]
# NOTE: git-zsh-autoload (./zsh-autoload.sh) is a small wrapper that
# launches autoloadable zsh functions (.config/zsh/autoload/git/*) in
# the right directory, as shell commands in git aliases are executed
# from the top-level directory of the repository.
# NOTE: git-external-script (./external-script.sh) is a small wrapper
# that launches external scripts from the ./scripts/ collection in the
# right directory, as shell commands in git aliases are executed from
# the top-level directory of the repository.
abort = "!git-zsh-autoload abort"
abort = "!git-external-script abort"
autosquash = -c sequence.editor=/bin/true rebase -i --autosquash
autofixup= autosquash
branch-rename = "!git-external-script branch-rename"
c = commit
changes = flog HEAD...FETCH_HEAD
checkout-worktree = "!git-zsh-autoload checkout-worktree"
checkout-worktree = "!git-external-script checkout-worktree"
cow = checkout-worktree
co = checkout
commit-last-msg = "!git-zsh-autoload commit-last-msg"
continue = "!git-zsh-autoload continue"
commit-last-msg = "!git-external-script commit-last-msg"
continue = "!git-external-script continue"
cont = continue
clm = commit-last-msg
last-msg = commit-last-msg
@@ -28,27 +29,61 @@
ft = fetch-tags-only
filter-repo = !git-filter-repo
fixes = log -1 --pretty=fixes
glog = "!git-zsh-autoload glog"
https-and-ssh = "!git-zsh-autoload https-and-ssh"
glog = "!git-external-script glog"
https-and-ssh = "!git-external-script https-and-ssh"
ssh-and-https = https-and-ssh
l = log
last-changed = "!git-zsh-autoload last-changed"
last-changed = "!git-external-script last-changed"
ls = ls-files
make-fork = "!git-zsh-autoload make-fork"
make-fork = "!git-external-script make-fork"
p = push
perm-stash = "!git-zsh-autoload perm-stash"
perm-stash = "!git-external-script perm-stash"
root = rev-parse --show-toplevel
signoff = rebase --signoff
ss = stash
ssync = "!git-zsh-autoload ssync"
submodule-rm = "!git-zsh-autoload submodule-rm"
track = "!git-zsh-autoload track"
ssync = "!git-external-script ssync"
submodule-rm = "!git-external-script submodule-rm"
track = "!git-external-script track"
branches = track
[blame]
date = short
[branch]
autosetuprebase = always
sort = -committerdate
[clone]
filterSubmodules = yes
[color "diff"]
# Make all bold colors also bright. See diff_colors in git's diff.c
oldMoved = bold brightmagenta
oldMovedAlternative = bold brightblue
newMoved = bold brightcyan
newMovedAlternative = bold brightyellow
oldBold = bold brightred
newBold = bold brightgreen
[color "decorate"]
# Make all bold colors also bright. See decoration_colors in git's
# log-tree.c
branch = bold brightgreen
remoteBranch = bold brightred
tag = bold brightyellow
stash = bold brightmagenta
HEAD = bold brightcyan
grafted = bold brightblue
[color "grep"]
# Make all bold colors also bright. See GREP_OPT_INIT in git's grep.h
matchContext = bold brightred
matchSelected = bold brightred
[color "interactive"]
# Make all bold colors also bright. See init_add_i_state in git's
# add-interactive.c
help = bold brightred
prompt = bold brightblue
error = bold brightred
[color "remote"]
# Make all bold colors also bright. See keywords in git's sideband.c
warning = bold brightyellow
success = bold brightgreen
error = bold brightred
[color "status"]
added = 076
untracked = 014
@@ -65,9 +100,8 @@
[core]
abbrev = 12
#pager = delta
pager = diff-so-fancy \
| less --tabs=8 --RAW-CONTROL-CHARS --quit-if-one-screen
whitespace = trailing-spaces,space-before-tab,indent-with-non-tab
pager = diff-so-fancy | less --tabs=8 --RAW-CONTROL-CHARS
whitespace = trailing-spaces,space-before-tab,indent-with-non-tab,tabwidth=8
[delta]
navigate = true
commit-decoration-style = bold yellow box
@@ -100,6 +134,12 @@
singleKey = true
[log]
follow = true
# Make all colors bold and additionally use bright versions of
# previously bold-only colors. See column_colors_ansi in git's color.c
# used by graph.c
graphColors = bold red,bold green,bold yellow,bold blue,bold magenta,bold cyan,bold brightred,bold brightgreen,bold brightyellow,bold brightblue,bold brightmagenta,bold brightcyan
# Show all refs as decoration (e.g. also notes)
initialDecorationSet = all
[merge]
conflictstyle = diff3
log = true
@@ -114,9 +154,9 @@
[rebase]
autostash = true
[rerere]
enabled = true
enabled = false
[status]
submodulesummary = true
submoduleSummary = true
[submodule]
fetchJobs = 0
[trailer]
@@ -125,5 +165,6 @@
email = julian@druck.dev
name = Julian Prein
signingkey = C0A44F69F2E29F6586C86B96CA6B3A516FAC2555
[include]
path = user.config

View File

@@ -2,8 +2,9 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 Julian Prein
#
# Meant to be used in git aliases to launch an autoloadable zsh function in the
# correct directory.
# Meant to be used by git aliases to easily launch an external script from the
# ./scripts/ collection through its basename and in the correct directory (i.e.
# GIT_PREFIX).
if [ $# -eq 0 ]; then
printf >&2 "Usage: %s <function>\n" "$(basename "$0")"
@@ -12,7 +13,7 @@ fi
name="$1"
shift
BASE="${XDG_CONFIG_HOME:-$HOME/.config}/zsh/autoload/git"
BASE="$(dirname "$(realpath "$0")")/scripts"
# In git aliases, shell commands are executed from the top-level directory of
# the repo. GIT_PREFIX contains the original directory relative to the

View File

@@ -36,18 +36,11 @@ set $TERM_CMD_FLAG
# a single sprite cache on the GPU"[^1], so that startup is almost instant.
#
# For this to work best, launch one hidden "daemon" instance at startup so that
# the kitty process is always running, even when no OS windows exists.
#
# NOTE: `--start-as hidden` needs kitty 0.42.0 or later.
#
# Additionally allow remote_control over a socket, so that kitty-cwd works.
# the kitty process is always running, even when no OS windows exists. See the
# daemon.sh script in .config/kitty.
#
# [^1]: kitty(1)
exec --no-startup-id $TERMINAL \
--start-as hidden \
--detach \
-o allow_remote_control=socket-only \
--listen-on unix:/tmp/mykitty
exec --no-startup-id kitty-daemon
# Multi monitor support
exec_always --no-startup-id ~/.config/i3/monitor-setup.sh &
@@ -86,6 +79,8 @@ bindsym $mod+Shift+v split horizontal
bindsym $mod+f fullscreen toggle
# change container layout (stacked, tabbed, toggle split)
#bindsym $mod+s layout stacking
#bindsym $mod+w layout tabbed
bindsym $mod+e layout toggle split
# toggle tiling / floating
@@ -107,13 +102,15 @@ bindsym $mod+6 exec ~/.config/i3/multi-monitor-workspaces.sh -s 6
bindsym $mod+7 exec ~/.config/i3/multi-monitor-workspaces.sh -s 7
bindsym $mod+8 exec ~/.config/i3/multi-monitor-workspaces.sh -s 8
bindsym $mod+9 exec ~/.config/i3/multi-monitor-workspaces.sh -s 9
bindsym $mod+0 exec ~/.config/i3/multi-monitor-workspaces.sh -s 0
bindsym $mod+0 exec ~/.config/i3/multi-monitor-workspaces.sh -s 10
# switch back to the previous workspace
workspace_auto_back_and_forth yes
bindsym $mod+Tab exec i3-msg workspace "$( \
i3-msg -t get_workspaces | \
jq -r '.[] | select(.focused).name')"
bindsym $mod+Tab workspace back_and_forth
# switch workspaces forward and backward
bindsym $mod+Next workspace next
bindsym $mod+Prior workspace prev
# Switch visible workspaces (e.g. multi monitor setup)
bindsym $mod+Shift+Tab exec i3-msg workspace "$( \
@@ -131,7 +128,7 @@ bindsym $mod+Shift+6 exec ~/.config/i3/multi-monitor-workspaces.sh -m 6
bindsym $mod+Shift+7 exec ~/.config/i3/multi-monitor-workspaces.sh -m 7
bindsym $mod+Shift+8 exec ~/.config/i3/multi-monitor-workspaces.sh -m 8
bindsym $mod+Shift+9 exec ~/.config/i3/multi-monitor-workspaces.sh -m 9
bindsym $mod+Shift+0 exec ~/.config/i3/multi-monitor-workspaces.sh -m 0
bindsym $mod+Shift+0 exec ~/.config/i3/multi-monitor-workspaces.sh -m 10
# move focused container and switch to workspace
bindsym Mod1+Shift+1 exec ~/.config/i3/multi-monitor-workspaces.sh -ms 1
@@ -143,7 +140,7 @@ bindsym Mod1+Shift+6 exec ~/.config/i3/multi-monitor-workspaces.sh -ms 6
bindsym Mod1+Shift+7 exec ~/.config/i3/multi-monitor-workspaces.sh -ms 7
bindsym Mod1+Shift+8 exec ~/.config/i3/multi-monitor-workspaces.sh -ms 8
bindsym Mod1+Shift+9 exec ~/.config/i3/multi-monitor-workspaces.sh -ms 9
bindsym Mod1+Shift+0 exec ~/.config/i3/multi-monitor-workspaces.sh -ms 0
bindsym Mod1+Shift+0 exec ~/.config/i3/multi-monitor-workspaces.sh -ms 10
# reload the configuration file
bindsym $mod+Shift+c reload

View File

@@ -25,25 +25,12 @@ done
shift $((OPTIND - 1))
[ $# -gt 0 ] || usage
outputs="$(i3-msg -t get_outputs | jq -r '.[] | select(.active).name')"
num_outs="$(printf "%s\n" "$outputs" | wc -l)"
if [ "$num_outs" -lt 2 ]; then
# only one monitor
workspace="$1"
else
name="$(i3-msg -t get_tree \
name="$(i3-msg -t get_tree \
| jq -r '.. | objects | select(.focused).output')"
num="$(printf "%s\n" "$outputs" \
| grep -Fxn "$name" \
| cut -d: -f1)"
num="$((num - 1))"
# Omit the number on the first monitor
[ "$num" -gt 0 ] || num=
workspace="$num$1"
fi
# NOTE: See `strip-wsnames` in polybar config. With it every monitor has its own
# 1-10 workspaces
workspace="$1: $name"
if [ -z "$switch" ] && [ -z "$move" ]; then
printf "%s\n" "$workspace"

34
.config/kitty/daemon.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/sh
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 Julian Prein
#
# Usage: kitty-daemon [GROUP_NAME]
#
# Daemonize kitty by launching one hidden instance that new invocations can use
# to create new OS windows. This makes kitty startup a lot faster since all
# windows can now share a single CPU process and GPU sprite cache. Additionally
# allow remote_control over a socket, so that kitty-cwd works.
#
# To launch new invocations using the daemon created by this script use:
#
# kitty --single-instance
#
# You can pass an optional instance-group as first parameter. In that case use:
#
# kitty --single-instance --instance-group <NAME>
#
# NOTE: `--start-as hidden` needs kitty 0.42.0 or later.
TMP_DIR="${TMPDIR:-/tmp}/kitty.$USER"
mkdir -p "$TMP_DIR"
name="kitty${1:+-$1}"
kitty \
--single-instance \
${1:+--instance-group "$1"} \
--start-as hidden \
--detach \
--detached-log "$(mktemp -p "$TMP_DIR" "$name.XXXXXX.log")" \
-o allow_remote_control=socket-only \
--listen-on unix:"$TMP_DIR/$name.sock"

View File

@@ -2,22 +2,24 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 Julian Prein
#
# Usage: kitty-cwd [GROUP_NAME]
#
# Print the current working directory of the focused kitty window. Returns 4 if
# none exist or is focused.
# NOTE: the backticks are used for hacky line-continuation, taken from
# https://stackoverflow.com/a/7729087/2092762c9
kitten @ --to unix:/tmp/mykitty ls \
| jq -er ".[]`
` | select(.is_focused).tabs.[]`
` | select(.is_focused).windows.[]`
` | select(.is_focused).cwd"
if [ -n "$KITTY_LISTEN_ON" ]; then
socket_path="${KITTY_LISTEN_ON#unix:}"
else
socket_path="${TMPDIR:-/tmp}/kitty.$USER/kitty${1:+-$1}.sock"
fi
[ -e "$socket_path" ] || exit 1
# An alternative version that uses recursive descent to find focused objects
# that also have a `.cwd` key:
#
# | jq -er "..`
# ` | objects`
# ` | select(.is_focused)`
# ` | to_entries.[]`
# ` | select(.key == \"cwd\").value"
# NOTE: Unfortunately kitten-@-ls(1) is slow, so communicate with the socket
# directly.
printf '\eP@kitty-cmd{%s,%s,%s}\e\\' \
'"cmd":"ls"' \
'"version":[0,26,0]' \
'"payload":{"match":"state:focused"}' \
| nc -U -q0 "$socket_path" \
| awk '{ print substr($0, 13, length($0) - 14) }' \
| jq -er ".data | fromjson | .[].tabs.[].windows.[].cwd"

View File

@@ -20,7 +20,7 @@
#: <https://sw.kovidgoyal.net/kitty/kittens/choose-fonts/#font-spec-
#: syntax>.
# font_size 11.0
font_size 12.0
#: Font size (in pts).
@@ -630,7 +630,7 @@ mouse_hide_wait -1
#: If empty (default) select_by_word_characters will be used for both
#: directions.
# click_interval -1.0
click_interval 0.4
#: The interval between successive clicks to detect double/triple
#: clicks (in seconds). Negative numbers will use the system default
@@ -1763,7 +1763,7 @@ close_on_child_death yes
#: special value of ask means that kitty will ask before opening the
#: link when clicked.
# shell_integration enabled
shell_integration no-cursor
#: Enable shell integration on supported shells. This enables features
#: such as jumping to previous prompts, browsing the output of the
@@ -2521,7 +2521,8 @@ map kitty_mod+shift+backspace change_font_size all 0
#: Open URL
map kitty_mod+e open_url_with_hints
# map kitty_mod+e open_url_with_hints
map kitty_mod+f open_url_with_hints
#:: Open a currently visible URL using the keyboard. The program used
#:: to open the URL is specified in open_url_with.

View File

@@ -6,11 +6,17 @@
# NOTE: the current file can be edited with `v` already, but this doesn't work
# when reading from stdin
# NOTE: ^P omits the "done" message
# NOTE: '' jumps back to the previous position
#
# edit in vim without any ANSI SGR sequences (e.g. color)
e noaction g|$no-ansi-sgr | nvim -\n
# edit in vim without any ANSI escape sequences (e.g. color)
e noaction g|$no-ansi | nvim -\n''
# edit in vim while keeping them
E noaction g|$nvim -\n
E noaction g|$nvim -\n''
# edit current screen in vim
^E noaction |.no-ansi | nvim -\n
# copy whole file
^Y noaction g|$xclip -selection clipboard\n''
#env
# NOTE: Lines need a trailing space when concatenating

View File

@@ -40,6 +40,7 @@ enable-ipc = true
type = internal/i3
pin-workspaces = true
format = <label-state> <label-mode>
strip-wsnames = true
index-sort = true
wrapping-scroll = false

View File

@@ -22,10 +22,11 @@ done
if ! pgrep -ax polybar >/dev/null 2>&1; then
# launch Polybar on every monitor
# https://github.com/polybar/polybar/issues/763
while read -r m; do
export MONITOR="${m%%:*}"
polybar --list-monitors \
| cut -d: -f1 \
| xargs -I'{}' -P0 \
env MONITOR='{}' \
polybar --reload -c "$BASE_DIR/config" main &
done <<<"$(polybar --list-monitors)"
echo "Polybar launched..."
else

View File

@@ -361,10 +361,12 @@ bind S set -w synchronize-panes
set -g remain-on-exit on
if -F "#{>=:#{version},3.3}" {
bind -n C-d if -F "#{pane_dead}" { kill-pane } { send }
bind -n Escape if -F "#{pane_dead}" { kill-pane } { send }
bind -n Enter if -F "#{pane_dead}" { respawn-pane } { send }
} {
# omitting the key argument was introduced in 3.3
bind -n C-d if -F "#{pane_dead}" { kill-pane } { send C-d }
bind -n Escape if -F "#{pane_dead}" { kill-pane } { send Escape }
bind -n Enter if -F "#{pane_dead}" { respawn-pane } { send Enter }
}

View File

@@ -37,18 +37,30 @@ setlocal showbreak=NONE
" This is very hacky.
" Only if WinResized is supported
if has('##WinResized')
if exists('##WinResized')
augroup man_resized
" The reload has to be delayed slightly, since with an `edit` directly in
" the autocmd, the buffer will just be cleared? (TODO)
" NOTE: One could add a wrapper function that checks for the existence of
" already running timers similar to how it's done in the
" highlight_current group (see autocommands.vim), but this feels
" overkill here.
au! WinResized <buffer> call timer_start(10, function("s:redraw_delayed"))
au! WinResized <buffer> call s:redraw_man(v:event)
augroup END
function s:redraw_man(event)
if exists('w:disable_man_resizing')
return
endif
if exists('w:man_resizing_timer_id')
call timer_stop(w:man_resizing_timer_id)
endif
echo a:event
" TODO: make sure that a:event contains window number and that the width
" actually changed with getwininfo()
let w:man_resizing_timer_id = timer_start(10, function("s:redraw_delayed"))
endfunction
" The function can't be redefined during the reload of the ftplugin (i.e.
" triggered by `edit`), since it is currently executing (i.e. `edit`):
"
@@ -56,6 +68,8 @@ augroup END
"
if !exists("*s:redraw_delayed")
function s:redraw_delayed(timer_id)
unlet w:man_resizing_timer_id
" Try to keep the position as close as possible, since edit will move to
" the start of the file
" TODO: this should be more accurate
@@ -72,5 +86,5 @@ endif
" lines, messing up the whole buffer. Since this is distracting, turn it off.
setlocal nowrap
endif " has('##WinResized')
endif " exists('##WinResized')
" ------------------------------------------------------------------------------

View File

@@ -0,0 +1,11 @@
" Either not at the start of the line, or otherwise not followed by a colon
syntax match markdownFootnoteZero /\v(.@1<=\[\^0\])|(^\[\^0\]:@!)/ conceal cchar=
syntax match markdownFootnoteOne /\v(.@1<=\[\^1\])|(^\[\^1\]:@!)/ conceal cchar=¹
syntax match markdownFootnoteTwo /\v(.@1<=\[\^2\])|(^\[\^2\]:@!)/ conceal cchar=²
syntax match markdownFootnoteThree /\v(.@1<=\[\^3\])|(^\[\^3\]:@!)/ conceal cchar=³
syntax match markdownFootnoteFour /\v(.@1<=\[\^4\])|(^\[\^4\]:@!)/ conceal cchar=
syntax match markdownFootnoteFive /\v(.@1<=\[\^5\])|(^\[\^5\]:@!)/ conceal cchar=
syntax match markdownFootnoteSix /\v(.@1<=\[\^6\])|(^\[\^6\]:@!)/ conceal cchar=
syntax match markdownFootnoteSeven /\v(.@1<=\[\^7\])|(^\[\^7\]:@!)/ conceal cchar=
syntax match markdownFootnoteEight /\v(.@1<=\[\^8\])|(^\[\^8\]:@!)/ conceal cchar=
syntax match markdownFootnoteNine /\v(.@1<=\[\^9\])|(^\[\^9\]:@!)/ conceal cchar=

View File

@@ -3,6 +3,9 @@ setlocal colorcolumn+=51
setlocal textwidth=72
" Spell checking always enabled
setlocal spell spelllang=en
" Disable C-indentation as it messes up formatting of paragraphs containing
" parentheses
setlocal nocindent
" Disable gutentags as it seems to regenerate the entire tags file when editing
" git-commits...
@@ -17,3 +20,27 @@ let g:gutentags_enabled = 0
" When aborting a commit I usually use :cq which I can't when committing through
" fugitive. Abbreviate it to something that works.
cabbrev <buffer> cq %d <Bar> x
" Fold file listings (staged, unstaged, untracked, ...) and diff
setlocal foldmethod=syntax
" Unfold staged files and diff. inspired by:
" https://vi.stackexchange.com/questions/4050/how-to-search-for-pattern-in-certain-syntax-regions/27008#27008
if has("patch-8.2.0915") || has("nvim-0.7.0")
function s:open_fold(group, content)
" Find line containing `content` that is highlighted with `group`
let l:line_nr = search(a:content, "n", 0, 0, { ->
\ synstack('.', col('.'))
\ ->map('synIDattr(v:val, "name")')
\ ->match(a:group) < 0 })
if l:line_nr <= 0
return
endif
execute l:line_nr->string() .. "foldopen"
endfunction
call s:open_fold("gitcommitSelected", "Changes to be committed:")
call s:open_fold("gitcommitDiff", "diff --")
endif " has("patch-8.2.0915") || has("nvim-0.7.0")

View File

@@ -1,5 +1,8 @@
" Turn on line-wrapping
setlocal wrap
" Disable C-indentation as it messes up formatting of paragraphs containing
" parentheses
setlocal nocindent
" Fold by sections
function! MdSectionFold()

View File

@@ -1,5 +1,8 @@
" Turn on line-wrapping
setlocal wrap
" Disable C-indentation as it messes up formatting of paragraphs containing
" parentheses
setlocal nocindent
" Close the quickfix window after a cursor movement
let g:vimtex_quickfix_autoclose_after_keystrokes = 1

View File

@@ -1,3 +1,7 @@
" Disable C-indentation as it messes up formatting of paragraphs containing
" parentheses
setlocal nocindent
" Don't highlight Unicode table separator (e.g. vertical box drawing character).
" See vimrc.d/looks.vim for w:ignore_non_ascii_chars
if vimwiki#vars#get_syntaxlocal('rxTableSep') !~ '[\d0-\d127]'

View File

@@ -15,8 +15,10 @@ endfor
" needs vim >= 8.1.1719 to support features like popup and text property as well
" as nodejs.
if ((has('patch-8.1.1719') || has('nvim')) && executable('node'))
let g:coc_global_extensions =
\ ['coc-clangd', 'coc-sh', 'coc-pyright', 'coc-vimtex', 'coc-vimlsp', 'coc-json']
let g:coc_global_extensions = [
\ 'coc-clangd', 'coc-sh', 'coc-pyright', 'coc-vimtex',
\ 'coc-vimlsp', 'coc-json', 'coc-go'
\ ]
let g:coc_config_home = $XDG_CONFIG_HOME .. "/vim"
packadd coc.nvim
endif
@@ -24,10 +26,13 @@ endif
" ctags
if (executable('ctags'))
packadd vim-gutentags
" Don't index these folders
let g:gutentags_ctags_exclude = [
\ 'node_modules/*',
\ '.git/*',
\ 'build/*'
\ 'build/*',
\ 'venv/*',
\ '__pycache__/*'
\]
endif
@@ -36,6 +41,12 @@ if (exists("g:loaded_tmux_navigator"))
let g:tmux_navigator_disable_when_zoomed = 1
endif
if (get(g:, 'loaded_fzf_vim'))
let g:fzf_vim = {}
" Use location list instead of quickfix list
let g:fzf_vim.listproc = { list -> fzf#vim#listproc#location(list) }
endif
if (get(g:, 'loaded_vimwiki'))
" Use vertical box drawing character as table separator
call vimwiki#vars#set_syntaxlocal('rxTableSep', '│')
@@ -45,4 +56,6 @@ if exists("g:loaded_nrrw_rgn")
" Open narrow window above or to the left of the current window (default
" is topleft). See :h aboveleft etc.
let g:nrrw_topbot_leftright = 'aboveleft'
" Leave one more line of padding when the window is small
let g:nrrw_rgn_pad = 1
endif

View File

@@ -6,10 +6,6 @@ if !exists('g:did_coc_loaded')
finish
endif
" Some servers have issues with backup files, see #649.
set nobackup
set nowritebackup
" Always show the signcolumn, otherwise it would shift the text each time
" diagnostics appear/become resolved.
set signcolumn=yes
@@ -68,7 +64,7 @@ endif
" Make <CR> to accept selected completion item or notify coc.nvim to format
" <C-g>u starts a new undo break, please make your own choice.
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#pum#confirm()
inoremap <silent><expr> <CR> coc#pum#visible() ? coc#_select_confirm()
\: "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"
" Use `[g` and `]g` to navigate diagnostics

View File

@@ -119,6 +119,15 @@ if (exists('g:loaded_gitgutter'))
" lines have been changed.
set foldtext=gitgutter#fold#foldtext()
endif
" Use the number column for the signcolumn (e.g. gitgutter, lsp diagnostics),
" but don't fallback to 'auto' when &number is off
" TODO: install autocommand to set signcolumn to yes when number is turned off
" (and back to number when turned back on)
if &number
set signcolumn=number
else
set signcolumn=yes
endif
" Netrw
" Use tree style listing

View File

@@ -91,40 +91,56 @@ elseif (has('terminal'))
nmap <leader><CR> <Cmd>terminal<CR>
endif
" Plugin specific bindings
if (get(g:, 'loaded_fzf'))
nmap <leader>f <Cmd>Files<CR>
nmap <leader>j <Cmd>Lines<CR>
nmap <leader>/ <Cmd>Lines<CR>
nmap <leader>h <Cmd>Helptags<CR>
" TODO: fix this?
if (get(g:, 'loaded_gutentags') || 1)
nmap <leader>t <Cmd>Tags<CR>
nmap <leader>bt <Cmd>BTags<CR>
endif
nmap <leader>ff <Cmd>Files<CR>
nmap <leader>fj <Cmd>Lines<CR>
nmap <leader>f/ <Cmd>Lines<CR>
nmap <leader>fh <Cmd>Helptags<CR>
nmap <leader>ft <Cmd>Tags<CR>
nmap <leader>fbt <Cmd>BTags<CR>
" git files that `git status` lists
nmap <leader>fgf <Cmd>GFiles?<CR>
" 'git log (log?)' and 'git log buffer '
map <leader>fgll <Cmd>Commits<CR>
map <leader>fglb <Cmd>BCommits<CR>
" TODO: <leader>fglb should restrict the log to all staged files when called
" in .git/COMMIT_EDITMSG, maybe with an ftplugin?
endif
" Search for selected text.
" Modified from https://vim.fandom.com/wiki/Search_for_visually_selected_text
function! GetVisualSelection()
let l:old_reg = getreg('"')
let l:old_regtype = getregtype('"')
" Modified version of:
" https://vim.fandom.com/wiki/Search_for_visually_selected_text
" and https://github.com/neovim/neovim/blob/08847a9ea15a/runtime/lua/vim/_defaults.lua#L73-L79
function! GetVisualSelection(escape = "", byteescape = 'n')
let l:save_reg = getreginfo('"')
norm gvy
let l:sel = getreg('"')
call setreg('"', l:old_reg, l:old_regtype)
call setreg('"', l:save_reg)
let l:sel = l:sel->escape(a:escape)
for l:char in a:byteescape
let l:sel = l:sel->substitute('\'..l:char, '\\'..l:char, 'g')
endfor
return l:sel
endfunction
vmap * /\V<C-R>=escape(GetVisualSelection(),'/\')<CR><CR>
vmap # ?\V<C-R>=escape(GetVisualSelection(),'?\')<CR><CR>
" In case these do not exist already (At the time of writing only Neovim adds
" mappings for these)
if maparg('*', 'v', 0, 1) == {}
vmap * /\V<C-R>=GetVisualSelection('/\')<CR><CR>
vmap # ?\V<C-R>=GetVisualSelection('?\')<CR><CR>
endif
" Extended `*`. Starts vim search (without jump) and ripgrep
nmap <leader>* :let @/ = '\<' . expand('<cword>') . '\>' <bar>
\ set hlsearch <bar>
\ Rg \b<C-R>=expand('<cword>')<CR>\b<CR>
vmap <leader>* :<C-U>let @/ = "\\V<C-R>=escape(escape(GetVisualSelection(), '\'), '"\')<CR>" <bar>
" TODO: pass --multiline to rg when multiple lines selected
" TODO: Use ^ and $ anchors in visual-line mode
vmap <leader>* :<C-U>let @/ = "\\V<C-R>=escape(GetVisualSelection('\'), '"\')<CR>" <bar>
\ set hlsearch <bar>
\ Rg <C-R>=escape(GetVisualSelection(), '.\[]<bar>*+?{}^$()')<CR><CR>
\ Rg <C-R>=GetVisualSelection('.\[]<bar>*+?{}^$()', 'nt')<CR><CR>
nmap <leader>g* :let @/ = expand('<cword>') <bar>
\ set hlsearch <bar>
\ Rg <C-R>=expand('<cword>')<CR><CR>
@@ -136,7 +152,8 @@ vmap <leader>/ <Esc><leader>v/
" Select last pasted text in same visual mode as it was selected (v, V, or ^V)
" Taken from: https://vim.fandom.com/wiki/Selecting_your_pasted_text
nnoremap <expr> gp '`[' . strpart(getregtype(), 0, 1) . '`]'
" TODO: I want the gp default back - find new mapping
" nnoremap <expr> gp '`[' . strpart(getregtype(), 0, 1) . '`]'
" Git bindings
@@ -153,10 +170,9 @@ nmap <leader>grc :let subject=system('git show -s --date=short --pretty="format:
nmap <leader>gso :r!git config --get user.name<CR>:r!git config --get user.email<CR>I<<ESC>A><ESC>kJISigned-off-by: <ESC>
" Add, stash or checkout the current file
" TODO: Conflict with <leader>gf
"nmap <leader>gfa <Cmd>!git add -- %<CR>
"nmap <leader>gfs <Cmd>!git stash -- %<CR>
"nmap <leader>gfu <Cmd>!git checkout -- %<CR>
nmap <leader>gfa <Cmd>!git add -- %<CR>
nmap <leader>gfs <Cmd>!git stash -- %<CR>
nmap <leader>gfu <Cmd>!git checkout -- %<CR>
if exists('g:loaded_fugitive')
" Interactive `git status`
@@ -165,6 +181,8 @@ if exists('g:loaded_fugitive')
nmap <leader>gcc <Cmd>G commit<CR>
" Amend the current commit and open the message in a split
nmap <leader>gca <Cmd>G commit --amend<CR>
" Commit with the last commit message as template
nmap <leader>gclm <Cmd>G commit-last-msg<CR>
" Move to root of directory
nmap <leader>gcd <Cmd>Gcd<CR>
" git blame in scroll bound vertical split (only the commit hashes, see
@@ -191,19 +209,12 @@ if exists('g:loaded_gitgutter')
xmap ih <Plug>(GitGutterTextObjectInnerVisual)
xmap ah <Plug>(GitGutterTextObjectOuterVisual)
" Same for hunk navigation bindings + center line
" TODO: <leader>[h to jump between **all** hunks across all modified
" files. (similar to `add -p`)
nmap [h <Plug>(GitGutterPrevHunk)zz
nmap ]h <Plug>(GitGutterNextHunk)zz
endif
if (get(g:, 'loaded_fzf'))
" git files that `git status` lists
nmap <leader>gf <Cmd>GFiles?<CR>
" 'git log (log?)' and 'git log buffer '
map <leader>gll <Cmd>Commits<CR>
map <leader>glb <Cmd>BCommits<CR>
" TODO: <leader>glb should restrict the log to all staged files when called
" in .git/COMMIT_EDITMSG, maybe with an ftplugin?
endif
" Y should behave like D & C does
nnoremap Y y$
@@ -441,7 +452,7 @@ vnoremap <leader><C-L> gu
" `ExpandVisualSelection(1)` which results in a block selection that spans over
" all other TODOs as well.
function! ExpandVisualSelection(direction)
let l:sel = escape(GetVisualSelection(), '\')
let l:sel = GetVisualSelection('\')
normal gv
" Move the cursor onto the side of the selection that points in the

View File

@@ -50,14 +50,24 @@ if (get(g:, 'loaded_fzf'))
endif
endif
" Get red from my colorscheme
let s:red = {}
if exists("*onedark#GetColors")
let s:red = onedark#GetColors()->get("red", {})
endif
let s:red_cterm = s:red->get("cterm", "red")
let s:red_gui = s:red->get("gui", "red")
" Highlight trailing whitespaces
if match(&listchars, 'trail: \@!') > -1 && match(&listchars, '\vtab:( +)@!') > -1
" Use foreground for coloring if tabs and trailing spaces are displayed
" as non-space characters
highlight TrailingWhitespace ctermfg=red guifg=red
execute "highlight TrailingWhitespace ctermfg=" .. s:red_cterm
\ .. " guifg=" .. s:red_gui
else
" Background otherwise
highlight TrailingWhitespace ctermbg=red guibg=red
execute "highlight TrailingWhitespace ctermbg=" .. s:red_cterm
\ .. " guibg=" .. s:red_gui
endif
augroup HighlightTrailingWhitespace
au!
@@ -74,8 +84,10 @@ let g:spl_special_chars = {
\ 'fr': 'àâæçèéêëîïôœùûüÿÀÂÆÇÈÉÊËÎÏÔŒÙÛÜŸ',
\ }
" Highlight non-ASCII characters in the red used by my color scheme "OneDark"
highlight NonASCIIChars ctermfg=white guifg=white ctermbg=204 guibg=#e06c75
" Highlight non-ASCII characters in red
execute "highlight NonASCIIChars ctermfg=white guifg=white "
\ .. "ctermbg=" .. s:red_cterm .. " guibg=" .. s:red_gui
" Do not highlight special characters that are valid in the respective spelllang
function! HighlightNonASCIIChars()
if exists('w:non_ascii_match_id')

View File

@@ -0,0 +1,26 @@
#!/usr/bin/env zsh
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 Julian Prein
#
# Rename a branch locally and on a given remote.
emulate -L zsh -o err_return -o no_unset
if (( # < 2 || # > 3 )); then
printf >&2 "Usage: %s OLD NEW [REMOTE]\n" "${0:t}"
return 1
fi
local old new remote
old="$1"
new="$2"
remote="${3:-origin}"
if ! git remote -v | awk '{ print $1 }' | uniq | grep -q "$remote"; then
printf >&2 "Remote '%s' does not exist\n" "$remote"
return 1
fi
git checkout-worktree "$old" <<EOF
git branch -m "$new" && git push -u && git push -d "$remote" "$old"
EOF

View File

@@ -31,11 +31,13 @@
emulate -L zsh -o err_return -o no_unset
local REPO_NAME WORKTREE_PATH
local git_dir cwd_offset REPO_NAME WORKTREE_PATH
# Use the folder name of the main working tree to make calls from another
# temporary working tree possible
REPO_NAME="${${${$(git rev-parse --git-dir):A}%%/.git*}:t}"
WORKTREE_PATH="$(mktemp -d -p "" "worktree.XXX.$REPO_NAME.${1//\//_}")"
git_dir="${$(git rev-parse --git-dir):A}"
[[ $git_dir == */.git/modules/* ]] || git_dir="${git_dir%%/.git*}"
REPO_NAME="${git_dir:t}"
WORKTREE_PATH="$(mktemp -d -p "" "wtree.$REPO_NAME.${1//\//_}.XXX")"
local errc ret=0
git worktree add "$WORKTREE_PATH" "$@" || ret=$?
@@ -47,11 +49,27 @@ fi
trap '
errc=$?
<&2 printf "Exiting abnormally. Check and possibly remove '$WORKTREE_PATH' manually.\n"
printf >&2 "Exiting abnormally. Check and possibly remove \"%s\" manually.\n" "'"$WORKTREE_PATH"'"
return $errc
' INT QUIT TERM EXIT
cwd_offset="${${PWD#$(git rev-parse --show-toplevel)}#/}"
pushd -q "$WORKTREE_PATH"
until [[ -d $cwd_offset || -z $cwd_offset ]]; do
cwd_offset="${cwd_offset:h}"
done
[[ -z $cwd_offset ]] || cd "$cwd_offset"
# Discard some environment variables that were set by git when calling this
# script through an alias.
#
# Is set for submodules and will confuse git in the subshell
unset GIT_DIR
# Not sure if this can bring any issues, but better be safe
unset GIT_PREFIX
# TODO: Do we want to unset this too? Could have been set on purpose by the user
# and not git. Maybe only for the subshell via `env`?
#unset GIT_EXEC_PATH
"$SHELL" && errc=$? || errc=$?
(( !errc )) || echo "shell exited with $errc"
@@ -59,7 +77,7 @@ pushd -q "$WORKTREE_PATH"
# Restart the shell (forcefully interactive) until the worktree is removed
until [[ ! -e "$WORKTREE_PATH" ]] || git worktree remove "$WORKTREE_PATH"; do
[[ -t 0 ]] ||
>&2 printf "Dropping into interactive shell to resolve conflicts\n"
printf >&2 "Dropping into interactive shell to resolve conflicts\n"
"$SHELL" -i && errc=$? || errc=$?
(( !errc )) || echo "shell exited with $errc"
done

View File

@@ -1,6 +1,20 @@
#!/usr/bin/env zsh
git for-each-ref --format='%(upstream),%(refname)' refs/heads refs/remotes \
local idx="${@[(ei)--help]}"
local flags_end="${@[(ei)--]}"
if (( idx < flags_end )); then
printf "Usage: $0 [--all] [REMOTE]..."
return 0
fi
idx="${@[(ei)--all]}"
if (( idx < flags_end )); then
# Replace --all flag with empty string. Will be replaced with
# refs/remotes/ later so that all remotes are listed
set -- "${@[1,$((idx-1))]}" "" "${@[$((idx+1)),-1]}"
fi
git for-each-ref --format='%(upstream),%(refname)' refs/heads "${@/#/refs/remotes/}" \
| sort -d \
| sed -Ez '
s:(^|\n|,)refs/(heads|remotes/):\1:g
@@ -8,9 +22,8 @@ git for-each-ref --format='%(upstream),%(refname)' refs/heads refs/remotes \
s:,/:,:g
s:(^|\n)([^,]+),\n\2:\1\2:g
s:(^|\n)([^/,]*)([^\n]*\n\2(,|/))*:\n,\n&:g
s:\n,\n+$:\n:
' \
| (echo remote,local; cat) \
s:\n,\n+$:\n:' \
| { echo remote,local; cat; } \
| sed -E 's:(.*),(.*):\2,\1:g; s:^,: ,:; s:,$:, :' \
| column -ts, \
| sed '2d; 1{p;s/./―/g}'

View File

@@ -105,6 +105,7 @@ local -A binds=(
"end" "last"
"ctrl-d" "half-page-down"
"ctrl-u" "half-page-up"
"ctrl-s" "toggle-sort"
"ctrl-t" "toggle-track"
# Keep the current line selected while deleting the query
"bspace" "track-current+backward-delete-char"
@@ -120,11 +121,11 @@ local -A binds=(
# TODO: This assumes less to be used in core.pager
"enter" "execute@$fzf_preview[patch] | $pager -+F@"
# Preview stats
"ctrl-s" "change-preview($fzf_preview[stat])"
"ctrl-alt-s" "change-preview($fzf_preview[stat])"
# Preview patch
"ctrl-p" "change-preview($fzf_preview[patch])"
"ctrl-alt-p" "change-preview($fzf_preview[patch])"
# Files only
"ctrl-f" "change-preview($fzf_preview[files_only])"
"ctrl-alt-f" "change-preview($fzf_preview[files_only])"
# For ctrl-space see below
)
@@ -132,13 +133,21 @@ local -A binds=(
# fzf_preview[stat] in this case). It does not really make sense to pass
# it to `git log` but can be an indicator for the preview function
local color_brown=$'\e[38;5;144m'
local color_grey=$'\e[38;5;59m'
local header=""
header+="${color_brown}Enter${color_grey}: fullscreen, "
header+="${color_brown}C-y${color_grey}: yank hash, "
header+="${color_brown}C-Space${color_grey}: cycle preview, "
header+="${color_brown}C-A-[spf]${color_grey}: preview stats/patch/files"
local -a fzf_args=(
# Understand ansi color escape sequences.
"--ansi"
# Expand the binds array in the format "key1:value1,key2:value2".
"--bind" "${(@kj:,:)binds/(#m)*/$MATCH:$binds[$MATCH]}"
# Display key-bindings in a sticky header
"--header" $'\e[38;5;144mEnter\e[38;5;59m: fullscreen, \e[38;5;144mC-y\e[38;5;59m: yank hash, \e[38;5;144mC-Space\e[38;5;59m: cycle preview, \e[38;5;144mC-[spf]\e[38;5;59m: preview stats/patch/files'
"--header" "$header"
# Keep header above prompt line
"--header-first"
# Execute git show on the commit as preview.

View File

@@ -128,7 +128,7 @@ fi
# Use a reasonable time format
alias date='env LC_TIME=tk_TM date'
# List human readable sizes in order
alias sizes='du -sch * | sort -h'
alias sizes='() { du -sch ${1:-*} "${@[2,-1]}" | sort -h }'
# Count number of occurrences for every line in stdin
alias count='sort | uniq -c | sort -n'
# Inspired by https://stackoverflow.com/a/54541337
@@ -183,7 +183,7 @@ fi
# Default flags
add_flags ls --color=auto --group-directories-first -p -v
add_flags grep --color=auto --exclude-dir=.git --exclude=tags
add_flags cp -i
add_flags cp -ia
add_flags mv -i
# Only add flags if rm is not aliased to a different command (e.g. trash).
# NOTE: This also works if rm is not yet aliased.

View File

@@ -0,0 +1 @@
../../.config/git/external-script.sh

View File

@@ -1 +0,0 @@
../../.config/git/zsh-autoload.sh

1
.local/bin/kitty-daemon Symbolic link
View File

@@ -0,0 +1 @@
../../.config/kitty/daemon.sh

View File

@@ -3,5 +3,26 @@
# Copyright (c) 2025 Julian Prein
#
# Remove ANSI escape sequences.
#
# Additionally to the general form `\e[ -/]*[0-~]` this also tries to cover
# sequences that are followed by additional bytes (e.g. CSI, OSC). This script
# covers no C1 sequences.
#
# The patterns cover the following escape sequences (from top to bottom):
# - CSI
# - OSC, DCS, PM & APC
# - SOS
# - All remaining sequences
#
# See:
# - https://en.wikipedia.org/wiki/ANSI_escape_code
# - https://www.ecma-international.org/wp-content/uploads/ECMA-35_6th_edition_december_1994.pdf
# - https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf
env LC_ALL=C sed 's/\[[0-?]*[ -/]*[@-z]//g'
env LC_ALL=C sed -E "$(printf "%b" \
's/' \
'\033\\[[0-?]*[ -/]*[@-~]' '|' \
'\033[]P^_][\010-\015 -~]*\033\\\\' '|' \
'\033X([^\033]|\033+[^\033X\\])*\033+\\\\' '|' \
'\033[ -/]*[0-~]' \
'//g')"

View File

@@ -5,4 +5,4 @@
# Remove ANSI SGR (Select Graphic Rendition) escape sequences, e.g. setting
# color or bold font.
env LC_ALL=C sed 's/\[[0-?]*[ -/]*m//g'
env LC_ALL=C sed "$(printf 's/\033\\[[0-?]*[ -/]*m//g')"

View File

@@ -62,4 +62,119 @@ git diff --staged --name-only --diff-filter=AT $against \
fi
done
[ "$abort" -eq 0 ] || die
}
} || exit
# Make sure that a deletion does not break any symlinks (including renaming a
# file)
# TODO: switch all these to null-terminated lines
deleted_files="$(git diff-index --cached --name-only --diff-filter=D $against)"
if [ -n "$deleted_files" ]; then
# First, check for broken symlinks in the tree
all_broken_links="$(find . -xtype l -exec stat -c '%N' '{}' '+')"
# NOTE: The cat could be replaced by instead adding the heredoc to the
# `done` of the loop, but would make the code much less readable
cat <<EOF \
| while read -r deletion
$deleted_files
EOF
do
# As a first heuristic, check if there is a broken symlink with
# a target with the same basename as the deleted file
#
# TODO: stat escapes quotes sometimes. Does everything work
# then?
possible_links="$(
grep "[\"'/]$(
basename "$deletion" \
| sed 's/[.[^$*\\]/\\&/g'
)[\"']\$" <<EOF
$all_broken_links
EOF
)"
[ -n "$possible_links" ] || continue
cat << EOF \
| while read -r link
$possible_links
EOF
do
# TODO: this is probably quite brittle, depending on how
# `stat` quotes source and target
target="${link##* -> [\"\']}"
target="${target%[\"\']}"
source="${link%%[\"\'] -> *}"
source="${source#[\"\']}"
if [ -z "${target##/*}" ]; then
# absolute link
if [ "$target" = "$PWD/$deletion" ]; then
die "You broke the symlink $link"
fi
else
# relative link
target="$(realpath -m "$source/../$target")"
if [ "$target" = "$PWD/$deletion" ]; then
die "You broke the symlink $link"
fi
fi
done || exit
done || exit
# Second, check all symlinks in the index if they still point to the
# deleted file
all_links_in_index="$(
git ls-files --format="%(objectmode) %(objectname) %(path)" \
| grep '^120000'
)"
cat <<EOF \
| while read -r deletion
$deleted_files
EOF
do
# As a first heuristic, get all links in the tree with a target
# with the same basename as the deleted file
possible_links="$(
cut -d' ' -f2 <<EOF \
| git cat-file --batch \
| grep -B1 "\(^\|/\)$(
basename "$deletion" \
| sed 's/[.[^$*\\]/\\&/g'
)\$" \
| paste - -
$all_links_in_index
EOF
)"
[ -n "$possible_links" ] || continue
cat << EOF \
| while read -r link
$possible_links
EOF
do
target="${link#* }"
source="$(
grep -F "${link%% *}" <<EOF \
| cut -d' ' -f3-
$all_links_in_index
EOF
)"
if [ -z "${target##/*}" ]; then
# absolute link
if [ "$target" = "$PWD/$deletion" ]; then
die "You broke the symlink \"$source\" -> \"$target\""
fi
else
# relative link
target="$(realpath -m "$source/../$target")"
if [ "$target" = "$PWD/$deletion" ]; then
die "You broke the symlink \"$source\" -> \"$target\""
fi
fi
done || exit
done || exit
# TODO: also check potential symlinks pointing to now empty directories
fi