├── .devcontainer └── devcontainer.json ├── .github └── workflows │ └── emacs.yml ├── .gitignore ├── .gitmodules ├── MAPPING ├── SourceCodePro-Regular.ttf ├── XCompose ├── Xmodmap_us_neo ├── Xresources ├── config ├── dunst │ └── dunstrc ├── emacs │ ├── custom.el │ ├── init.el │ ├── layouts │ │ └── zkj.window-layout │ └── lisp │ │ ├── zkj-emacs.el │ │ ├── zkj-gbp.el │ │ ├── zkj-go.el │ │ ├── zkj-hugo.el │ │ ├── zkj-lisp.el │ │ ├── zkj-live-reload.el │ │ ├── zkj-notmuch.el │ │ ├── zkj-perl.el │ │ └── zkj-protobuf.el ├── fontconfig │ └── fonts.conf ├── gtk-3.0 │ └── settings.ini ├── i3 │ └── config ├── i3status │ └── config └── systemd │ └── user │ └── hugo.service ├── cwd-spawn ├── devscripts ├── diff-rel ├── dupload.conf ├── gbp.conf ├── gdbinit ├── gitconfig ├── gitignore ├── gocode ├── bin │ ├── configfiles │ ├── configfiles.amd64 │ └── configfiles.arm64 └── src │ └── configfiles │ ├── Makefile │ ├── configfiles-updater.service │ ├── gitresolve.go │ ├── go.mod │ ├── go.sum │ └── main.go ├── gpg.conf ├── initialize.sh ├── lintianrc ├── midna └── Xmodmap ├── mplayer.config ├── poc-template.c ├── poc-template.go ├── poc-template.pl ├── screen-logs-session.zsh ├── screenrc ├── screenrc-mqtt.zsh ├── screenrc-router7-serial.zsh ├── screenrc-syslog.zsh ├── tex-template-slides.tex ├── tmux.conf ├── travis ├── Dockerfile └── emacs-starts-up.bash ├── update.sh ├── urxvt-fonts ├── urxvt-for-emacs ├── urxvt-mark-yank-urls ├── vimrc ├── xsession ├── zmacsclient ├── zshenv └── zshrc /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "mcr.microsoft.com/vscode/devcontainers/base:bookworm", 3 | "features": { 4 | "ghcr.io/devcontainers/features/go:1": {} 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.github/workflows/emacs.yml: -------------------------------------------------------------------------------- 1 | name: Emacs 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | startup: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Build Docker container with Emacs 17 | run: | 18 | docker build --pull --no-cache --rm -t=emacs -f travis/Dockerfile . 19 | 20 | - name: verify Emacs starts up without error 21 | run: | 22 | docker run \ 23 | --init \ 24 | --volume $PWD:/root/configfiles \ 25 | emacs \ 26 | travis/emacs-starts-up.bash 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .logs 2 | gocode/pkg 3 | gocode/bin/configfiles 4 | config/google-chrome* 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "gocode/src/github.com/godbus/dbus"] 2 | path = gocode/src/github.com/godbus/dbus 3 | url = git://github.com/godbus/dbus 4 | [submodule "gocode/src/github.com/nightlyone/lockfile"] 5 | path = gocode/src/github.com/nightlyone/lockfile 6 | url = git://github.com/nightlyone/lockfile 7 | -------------------------------------------------------------------------------- /MAPPING: -------------------------------------------------------------------------------- 1 | mplayer.config ~/.mplayer/config 2 | gpg.conf ~/.gnupg/gpg.conf 3 | urxvt-mark-yank-urls ~/.urxvt/ext/mark-yank-urls 4 | urxvt-fonts ~/.urxvt/ext/fonts 5 | cwd-spawn ~/.urxvt/ext/cwd-spawn 6 | SourceCodePro-Regular.ttf ~/.fonts/SourceCodePro-Regular.ttf 7 | urxvt-for-emacs ~/.local/bin/urxvt-for-emacs 8 | -------------------------------------------------------------------------------- /SourceCodePro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stapelberg/configfiles/95def678d9119b99a7d478863b6b113114a6aea4/SourceCodePro-Regular.ttf -------------------------------------------------------------------------------- /Xmodmap_us_neo: -------------------------------------------------------------------------------- 1 | !! ~/.xmodmap 2 | !! 3 | !! German Neo-Layout 4 | !! adopted 2004 by Hanno Behrens 5 | !! inspired by Dvorak/de-ergo http://www.goebel-consult.de/de-ergo/ 6 | !! Authors: 7 | !! Benjamin Kellermann 8 | !! Erik Streb 9 | !! Pascal Hauck 10 | !! 11 | !! Other Questions: 12 | !! 13 | !! 14 | !! $Revision: 2332 $, $Date: 2010-08-06 08:42:35 +0200 (Fri, 06 Aug 2010) $ 15 | !! http://neo-layout.org 16 | !! 17 | !! To try the layout in this file, simply do xmodmap . 18 | !! To load the layout in this file at X startup, simply store it as 19 | !! ~/.xmodmap 20 | 21 | 22 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 23 | ! Ebenen 24 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 25 | ! Ebene 1: normal 26 | ! Ebene 2: Shift 27 | ! Ebene 3: Mod3 28 | ! Ebene 4: Mod4 (zum Markieren Shift+Mod4) 29 | ! Ebene 5: Shift+Mod3 30 | ! Ebene 6: Mod3+Mod4 (in dieser Reihenfolge!) 31 | ! Ebene 7: wird (bis auf technisch bedingte Ausnahmen) nicht belegt 32 | ! Multi_key=Compose (keine eigene Ebene): Mod3+Tab or right window key 33 | ! Feststellen/Shift_Lock: Shift+Shift 34 | ! Mod4_Lock: Mod4(rechts)+Mod4(links) 35 | 36 | ! Reihenfolge der Ebenen in der Xmodmap: 37 | ! Ebene1 Ebene2 Ebene3 Ebene5 Ebene4 Ebene4+Sh Ebene6 Ebene7 38 | 39 | 40 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 41 | ! Modifier definition 42 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 43 | clear Lock 44 | clear Mod2 45 | ! Mod2 war NumLock ! 46 | clear Mod3 47 | clear Mod5 48 | 49 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 50 | ! Shift 51 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 52 | ! 50=left 62=right 53 | ! Shift+Shift ergibt ein ShiftLock (wie Caps, wirkt aber auf alle Zeichen, nicht nur auf Großbuchstaben) 54 | ! Der Lock lässt sich durch ein weiteres Shift lösen. 55 | ! Eigentlich (siehe Referenz) sollte hier ein CapsLock stehen. 56 | keycode 50 = Shift_L Shift_Lock 57 | keycode 62 = Shift_R Shift_Lock 58 | 59 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 60 | ! Mod3 61 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 62 | ! 66=left 51=right 63 | ! Make CapsLock an modifier called Mod3 (similar to AltGr) (Mode_switch or ISO_Group_Shift is for 3rd and 4th level) 64 | ! Make former CapsLock and qwertz-# to Mode_switch or ISO_Group_Shift 65 | ! Mod3(links) (=Qwertz-Caps) erlaubt nur 4 Ebenen 66 | ! Ohne einen Eintrag in der zweiten Gruppe (=Ebene 3) ergäbe Mod3+Mod3=Group_Shift+Group_Shift=Gruppe 3=Ebene 6. Das ist nicht gewünscht. 67 | keycode 66 = ISO_Group_Shift ISO_Group_Shift ISO_First_Group NoSymbol 68 | keycode 51 = ISO_Group_Shift ISO_Group_Shift ISO_First_Group NoSymbol 69 | 70 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 71 | ! Mod4 72 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 73 | ! 94=left 113=right 74 | ! Make the former AltGr and qwertz-< to Mod4 (ISO_Level3_Shift) 75 | ! Mod4(rechts)+Mod4(links) lässt Mod4 einrasten (Mod4Lock) 76 | ! das funktioniert nur in dieser Reihenfolge, da Mod4(rechts) (=Qwertz-AltGr) nur 4 Ebenen hat 77 | ! Der Lock lässt sich durch ein weiteres Mod4 lösen. 78 | keysym less = ISO_Level3_Shift ISO_Level3_Shift ISO_Group_Shift ISO_Group_Shift ISO_Level3_Lock NoSymbol 79 | keysym ISO_Level3_Shift = ISO_Level3_Shift ISO_Level3_Shift ISO_Group_Shift ISO_Group_Shift ISO_Level3_Lock NoSymbol 80 | 81 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 82 | ! window keys 83 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 84 | ! keysym Super_L = Super_L 85 | ! keycode 116 = Super_R 86 | ! keysym Super_R = Multi_key Multi_key 87 | ! add Mod4 = Super_L 88 | 89 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 90 | ! general Lock 91 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 92 | ! Einrasten über linke Win-Taste+Modifier, Lösen über nochmaliges Betätigen des Modifiers 93 | ! Shift_Lock und Mo4_Lock funktionieren, Mod3_Lock lässt sich aber nicht mehr lösen!!!! 94 | ! keycode 115 = ISO_Lock NoSymbol 95 | ! add Lock = ISO_Lock 96 | 97 | 98 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 99 | ! main keyboard 100 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 101 | 102 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 103 | ! Tab key 104 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 105 | keycode 23 = Tab ISO_Left_Tab Multi_key ISO_Level3_Lock 106 | 107 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 108 | ! Space and Return key 109 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 110 | keycode 65 = space space space nobreakspace KP_0 KP_0 U202F NoSymbol 111 | keycode 36 = Return Return Return Return KP_Enter KP_Enter Return Return 112 | 113 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 114 | ! dead keys 115 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 116 | ! Ebene1 Ebene2 Ebene3 Ebene5 Ebene4 Ebene4+Sh Ebene6 Ebene7 117 | 118 | keycode 9 = dead_circumflex dead_caron U21BB U02DE dead_abovedot Pointer_EnableKeys dead_belowdot NoSymbol 119 | 120 | keycode 49 = Escape 121 | 122 | ! called T1 ˆ ˇ ↻ ˞ ˙ (keypad-mouse mode) . 123 | keycode 21 = dead_grave dead_cedilla dead_abovering dead_dasia dead_diaeresis NoSymbol dead_macron NoSymbol 124 | ! called T2 ` ¸ ˚ ῾ dasia (asper) ¨ ¯ 125 | keycode 35 = dead_acute dead_tilde dead_stroke dead_psili dead_doubleacute NoSymbol dead_breve NoSymbol 126 | ! called T3 ´ ˜ / ᾿ psili (lenis) ˝ ˘ 127 | 128 | 129 | 130 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 131 | ! The first row (number Row) 132 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 133 | ! Ebene1 Ebene2 Ebene3 Ebene5 Ebene4 Ebene4+Sh Ebene6 Ebene7 134 | 135 | keycode 10 = 1 degree onesuperior onesubscript ordfeminine NoSymbol notsign NoSymbol 136 | ! ° ¹ ₁ ª ¬ 137 | keycode 11 = 2 section twosuperior twosubscript masculine NoSymbol logicalor NoSymbol 138 | ! § ² ₂ º ∨ 139 | keycode 12 = 3 U2113 threesuperior threesubscript numerosign NoSymbol logicaland NoSymbol 140 | ! ℓ liter ³ ₃ № ∧ 141 | keycode 13 = 4 guillemotright U203A femalesymbol NoSymbol NoSymbol U22A5 NoSymbol 142 | ! » › ♀ ⊥ perpendicular 143 | keycode 14 = 5 guillemotleft U2039 malesymbol periodcentered NoSymbol U2221 NoSymbol 144 | ! « ‹ ♂ · ∡ angle sign 145 | keycode 15 = 6 dollar cent U26A5 sterling NoSymbol U2225 NoSymbol 146 | ! $ ¢ ⚥ £ ∥ parallel 147 | 148 | keycode 16 = 7 EuroSign yen U03F0 currency NoSymbol rightarrow NoSymbol 149 | ! € ¥ ϰ Greek_kappa ¤ → 150 | keycode 17 = 8 doublelowquotemark singlelowquotemark leftanglebracket Tab ISO_Left_Tab infinity NoSymbol 151 | ! „ ‚ ⟨ (bra) ∞ 152 | keycode 18 = 9 leftdoublequotemark leftsinglequotemark rightanglebracket KP_Divide KP_Divide variation NoSymbol 153 | ! “ ‘ ⟩ (ket) / / ∝ proportional to 154 | keycode 19 = 0 rightdoublequotemark rightsinglequotemark zerosubscript KP_Multiply KP_Multiply emptyset NoSymbol 155 | ! ” ’ ₀ * * ∅ 156 | keycode 20 = minus emdash NoSymbol U2011 KP_Subtract KP_Subtract hyphen NoSymbol 157 | ! - — ‑ non-breaking - - ­ soft hyphen 158 | 159 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 160 | ! The upper row 161 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 162 | ! Ebene1 Ebene2 Ebene3 Ebene5 Ebene4 Ebene4+Sh Ebene6 Ebene7 163 | 164 | keycode 24 = x X ellipsis Greek_xi Prior Prior Greek_XI Greek_XI 165 | ! … ξ Ξ Ξ 166 | keycode 25 = v V underscore NoSymbol BackSpace BackSpace radical NoSymbol 167 | ! _ √ 168 | keycode 26 = l L bracketleft Greek_lambda Up Up Greek_LAMBDA Greek_LAMBDA 169 | ! [ λ Λ Λ 170 | keycode 27 = c C bracketright Greek_chi Delete Delete U2102 NoSymbol 171 | ! ] χ ℂ komplex 172 | keycode 28 = w W asciicircum Greek_omega Next Next Greek_OMEGA Greek_OMEGA 173 | ! ^ ω Ω Ω 174 | 175 | keycode 29 = k K exclam Greek_kappa exclamdown NoSymbol multiply NoSymbol 176 | ! ! κ ¡ × times 177 | keycode 30 = h H less Greek_psi KP_7 KP_7 Greek_PSI Greek_PSI 178 | ! < η Ψ Ψ 179 | keycode 31 = g G greater Greek_gamma KP_8 KP_8 Greek_GAMMA Greek_GAMMA 180 | ! > γ Γ Γ 181 | keycode 32 = f F equal Greek_phi KP_9 KP_9 Greek_PHI Greek_PHI 182 | ! = φ Φ Φ 183 | keycode 33 = q Q ampersand U03D5 KP_Add KP_Add U211A NoSymbol 184 | ! & ϕ Greek_phi + + ℚ rational 185 | keycode 34 = ssharp U1E9E U017F Greek_finalsmallsigma U2212 NoSymbol jot NoSymbol 186 | ! ß ẞ Capital ß ſ long s ς − real minus ∘ ring operator 187 | 188 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 189 | ! The home row (middle row) 190 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 191 | ! Ebene1 Ebene2 Ebene3 Ebene5 Ebene4 Ebene4+Sh Ebene6 Ebene7 192 | 193 | keycode 38 = u U backslash NoSymbol Home Home includedin NoSymbol 194 | ! \ ⊂ 195 | keycode 39 = i I slash Greek_iota Left Left integral NoSymbol 196 | ! / ι ∫ 197 | keycode 40 = a A braceleft Greek_alpha Down Down U2200 NoSymbol 198 | ! { α ∀ for all 199 | keycode 41 = e E braceright Greek_epsilon Right Right U2203 NoSymbol 200 | ! } ε ∃ there exists 201 | keycode 42 = o O asterisk Greek_omicron End End elementof NoSymbol 202 | ! * ο ∈ 203 | 204 | keycode 43 = s S question Greek_sigma questiondown NoSymbol Greek_SIGMA Greek_SIGMA 205 | ! ? σ ¿ Σ Σ 206 | keycode 44 = n N parenleft Greek_nu KP_4 KP_4 U2115 NoSymbol 207 | ! ( ν ℕ natural 208 | keycode 45 = r R parenright Greek_rho KP_5 KP_5 U211D NoSymbol 209 | ! ) ρ ℝ real 210 | keycode 46 = t T minus Greek_tau KP_6 KP_6 partialderivative 211 | ! - τ ∂ 212 | keycode 47 = d D colon Greek_delta KP_Separator comma Greek_DELTA Greek_DELTA 213 | ! : δ , , Δ Δ 214 | keycode 48 = y Y at Greek_upsilon period KP_Decimal nabla NoSymbol 215 | ! @ υ . . ∇ 216 | 217 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 218 | ! The lower row 219 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 220 | ! Ebene1 Ebene2 Ebene3 Ebene5 Ebene4 Ebene4+Sh Ebene6 Ebene7 221 | 222 | keycode 52 = udiaeresis Udiaeresis numbersign NoSymbol Escape Escape union NoSymbol 223 | ! ü Ü # ∪ 224 | keycode 53 = odiaeresis Odiaeresis dollar U03F5 Tab ISO_Left_Tab intersection NoSymbol 225 | ! ö Ö $ ϵ ∩ 226 | keycode 54 = adiaeresis Adiaeresis bar Greek_eta Insert Insert U2135 NoSymbol 227 | ! ä Ä | η ℵ 228 | keycode 55 = p P asciitilde Greek_pi Return Return Greek_PI Greek_PI 229 | ! ~ π Π Π 230 | keycode 56 = z Z grave Greek_zeta Undo Redo U2124 NoSymbol 231 | ! ` ζ ℤ integers 232 | 233 | keycode 57 = b B plus Greek_beta colon NoSymbol U21D0 NoSymbol 234 | ! + β : ⇐ 235 | keycode 58 = m M percent Greek_mu KP_1 KP_1 ifonlyif NoSymbol 236 | ! % μ ⇔ 237 | keycode 59 = comma endash quotedbl U03F1 KP_2 KP_2 U21D2 NoSymbol 238 | ! , – " ϱ Greek_rho ⇒ implies 239 | keycode 60 = period enfilledcircbullet apostrophe U03D1 KP_3 KP_3 U21A6 NoSymbol 240 | ! . • ' ϑ Greek_theta ↦ 241 | keycode 61 = j J semicolon Greek_theta semicolon NoSymbol Greek_THETA Greek_THETA 242 | ! ; θ ; Θ 243 | 244 | 245 | 246 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 247 | ! Keypad 248 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 249 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 250 | ! The uppest row 251 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 252 | ! Ebene1 Ebene2 Ebene3 Ebene5 Ebene6 Ebene7 Ebene4 Ebene4+Sh 253 | 254 | keycode 77 = Tab ISO_Left_Tab equal approxeq identical NoSymbol notequal Pointer_EnableKeys 255 | ! = ≈ almost equal ≡ identical to ≠ (keypad-mouse mode) 256 | keysym KP_Divide = KP_Divide KP_Divide division U2300 U2223 NoSymbol U2044 NoSymbol 257 | ! / / ÷ ⌀ diameter ∣ divides (for ⁶⁄₅₉) 258 | keycode 63 = KP_Multiply KP_Multiply U22C5 U2299 U2297 NoSymbol multiply NoSymbol 259 | ! * * ⋅ dot ⊙ cirled dot ⊗ circled times × times 260 | keycode 82 = KP_Subtract KP_Subtract U2212 U2296 U2238 NoSymbol U2216 NoSymbol 261 | ! - - − real minus ⊖ cirled minus ∸ dot minus ∖ set minus 262 | 263 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 264 | ! The upper row 265 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 266 | ! Ebene1 Ebene2 Ebene3 Ebene5 Ebene6 Ebene7 Ebene4 Ebene4+Sh 267 | 268 | keycode 79 = KP_7 U2714 U2195 U226A upstile NoSymbol KP_Home KP_Home 269 | ! ✔ check mark ↕ arrow ≪ much less ⌈ 270 | keycode 80 = KP_8 U2718 uparrow intersection U22C2 NoSymbol KP_Up KP_Up 271 | ! ✘ ballot x ↑ ∩ ⋂ n-ary intersection 272 | keycode 81 = KP_9 dagger U20D7 U226B U2309 NoSymbol KP_Prior KP_Prior 273 | ! † vector ≫ much greater ⌉ 274 | keycode 86 = KP_Add KP_Add plusminus U2295 U2214 NoSymbol U2213 NoSymbol 275 | ! + + ± circled plus dot plus ∓ minus-plus 276 | 277 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 278 | ! The middle row 279 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 280 | ! Ebene1 Ebene2 Ebene3 Ebene5 Ebene6 Ebene7 Ebene4 Ebene4+Sh 281 | 282 | keycode 83 = KP_4 club leftarrow includedin U2286 NoSymbol KP_Left KP_Left 283 | ! ♣ ← ⊂ ⊆ 284 | keycode 84 = KP_5 EuroSign colon U22B6 U22B7 NoSymbol KP_Begin KP_Begin 285 | ! € : ⊶ original of ⊷ image of 286 | keycode 85 = KP_6 U2023 rightarrow includes U2287 NoSymbol KP_Right KP_Right 287 | ! ‣ → ⊃ ⊇ 288 | 289 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 290 | ! The lower row 291 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 292 | ! Ebene1 Ebene2 Ebene3 Ebene5 Ebene6 Ebene7 Ebene4 Ebene4+Sh 293 | 294 | keycode 87 = KP_1 diamond U2194 lessthanequal downstile NoSymbol KP_End KP_End 295 | ! ♦ ↔ arrow ≤ ⌊ 296 | keycode 88 = KP_2 heart downarrow union U22C3 NoSymbol KP_Down KP_Down 297 | ! ♥ ↓ ∪ ⋃ n-ary union 298 | keycode 89 = KP_3 U2660 U21CC greaterthanequal U230B NoSymbol KP_Next KP_Next 299 | ! ♠ ⇌ ≥ ⌋ 300 | ! keycode 108 = KP_Enter KP_Enter KP_Enter KP_Enter KP_Enter KP_Enter KP_Enter KP_Enter 301 | ! 302 | 303 | 304 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 305 | ! The lowest row 306 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 307 | ! Ebene1 Ebene2 Ebene3 Ebene5 Ebene6 Ebene7 Ebene4 Ebene4+Sh 308 | 309 | keycode 90 = KP_0 U2423 percent U2030 U25A1 NoSymbol KP_Insert KP_Insert 310 | ! ␣ space sign % ‰ per mille □ white square 311 | keycode 91 = KP_Separator period comma minutes seconds NoSymbol KP_Delete KP_Delete 312 | ! , . , ′ min,feets ″ sec,inches 313 | 314 | 315 | add Mod3 = ISO_First_Group 316 | add Mod5 = ISO_Level3_Shift 317 | 318 | 319 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 320 | ! Bemerkungen 321 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 322 | ! 1.) Ebene 6 (hier: der 7. Eintrag) erreicht man über ISO_Group_Shift+ISO_Group_Shift 323 | ! (bzw. mode_switch+mode_switch) und über keine andere mir bekannte Kombination. Insbesondere legt 324 | ! ISO_Level3_Shift Level3 (Ebene 4, hier: Eintrag 5) fest, verschiebt also nicht. Darum kann man 325 | ! ISO_Level3_Shift nur mit Shift sinnvoll kombinieren. Daraus resultiert, dass Ebene 6 nur über 326 | ! Mod3+Mod4 (in dieser Reihenfolge!) erreicht werden kann. 327 | ! 328 | ! 2.) Die KP_-Einträge ermöglichen die Steuerung des Mauscursors mit der Tastatur. 329 | ! Hierzu wird mittels Shift+Mod4+T1 dieser Betriebsmodus ein- und später wieder ausgeschaltet. 330 | ! Die Steuerung des Cursors kann über den Ziffernblock (Ebene 4, eventuell mit 331 | ! eingerastetem Mod4) erfolgen. 332 | -------------------------------------------------------------------------------- /Xresources: -------------------------------------------------------------------------------- 1 | Emacs*toolBar: 0 2 | Emacs*menuBar: 0 3 | Emacs*verticalScrollBars: off 4 | 5 | !*font: -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 6 | URxvt.font: xft:Bitstream Vera Sans Mono:size=8 7 | URxvt.letterSpace: -1 8 | 9 | URxvt.jumpScroll: true 10 | URxvt.skipScroll: true 11 | URxvt.saveLines: 32768 12 | URxvt.scrollBar: false 13 | URxvt.background: black 14 | URxvt.foreground: lightgrey 15 | URxvt.internalBorder: 1 16 | URxvt.cursorBlink: 0 17 | URxvt.visualBell: off 18 | URxvt.keysym.Mod1-u: perl:mark-yank-urls:activate_mark_mode 19 | URxvt.keysym.Mod4-p: perl:fonts:plus 20 | URxvt.keysym.Mod4-m: perl:fonts:minus 21 | URxvt.keysym.Mod4-o: perl:cwd-spawn 22 | URxvt.keysym.Mod4-s: perl:searchable-scrollback:start 23 | URxvt.underlineURLs: false 24 | URxvt.perl-ext: selection,mark-yank-urls,cwd-spawn,selection-to-clipboard 25 | URxvt.urlLauncher: google-chrome 26 | URxvt.urgentOnBell: true 27 | URxvt.scrollstyle: next 28 | !URxvt.color4: #496AA0 29 | !URxvt.color12: #11AAFF 30 | 31 | 32 | URxvt*color0 : #2E3436 33 | URxvt*color8 : #555753 34 | ! red 35 | URxvt*color1 : #CC0000 36 | URxvt*color9 : #EF2929 37 | ! green 38 | URxvt*color2 : #4E9A06 39 | URxvt*color10 : #8AE234 40 | ! yellow 41 | URxvt*color3 : #C4A000 42 | URxvt*color11 : #FCE94F 43 | ! blue 44 | URxvt*color4 : #3465A4 45 | URxvt*color12 : #729FCF 46 | ! magenta 47 | URxvt*color5 : #EF33C0 48 | URxvt*color13 : #EE38DA 49 | ! cyan 50 | URxvt*color6 : #04B5B8 51 | URxvt*color14 : #34E2E2 52 | ! white 53 | URxvt*color7 : #D3D7CF 54 | URxvt*color15 : #EEEEEC 55 | 56 | !Xft.hinting: 1 57 | !Xft.hintstyle: hintslight 58 | !Xft.antialias: 1 59 | !Xft.rgba: rgb 60 | 61 | ! SRVR_midna is defined by xrdb(1) when connected to the X11 display with 62 | ! hostname midna, see https://manpages.debian.org/stretch/x11-xserver-utils/xrdb.1 63 | #ifdef SRVR_midna 64 | ! https://michael.stapelberg.de/posts/2017-12-11-dell-up3218k/ 65 | Xft.dpi: 288 66 | #else 67 | Xft.dpi: 192 68 | #endif 69 | 70 | Xft.autohint: 0 71 | Xft.lcdfilter: lcddefault 72 | Xft.hintstyle: hintslight 73 | Xft.hinting: 1 74 | Xft.antialias: 1 75 | Xft.rgba: rgb 76 | 77 | !*background: black 78 | !*foreground: lightgrey 79 | 80 | Xcursor.theme: Adwaita 81 | 82 | XTerm.vt100.termName: xterm-256color 83 | 84 | XTerm.vt100.bellIsUrgent: true 85 | 86 | XTerm.vt100.foreground: lightgrey 87 | XTerm.vt100.background: black 88 | 89 | XTerm.vt100.faceName: Bitstream Vera Sans Mono:size=8:antialias=true 90 | 91 | XTerm.vt100.color0: #2E3436 92 | XTerm.vt100.color8: #555753 93 | ! red 94 | XTerm.vt100.color1: #CC0000 95 | XTerm.vt100.color9: #EF2929 96 | ! green 97 | XTerm.vt100.color2 : #4E9A06 98 | XTerm.vt100.color10 : #8AE234 99 | ! yellow 100 | XTerm.vt100.color3 : #C4A000 101 | XTerm.vt100.color11 : #FCE94F 102 | ! blue 103 | XTerm.vt100.color4 : #3465A4 104 | XTerm.vt100.color12 : #729FCF 105 | ! magenta 106 | XTerm.vt100.color5 : #EF33C0 107 | XTerm.vt100.color13 : #EE38DA 108 | ! cyan 109 | XTerm.vt100.color6 : #04B5B8 110 | XTerm.vt100.color14 : #34E2E2 111 | ! white 112 | XTerm.vt100.color7 : #D3D7CF 113 | XTerm.vt100.color15 : #EEEEEC 114 | 115 | ! These were taken from xterm(1), then prepended with a colon as per 116 | ! https://lists.neo-layout.org/pipermail/diskussion/2009-May/000265.html 117 | XTerm*VT100.translations: #replace \n\ 118 | :Shift Prior:scroll-back(1,halfpage) \n\ 119 | :Shift Next:scroll-forw(1,halfpage) \n\ 120 | :Shift Select:select-cursor-start() \ 121 | select-cursor-end(SELECT, CUT_BUFFER0) \n\ 122 | :Shift Insert:insert-selection(SELECT, CUT_BUFFER0) \n\ 123 | :Alt Return:fullscreen() \n\ 124 | Scroll_Lock:scroll-lock() \n\ 125 | :Shift~Ctrl KP_Add:larger-vt-font() \n\ 126 | :Shift Ctrl KP_Add:smaller-vt-font() \n\ 127 | :Shift KP_Subtract:smaller-vt-font() \n\ 128 | ~Meta :insert-seven-bit() \n\ 129 | Meta :insert-eight-bit() \n\ 130 | !Ctrl :popup-menu(mainMenu) \n\ 131 | !Lock Ctrl :popup-menu(mainMenu) \n\ 132 | !Lock Ctrl @Num_Lock :popup-menu(mainMenu) \n\ 133 | ! @Num_Lock Ctrl :popup-menu(mainMenu) \n\ 134 | ~Meta :select-start() \n\ 135 | ~Meta :select-extend() \n\ 136 | !Ctrl :popup-menu(vtMenu) \n\ 137 | !Lock Ctrl :popup-menu(vtMenu) \n\ 138 | !Lock Ctrl @Num_Lock :popup-menu(vtMenu) \n\ 139 | ! @Num_Lock Ctrl :popup-menu(vtMenu) \n\ 140 | ~Ctrl ~Meta :ignore() \n\ 141 | Meta :clear-saved-lines() \n\ 142 | ~Ctrl ~Meta :insert-selection(SELECT, CUT_BUFFER0) \n\ 143 | !Ctrl :popup-menu(fontMenu) \n\ 144 | !Lock Ctrl :popup-menu(fontMenu) \n\ 145 | !Lock Ctrl @Num_Lock :popup-menu(fontMenu) \n\ 146 | ! @Num_Lock Ctrl :popup-menu(fontMenu) \n\ 147 | ~Ctrl ~Meta :start-extend() \n\ 148 | ~Meta :select-extend() \n\ 149 | Ctrl :scroll-back(1,halfpage,m) \n\ 150 | Lock Ctrl :scroll-back(1,halfpage,m) \n\ 151 | Lock @Num_Lock Ctrl :scroll-back(1,halfpage,m) \n\ 152 | @Num_Lock Ctrl :scroll-back(1,halfpage,m) \n\ 153 | :scroll-back(5,line,m) \n\ 154 | Ctrl :scroll-forw(1,halfpage,m) \n\ 155 | Lock Ctrl :scroll-forw(1,halfpage,m) \n\ 156 | Lock @Num_Lock Ctrl :scroll-forw(1,halfpage,m) \n\ 157 | @Num_Lock Ctrl :scroll-forw(1,halfpage,m) \n\ 158 | :scroll-forw(5,line,m) \n\ 159 | :select-end(SELECT, CUT_BUFFER0) \n\ 160 | :ignore() 161 | -------------------------------------------------------------------------------- /config/dunst/dunstrc: -------------------------------------------------------------------------------- 1 | [global] 2 | font = DejaVu Sans Mono 32 3 | sort = yes 4 | indicate_hidden = yes 5 | alignment = left 6 | show_age_threshold = 99999 7 | word_wrap = yes 8 | ignore_newline = no 9 | origin = top-left 10 | # dunst 1.9 gained hidpi support, so the offset is scaled 11 | offset = 946x333 12 | #offset = 2840x1000 13 | width = (500, 750) 14 | height = 500 15 | transparency = 0 16 | idle_threshold = 0 17 | follow = mouse 18 | show_indicators = yes 19 | line_height = 0 20 | markup = full 21 | separator_height = 2 22 | padding = 8 23 | horizontal_padding = 8 24 | separator_color = frame 25 | dmenu = /usr/bin/dmenu -p dunst: 26 | browser = /usr/bin/x-www-browser 27 | icon_position = left 28 | format = "%s\n%b" 29 | mouse_right_click = do_action 30 | frame_width = 5 31 | 32 | # before dunst v1.7: 33 | #[frame] 34 | # color = "#222222" 35 | 36 | [urgency_low] 37 | # IMPORTANT: colors have to be defined in quotation marks. 38 | # Otherwise the "#" and following would be interpreted as a comment. 39 | background = "#000000" 40 | foreground = "#888888" 41 | timeout = 5 42 | 43 | [urgency_normal] 44 | background = "#000000" 45 | foreground = "#ffffff" 46 | timeout = 5 47 | 48 | [urgency_critical] 49 | background = "#900000" 50 | foreground = "#ffffff" 51 | timeout = 5 52 | 53 | # vim: ft=cfg 54 | -------------------------------------------------------------------------------- /config/emacs/custom.el: -------------------------------------------------------------------------------- 1 | (custom-set-faces 2 | ;; custom-set-faces was added by Custom. 3 | ;; If you edit it by hand, you could mess it up, so be careful. 4 | ;; Your init file should contain only one such instance. 5 | ;; If there is more than one, they won't work right. 6 | '(message-header-to ((t (:foreground "green" :weight normal))))) 7 | (custom-set-variables 8 | ;; custom-set-variables was added by Custom. 9 | ;; If you edit it by hand, you could mess it up, so be careful. 10 | ;; Your init file should contain only one such instance. 11 | ;; If there is more than one, they won't work right. 12 | '(ag-arguments (quote ("--case-sensitive" "--stats" "--follow"))) 13 | '(clang-format-executable "clang-format-3.8") 14 | '(godoc-at-point-function (quote godoc-gogetdoc)) 15 | '(magit-status-sections-hook 16 | (quote 17 | (magit-insert-status-headers magit-insert-merge-log magit-insert-rebase-sequence magit-insert-am-sequence magit-insert-sequencer-sequence magit-insert-bisect-output magit-insert-bisect-rest magit-insert-bisect-log magit-insert-unstaged-changes magit-insert-staged-changes magit-insert-stashes magit-insert-untracked-files magit-insert-unpulled-from-upstream magit-insert-unpulled-from-pushremote magit-insert-unpushed-to-upstream magit-insert-unpushed-to-pushremote))) 18 | '(org-agenda-files (quote ("~/NoName/rgb2r-orga/2019-rgb2r-orga-tasks.org"))) 19 | '(package-selected-packages 20 | (quote 21 | (dash lsp-mode window-purpose esup use-package google-this term-keys bind-key go-mode eieio xelb diff-hl better-shell ssh go-rename editorconfig clang-format smex livereload websocket protobuf-mode magit gotest go-guru go-eldoc crontab-mode ag)))) 22 | -------------------------------------------------------------------------------- /config/emacs/init.el: -------------------------------------------------------------------------------- 1 | ;;;; © 2012-2013 Michael Stapelberg (BSD-licensed) 2 | ;;;; 3 | ;;;; ~/.emacs.d/init.el sets up the load-path and loads modular pieces 4 | ;;;; of configuration. All the files start with zkj to make sure there 5 | ;;;; is no name-clash. 6 | ;;;; 7 | ;;;; See also http://emacswiki.org/emacs/DotEmacsDotD 8 | 9 | ;; Set Garbage Collection threshold extremely high (1 GB), 10 | ;; but run Garbage Collection when Emacs loses focuses: 11 | ;; https://news.ycombinator.com/item?id=39190110 12 | (setq gc-cons-threshold 1073741824) 13 | (add-function :after 14 | after-focus-change-function 15 | (lambda () (unless (frame-focus-state) (garbage-collect)))) 16 | 17 | ;; byte compilation does not make a difference with my current config 18 | ;; (byte-recompile-directory (expand-file-name "~/.emacs.d/lisp") 0) 19 | 20 | (add-to-list 'load-path "~/configfiles/config/emacs/lisp/") 21 | (add-to-list 'load-path "~/configfiles/config/emacs/lisp/emacs-livereload") 22 | 23 | (progn 24 | (message "initializing package") 25 | (package-initialize)) 26 | 27 | ;; Workaround for Emacs < 26.3 (e.g. Debian stable): 28 | ;; https://www.reddit.com/r/emacs/comments/cdei4p/failed_to_download_gnu_archive_bad_request/ 29 | (setq gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3") 30 | 31 | (add-to-list 'package-archives 32 | '("melpa" . 33 | "https://melpa.org/packages/")) 34 | 35 | ;; https://www.reddit.com/r/emacs/comments/4fqu0a/automatically_install_packages_on_startup/d2b7g30 36 | (unless (package-installed-p 'use-package) 37 | (package-refresh-contents) 38 | (package-install 'use-package)) 39 | 40 | (eval-when-compile 41 | (require 'use-package)) 42 | (setq use-package-verbose t) 43 | (setq use-package-always-ensure t) 44 | 45 | ;; Whenever use-package statements use ensure (directly or via 46 | ;; use-package-always-ensure), we need to refresh the package contents first, 47 | ;; as installation fails otherwise: 48 | ;; https://github.com/jwiegley/use-package/issues/256#issuecomment-263313693 49 | (defun my-package-install-refresh-contents (&rest args) 50 | (package-refresh-contents) 51 | (advice-remove 'package-install 'my-package-install-refresh-contents)) 52 | 53 | (advice-add 'package-install :before 'my-package-install-refresh-contents) 54 | 55 | ;; General emacs settings. 56 | (load "zkj-emacs") 57 | 58 | ;; LISP/SCHEME-related settings. 59 | (load "zkj-lisp") 60 | 61 | ;; notmuch-specific configuration, if it is installed. 62 | (if (require 'notmuch nil t) 63 | (load "zkj-notmuch")) 64 | 65 | ;; Perl-related settings. 66 | (load "zkj-perl") 67 | 68 | ;; Go-related settings. 69 | (load "zkj-go") 70 | 71 | ;; protobuf-related settings. 72 | (load "zkj-protobuf") 73 | 74 | ;; Magit gbp mode. 75 | (use-package magit 76 | :bind (("C-x g" . magit-status)) 77 | :config 78 | (load "zkj-gbp") 79 | ;; magit: don’t restore old window configurations 80 | (setq magit-bury-buffer-function 'magit-mode-quit-window)) 81 | 82 | ;; Hugo-related settings. 83 | (load "zkj-hugo") 84 | 85 | (if (string-prefix-p "pacna" system-name) 86 | (load "pacna-early")) 87 | 88 | ;; Settings stored by the customize interface. 89 | (setq custom-file "~/configfiles/config/emacs/custom.el") 90 | (load custom-file) 91 | 92 | (add-hook 93 | 'find-file-hook 94 | (lambda () 95 | (when (and (stringp buffer-file-name) 96 | (string-match "\\.asciidoc\\'" buffer-file-name)) 97 | (if (require 'livereload nil t) 98 | (load "zkj-live-reload"))))) 99 | -------------------------------------------------------------------------------- /config/emacs/layouts/zkj.window-layout: -------------------------------------------------------------------------------- 1 | (nil (0 0 201 97) (t (0 0 96 97) (:purpose edit :purpose-dedicated t :width 0.4824120603015075 :height 0.6082474226804123 :edges (0.0 0.0 0.4824120603015075 0.6082474226804123)) (:purpose compile :purpose-dedicated t :width 0.4824120603015075 :height 0.3917525773195876 :edges (0.0 0.6082474226804123 0.4824120603015075 1.0))) (t (96 0 201 97) (:purpose edit :purpose-dedicated nil :width 0.5276381909547738 :height 0.6185567010309279 :edges (0.4824120603015075 0.0 1.0100502512562815 0.6185567010309279)) (:purpose magit :purpose-dedicated t :width 0.5276381909547738 :height 0.38144329896907214 :edges (0.4824120603015075 0.6185567010309279 1.0100502512562815 1.0)))) -------------------------------------------------------------------------------- /config/emacs/lisp/zkj-emacs.el: -------------------------------------------------------------------------------- 1 | ;;;; © 2012 Michael Stapelberg (BSD-licensed) 2 | ;;;; 3 | ;;;; ~/.emacs.d/lisp/zkj-emacs.el sets general emacs configuration 4 | ;;;; like fonts and keybindings. 5 | 6 | (provide 'zkj-emacs) 7 | 8 | ;; Of course, everything is UTF-8. 9 | (prefer-coding-system 'utf-8) 10 | (set-default-coding-systems 'utf-8) 11 | (set-terminal-coding-system 'utf-8) 12 | (set-keyboard-coding-system 'utf-8) 13 | ;; Treat clipboard input as UTF-8 string first; compound text next, etc. 14 | (setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)) 15 | 16 | ;; Display C-h C-a help message: 17 | ;; https://emacs.stackexchange.com/questions/432/how-to-change-default-minibuffer-message 18 | (defun display-startup-echo-area-message () 19 | (message "")) 20 | 21 | ;; show-paren-mode was enabled by default with Emacs 28.1, but I don’t like it. 22 | (setq show-paren-mode nil) 23 | 24 | ;; Contrary to global-set-key, whose effects can be shadowed by modes (e.g. the 25 | ;; GNUmakefile mode shadows C-c C-f), bind-key overwrites keys in all modes. 26 | (require 'bind-key) 27 | 28 | ;; C-w and C-y should use the PRIMARY selection (mouse-selected) *and* 29 | ;; the CLIPBOARD selection (copy function selected). When yanking, 30 | ;; both will be set. When inserting, the more recently changed one 31 | ;; will be used. 32 | (setq x-select-enable-primary t) 33 | (setq x-select-enable-clipboard t) 34 | 35 | ;; TODO: this breaks C-w in rectangle mode (C-x space) 36 | ;; Make C-w behave like in bash: delete a word when invoked without a region. 37 | ;; (defadvice kill-region (before unix-werase activate compile) 38 | ;; "When called interactively with no active region, delete a single word 39 | ;; backwards instead." 40 | ;; (interactive 41 | ;; (if mark-active (list (region-beginning) (region-end)) 42 | ;; (list (save-excursion (backward-word 1) (point)) (point))))) 43 | 44 | 45 | (setq default-frame-alist '((font . "Go Mono 8"))) 46 | ;; For presentations 47 | ;; (setq default-frame-alist '((font . "Go Mono 16"))) 48 | 49 | ;; Use Noto font for emojis 💯 50 | (set-fontset-font t 'symbol "Noto Color Emoji" nil 'append) 51 | 52 | (use-package smex 53 | :defer t 54 | :init (or (boundp 'smex-cache) 55 | (smex-initialize)) 56 | :bind ("M-x" . smex)) 57 | 58 | ;;;; general appearance 59 | 60 | ;; Don’t ask when following a symlink into a version-controlled folder 61 | ;; (my ~/configfiles). 62 | (setq vc-follow-symlinks t) ;; required so that (ma)git finds ~/configfiles as GIT_DIR 63 | 64 | ;; No blinking cursor. 65 | (blink-cursor-mode 0) 66 | 67 | ;; Open the *scratch* buffer by default, not the welcome message. 68 | (setq inhibit-startup-screen t) 69 | 70 | ;; Better than the default. 71 | (load-theme 'tango-dark t) 72 | 73 | ;; Use google-chrome to open URLs. 74 | (setq browse-url-browser-function 'browse-url-generic 75 | browse-url-generic-program "google-chrome") 76 | 77 | ;; ido-mode has a *much* better buffer selection (and file opening) :). 78 | (defun zkj-lazy-ido-enable () 79 | "since ido is loaded with Emacs, use-package cannot defer" 80 | (ido-mode t) 81 | ;; Disable searching in other directories when there are no matches 82 | ;; (more annoying than helpful). 83 | (setq ido-auto-merge-work-directories-length -1) 84 | 85 | (if (require 'ido-sort-mtime nil t) 86 | (ido-sort-mtime-mode t))) 87 | 88 | (defun zkj-lazy-ido-switch-buffer () 89 | "ibuffer wrapper" 90 | (interactive) 91 | (zkj-lazy-ido-enable) 92 | (call-interactively 'ido-switch-buffer)) 93 | 94 | (defun zkj-lazy-ido-find-file () 95 | "find-file wrapper" 96 | (interactive) 97 | (zkj-lazy-ido-enable) 98 | (call-interactively 'ido-find-file)) 99 | 100 | (use-package ido 101 | :ensure nil ; built-in 102 | :bind (("C-x b" . zkj-lazy-ido-switch-buffer) 103 | ("C-x C-f" . zkj-lazy-ido-find-file) 104 | ("C-x C-p" . counsel-projectile))) 105 | 106 | ;; Store backups and auto-save files in a single directory so that 107 | ;; they don’t clutter up my filesystem (or fail to be written on curlftpfs): 108 | (let ((backupdir (format "%s/emacs-backups%d/" (or (getenv "XDG_RUNTIME_DIR") "/tmp") (user-uid)))) 109 | (mkdir backupdir t) 110 | (setq backup-directory-alist `(("." . ,backupdir))) 111 | (setq auto-save-file-name-transforms 112 | `((".*" ,backupdir t)))) 113 | 114 | ;;;; keybindings 115 | 116 | ;; C-z by default suspends the session, which is… incredibly useless. 117 | (bind-key* "C-z" 'undo) 118 | 119 | ;; Make C-c C-f expand filenames (like vim’s omni-complete) 120 | 121 | (bind-key* "C-c C-f" 'my-expand-file-name-at-point) 122 | (defun my-expand-file-name-at-point () 123 | "Use hippie-expand to expand the filename" 124 | (interactive) 125 | (let ((hippie-expand-try-functions-list '(try-complete-file-name-partially try-complete-file-name))) 126 | (call-interactively 'hippie-expand))) 127 | 128 | ;; Easy window switching with M- 129 | (use-package windmove 130 | :ensure nil ; built-in 131 | :bind* (("" . windmove-left) 132 | ("" . windmove-up) 133 | ("" . windmove-right) 134 | ("" . windmove-down))) 135 | 136 | ;; Don’t ask to save files before compilation, just save them. 137 | (setq compilation-ask-about-save nil) 138 | 139 | ;; Don’t ask to kill currently running compilation, just kill it. 140 | (setq compilation-always-kill t) 141 | 142 | ;; Don’t ask to create parent directories when saving files, just 143 | ;; create them. 144 | (add-hook 'before-save-hook 145 | (lambda () 146 | (when buffer-file-name 147 | (let ((dir (file-name-directory buffer-file-name))) 148 | (when (not (file-exists-p dir)) 149 | (make-directory dir t)))))) 150 | 151 | 152 | ;; Save minibuffer history (for compile command etc.) 153 | (savehist-mode 1) 154 | 155 | ;; compilation: set urgency hint when compilation finishes. 156 | (defun x-urgency-hint (frame arg &optional source) 157 | "Set the x-urgency hint for the frame to arg: 158 | 159 | - If arg is nil, unset the urgency. 160 | - If arg is any other value, set the urgency. 161 | 162 | If you unset the urgency, you still have to visit the frame to make the urgency setting disappear (at least in KDE)." 163 | (let* ((wm-hints (append (x-window-property 164 | "WM_HINTS" frame "WM_HINTS" source nil t) nil)) 165 | (flags (car wm-hints))) 166 | (setcar wm-hints 167 | (if arg 168 | (logior flags #x100) 169 | (logand flags (lognot #x100)))) 170 | (x-change-window-property "WM_HINTS" wm-hints frame "WM_HINTS" 32 t))) 171 | (defun compilation-finished-hook (buf status) 172 | (if (eq (window-system) 'x) 173 | (x-urgency-hint (window-frame (get-buffer-window buf)) 1))) 174 | (add-hook 'compilation-finish-functions #'compilation-finished-hook) 175 | 176 | ;; compile-parent defaults to a make command line using the closest Makefile, 177 | ;; i.e. working in any project subdirectory: 178 | (defun compile-parent (command) 179 | (interactive 180 | (let* ((make-directory (locate-dominating-file 181 | default-directory 182 | "Makefile")) 183 | (command (concat "make -k -C " 184 | (shell-quote-argument make-directory) 185 | " "))) 186 | (list (compilation-read-command command)))) 187 | (compile command)) 188 | 189 | (bind-key* "C-3" 'compile-parent) 190 | ;; C-4 is a good choice as per “Good Key Choices” in 191 | ;; http://ergoemacs.org/emacs/keyboard_shortcuts.html 192 | (bind-key* "C-4" 'zkj-recompile) 193 | ;; f8 is an alias for zkj-recompile, slightly less convenient compared to C-4, 194 | ;; but works in the terminal (which C-4 does not). 195 | (bind-key* "" 'zkj-recompile) 196 | 197 | (defun zkj-recompile () 198 | "Interrupt current compilation and recompile" 199 | (interactive) 200 | (ignore-errors (kill-compilation)) 201 | (recompile)) 202 | 203 | (use-package tramp 204 | ;; https://github.com/jwiegley/use-package/issues/977 205 | :ensure nil 206 | :defer t 207 | :config 208 | ;; does not work in https://github.com/gokrazy/breakglass 209 | (setq tramp-histfile-override "/dev/null") 210 | 211 | ;; Open e.g. /breakglass:router7:/perm/dhcp4d/leases.json 212 | ;; 213 | ;; Requires /perm/sh to be present (use e.g. static busybox) and ls to be in 214 | ;; $PATH (`ln -s busybox ls` will work). 215 | (add-to-list 'tramp-methods 216 | '("breakglass" 217 | (tramp-login-program "ssh") 218 | (tramp-login-args (("-l" "%u") ("-p" "%p") ("%c") 219 | ("-e" "none") ("%h"))) 220 | (tramp-async-args (("-q"))) 221 | (tramp-remote-shell "/perm/sh") 222 | (tramp-remote-shell-login ("-l")) 223 | (tramp-remote-shell-args ("-c")))) 224 | 225 | ;; tell tramp that my ~/.ssh/config is already set up for master mode 226 | ;; (tramp will not use master mode otherwise). 227 | (setq tramp-use-ssh-controlmaster-options nil)) 228 | 229 | (use-package org 230 | :defer t 231 | :config 232 | (progn 233 | (setq org-startup-truncated nil ; wrap lines instead of truncating 234 | org-return-follows-link t ; follow hyperlinks when pressing RET 235 | org-agenda-window-setup 'current-window ; open agenda in same Emacs window 236 | org-startup-folded nil) ; default to #+STARTUP: showall 237 | (setq org-src-window-setup 'current-window) 238 | ;; Make shell source blocks work in Org Mode: 239 | (org-babel-do-load-languages 240 | 'org-babel-load-languages 241 | '((shell . t))) 242 | ;; follow links in the same Emacs window 243 | (setcdr (assoc 'file org-link-frame-setup) 'find-file))) 244 | 245 | ;; https://github.com/bmag/emacs-purpose (“window-purpose” on MELPA) allows 246 | ;; dedicating a window to a certain purpose (e.g. compilation, magit, edit, 247 | ;; …) using C-c , d. 248 | ;; 249 | ;; When happy with a layout, save using: 250 | ;; M-x purpose-save-window-layout NAME RET TAB RET 251 | ;; …and load using: 252 | ;; M-x purpose-load-window-layout NAME 253 | (use-package window-purpose 254 | :defer t 255 | :config 256 | (progn 257 | ;; Prefer opening new buffers in the same Emacs window. 258 | ;; 259 | ;; I don’t want this to happen when not working with 260 | ;; purpose mode in my layout, as it results in magit 261 | ;; windows not popping up anymore. Instead, they just 262 | ;; replace the current window. To make matters worse, 263 | ;; the COMMITMSG buffer ends up being buried under 264 | ;; the diff buffer, which is really confusing. 265 | (setq pop-up-windows nil) 266 | 267 | ;; make M-x man open manpages in the same Emacs window 268 | (setq Man-notify-method 'pushy) 269 | 270 | (add-to-list 'purpose-user-mode-purposes '(compilation-mode . compile)) 271 | (add-to-list 'purpose-user-mode-purposes '(dired-mode . edit)) 272 | (add-to-list 'purpose-user-name-purposes '("*Go Test*" . compile)) 273 | (add-to-list 'purpose-user-regexp-purposes '("^magit: " . magit)) 274 | (define-key purpose-mode-map (kbd "C-x b") nil) 275 | (define-key purpose-mode-map (kbd "C-x C-f") nil) 276 | (purpose-compile-user-configuration) ;; activate changes 277 | )) 278 | 279 | ;; https://github.com/bmag/emacs-purpose (“window-purpose” on MELPA) allows 280 | ;; dedicating a window to a certain purpose (e.g. compilation, magit, edit, 281 | ;; …) using C-c , d. 282 | ;; 283 | ;; When happy with a layout, save using: 284 | ;; M-x purpose-save-window-layout NAME RET TAB RET 285 | ;; …and load using: 286 | ;; M-x purpose-load-window-layout NAME 287 | (defun zkj-purpose () 288 | "loads purpose and restores my typical window layout" 289 | (interactive) 290 | (progn 291 | (purpose-mode) 292 | (message "loading window layout") 293 | (purpose-load-window-layout "zkj"))) 294 | 295 | (use-package winner 296 | :ensure nil ; built-in 297 | :bind (("C-c " . winner-undo) 298 | ("C-c " . winner-redo)) 299 | ;; Initialize winner-mode immediately; it needs to record all window 300 | ;; configurations before the first invokation to be useful. 301 | :init 302 | (winner-mode t)) 303 | 304 | ;; use 80 characters for line wrapping with M-q 305 | (setq-default fill-column 80) 306 | 307 | ;; display line numbers and column numbers in all modes 308 | (setq line-number-mode t) 309 | (setq column-number-mode t) 310 | 311 | ;; automatically revert buffers when files change 312 | (global-auto-revert-mode 1) 313 | 314 | ;; ;; See editorconfig.org 315 | ;; (if (require 'editorconfig nil t) 316 | ;; (editorconfig-mode 1)) 317 | 318 | ;; Always ask for y/n, never yes/no. 319 | (defalias 'yes-or-no-p 'y-or-n-p) 320 | 321 | ;; Always show the buffer name in the frame title (Emacs default is to show the 322 | ;; hostname when there is only one frame). 323 | (setq frame-title-format 324 | (setq icon-title-format 325 | '((:eval (if (buffer-file-name) 326 | (abbreviate-file-name (buffer-file-name)) 327 | "%b")) 328 | (:eval (if (buffer-modified-p) 329 | "*")) 330 | " - Emacs") 331 | )) 332 | 333 | ;; ;; Disable the scroll bar by default, they flicker. Use M-x scroll-bar-mode to 334 | ;; ;; make it re-appear. 335 | ;; (scroll-bar-mode -1) 336 | 337 | ;; Add final newlines to all files by default, not just in modes which think 338 | ;; this is useful. 339 | (setq require-final-newline t) 340 | 341 | ;; Persistent desktops (which buffers are open) 342 | (setq desktop-save t) ;; always save 343 | ;;(desktop-save-mode) 344 | 345 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 346 | ;; Daemon mode 347 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 348 | 349 | (require 'seq) ;; Emacs 25.1 350 | (defun zkj-reload-all () 351 | "reloads all running Emacs daemons" 352 | (interactive) 353 | ;; socket location when using emacsclient --socket-name: 354 | (let* ((socket-dir (format "%s/emacs%d" (or (getenv "TMPDIR") "/tmp") (user-uid))) 355 | (not-dot (lambda (x) (not (or (string= x ".") 356 | (string= x ".."))))) 357 | (daemons (seq-filter not-dot (directory-files socket-dir)))) 358 | (mapcar (lambda (daemon) (server-eval-at daemon '(load-file user-init-file))) daemons))) 359 | 360 | (defun zkj--output-or-empty (command) 361 | (progn 362 | (require 'subr-x) 363 | (with-temp-buffer 364 | (let* ((exitcode (apply 'call-process "/bin/sh" nil (current-buffer) nil (list "-c" command))) 365 | (output (if (= exitcode 0) 366 | (string-trim-right (buffer-string)) 367 | ""))) 368 | output)))) 369 | 370 | ;; Returns the parent directory containing a .project.el file, if any, 371 | ;; to override the standard project.el detection logic when needed. 372 | (defun zkj-project-find (dir) 373 | (let ((override (locate-dominating-file dir ".project.el"))) 374 | (if override 375 | (cons 'vc override) 376 | nil))) 377 | 378 | (use-package project 379 | ;; https://github.com/jwiegley/use-package/issues/977 380 | :ensure nil 381 | ;; Cannot use :hook because 'project-find-functions does not end in -hook 382 | ;; Cannot use :init (must use :config) because otherwise 383 | ;; project-find-functions is not yet initialized. 384 | :config 385 | (add-hook 'project-find-functions #'zkj-project-find) 386 | ;; Workaround for: 387 | ;; eval-after-load: Symbol’s value as variable is void: project-switch-commands [4 times] 388 | ;; from https://libredd.it/r/emacs/comments/po9cfj/magit_commands_broken/?sort=new 389 | :init (if (not (boundp 'project-switch-commands)) 390 | (setq project-switch-commands nil))) 391 | 392 | ;; You can interactively overwrite this using e.g. M-: 393 | ;; (defun zkj-ag-default-directory () "~/kinx/chibi41") 394 | (defun zkj-ag-default-directory () 395 | (project-root (project-current))) 396 | 397 | (defun zkj-ag (string directory) 398 | "ag defaulting to the project directory" 399 | (interactive 400 | (progn 401 | (require 'ag) 402 | (list (ag/read-from-minibuffer "Search string") 403 | (read-directory-name "Directory: " (zkj-ag-default-directory))))) 404 | (ag/search string directory)) 405 | 406 | (setq counsel-fzf-cmd "fd --type f | fzf -f \"%s\"") 407 | 408 | (use-package counsel 409 | :ensure t 410 | :config 411 | ;; Explicitly use counsel without ivy: 412 | ;; ivy changes the behavior of code completion in Go, 413 | ;; e.g. typing mux.Hand 414 | ;; (ivy-mode 1) 415 | (counsel-mode 1)) 416 | 417 | (use-package projectile 418 | :ensure t 419 | :init 420 | (projectile-mode +1) 421 | (setq projectile-enable-caching t)) 422 | 423 | (use-package counsel-projectile 424 | :ensure t) 425 | 426 | (defun fzf () 427 | "fuzzy find on the closest git repository" 428 | (interactive) 429 | (counsel-projectile)) 430 | 431 | (defun config () 432 | "invokes counsel-fzf on ~/configfiles/config/emacs/lisp" 433 | (interactive) 434 | (counsel-fzf nil "~/configfiles/config/emacs/lisp")) 435 | 436 | ;; M-x website menu partial 437 | (defun website () 438 | "invokes counsel-fzf on ~/hugo" 439 | (interactive) 440 | (counsel-fzf nil "~/hugo")) 441 | 442 | ;; Emacs doesn’t know about XC 443 | ;; (https://en.wikipedia.org/wiki/XC_(programming_language)) and defaults to 444 | ;; opening .xc files as image files. 445 | (add-to-list 'auto-mode-alist '("\\.xc\\'" . c-mode)) 446 | 447 | ;; https://eklitzke.org/smarter-emacs-clang-format 448 | (defun clang-format-buffer-smart () 449 | "Reformat buffer if .clang-format exists in the projectile root." 450 | (when (file-exists-p (expand-file-name ".clang-format" (project-root (project-current)))) 451 | (clang-format-buffer))) 452 | 453 | (defun clang-format-buffer-smart-on-save () 454 | "Add auto-save hook for clang-format-buffer-smart." 455 | (add-hook 'before-save-hook 'clang-format-buffer-smart nil t)) 456 | 457 | ;;(add-hook 'c-mode-hook 'clang-format-buffer-smart-on-save) 458 | ;;(add-hook 'c++-mode-hook 'clang-format-buffer-smart-on-save) 459 | 460 | ;; eglot is a language server protocol (LSP) package for Emacs, which is more 461 | ;; minimalist than lsp-mode: https://github.com/joaotavora/eglot 462 | (if (version< emacs-version "26.3") 463 | (message "not installing eglot as emacs is too old") 464 | (use-package eglot 465 | :hook 466 | (c-mode . eglot-ensure) 467 | (c++-mode . eglot-ensure) 468 | (go-mode . eglot-ensure) 469 | (python-mode . eglot-ensure) 470 | :config 471 | (setq eglot-sync-connect 0) 472 | (add-to-list 'eglot-server-programs '((c++-mode c-mode) "clangd")))) 473 | 474 | ;; Do not create lockfiles, they trip up e.g. hugo (because they are an 475 | ;; unreadable symlink: 476 | ;; File: /home/michael/hugo/content/posts/.#2019-07-11-introducing-distri.markdown -> michael@xps.25964:1563787245 477 | (setq create-lockfiles nil) 478 | 479 | ;; Make M-next and M-prior (M-PageDown and M-PageUp, respectively) preferably 480 | ;; operate on the window displaying the compilation buffer, if precisely 1. 481 | (defun zkj-with-compilation-window (FUNC) 482 | (let ((compilation-mode-windows 483 | (mapcan 484 | (lambda (window) 485 | (with-current-buffer 486 | (window-buffer window) 487 | (if (equal major-mode 'compilation-mode) 488 | (list window) 489 | '()))) 490 | (window-list)))) 491 | (if (= (length compilation-mode-windows) 1) 492 | (save-selected-window 493 | (select-window (car compilation-mode-windows)) 494 | (funcall FUNC) 495 | t) 496 | nil))) 497 | 498 | (defun zkj-scroll-compilation-window-down () 499 | "Scroll the compilation window down" 500 | (interactive) 501 | (if (not (zkj-with-compilation-window #'scroll-down)) 502 | (scroll-other-window-down))) 503 | 504 | (defun zkj-scroll-compilation-window-up () 505 | "Scroll the compilation window up" 506 | (interactive) 507 | (if (not (zkj-with-compilation-window #'scroll-up)) 508 | (scroll-other-window))) 509 | 510 | (bind-key* "" #'zkj-scroll-compilation-window-up) 511 | (bind-key* "" #'zkj-scroll-compilation-window-down) 512 | 513 | ;; for more details on display-buffer-alist, see: 514 | ;; https://www.masteringemacs.org/article/demystifying-emacs-window-manager 515 | 516 | ;; By default, when e.g. M-x magit-status opens a new buffer, the frame is 517 | ;; raised, which focuses the X11 window in i3, thereby stealing focus. 518 | ;; 519 | ;; By setting inhibit-switch-frame to t, Emacs will not call raise-frame. 520 | (add-to-list 521 | 'display-buffer-alist 522 | '(".*" . (display-buffer-reuse-window 523 | . ((inhibit-switch-frame . t))))) 524 | 525 | ;; Open M-x compile buffers to the right instead of at the bottom (default). 526 | (add-to-list 527 | 'display-buffer-alist 528 | '("*compilation*" (display-buffer-reuse-window display-buffer-in-direction) 529 | (direction . right))) 530 | -------------------------------------------------------------------------------- /config/emacs/lisp/zkj-gbp.el: -------------------------------------------------------------------------------- 1 | (provide 'zkj-gbp) 2 | 3 | (defun outdir () 4 | (replace-regexp-in-string 5 | (regexp-quote (expand-file-name "~/d/pkg")) 6 | (expand-file-name "~/d/out") 7 | default-directory)) 8 | 9 | (defun gbp-buildpackage () 10 | (interactive) 11 | (let ((out (outdir)) 12 | (default-directory (magit-toplevel))) 13 | (compile (concat "gbp buildpackage --git-ignore-new --git-export-dir=" out)))) 14 | 15 | ;; TODO: team flag 16 | (defun gbp-dch () 17 | (interactive) 18 | (let ((default-directory (magit-toplevel))) 19 | (compile "gbp dch -R --commit"))) 20 | 21 | (defun gbp-tag () 22 | (interactive) 23 | (let ((default-directory (magit-toplevel))) 24 | (compile "gbp buildpackage --git-tag-only --git-ignore-new"))) 25 | 26 | (defun gbp-push () 27 | (interactive) 28 | (let ((default-directory (magit-toplevel))) 29 | (compile "gbp push"))) 30 | 31 | (defun gbp-pull () 32 | (interactive) 33 | (let ((default-directory (magit-toplevel))) 34 | (compile "gbp pull"))) 35 | 36 | (defun dput () 37 | (interactive) 38 | (let ((default-directory (outdir))) 39 | (compile "dput" t))) ;; run compile in COMINT mode to allow input 40 | 41 | (use-package magit-popup 42 | :config 43 | (magit-define-popup gbp-popup "git buildpackage" 44 | :actions '((?B "buildpackage" gbp-buildpackage) 45 | (?d "dch" gbp-dch) 46 | (?t "tag" gbp-tag) 47 | (?F "pull" gbp-pull) 48 | (?P "push" gbp-push) 49 | (?U "dput" dput)) 50 | :default-action 'gbp 51 | )) 52 | 53 | (define-key magit-status-mode-map (kbd "H") 'gbp-popup) 54 | 55 | (magit-define-popup-action 'magit-dispatch-popup 56 | ?H "Git buildpackage" 'gbp-popup ?!) 57 | -------------------------------------------------------------------------------- /config/emacs/lisp/zkj-go.el: -------------------------------------------------------------------------------- 1 | ;;;; © 2012-2013 Michael Stapelberg (BSD-licensed) 2 | ;;;; 3 | ;;;; ~/.emacs.d/lisp/zkj-go.el sets go-specific 4 | ;;;; configuration. 5 | (provide 'zkj-go) 6 | 7 | (defun zkj-go-test-at-point () 8 | (interactive) 9 | (let ((go-test-args "-count=1") 10 | (go-test-verbose t)) 11 | (go-test-current-test))) 12 | 13 | (defun zkj-find-definition () 14 | (interactive) 15 | (call-interactively 'xref-find-definitions) 16 | (recenter-top-bottom 0)) 17 | 18 | (defun zkj-eglot-organize-imports () 19 | (call-interactively 'eglot-code-action-organize-imports)) 20 | 21 | (defun zkj-go-mode-hook () 22 | ;; Format (previously: gofmt) and organize imports (previously: goimports). 23 | (add-hook 'before-save-hook #'eglot-format-buffer -10 t) 24 | (add-hook 'before-save-hook #'zkj-eglot-organize-imports nil t) 25 | 26 | ;; Jump to first error. Go has no warnings. 27 | (setq compilation-scroll-output 'first-error) 28 | ;; Jump to the definition of the symbol under the cursor. 29 | ;; (Jump back with M-*) 30 | (local-set-key (kbd "M-.") 'zkj-find-definition) 31 | (local-set-key (kbd "C-c d") 'godoc-at-point) 32 | (local-set-key (kbd "M-g t") 'zkj-go-test-at-point) 33 | ;; One tab will be displayed as 4 spaces. 34 | (set 'tab-width 4)) 35 | ;; Enable eldoc (displays function signatures in the minibuf). 36 | ;; (go-eldoc-setup)) 37 | (add-hook 'go-mode-hook 'zkj-go-mode-hook) 38 | (add-hook 'go-mode-hook 'eglot-ensure) 39 | -------------------------------------------------------------------------------- /config/emacs/lisp/zkj-hugo.el: -------------------------------------------------------------------------------- 1 | (provide 'zkj-hugo) 2 | 3 | (defun hugo-replace-key (key val) 4 | (save-excursion 5 | (goto-char (point-min)) 6 | ; quoted value 7 | (if (and (re-search-forward (concat key ": \"") nil t) 8 | (re-search-forward "[^\"]+" (line-end-position) t)) 9 | (or (replace-match val) t) ; ensure we return t 10 | ; unquoted value 11 | (when (and (re-search-forward (concat key ": ") nil t) 12 | (re-search-forward ".+" (line-end-position) t)) 13 | (or (replace-match val) t))))) 14 | 15 | (defun hugo-enable-draft () 16 | (hugo-replace-key "draft" "true")) 17 | 18 | (add-hook 'markdown-mode-hook 'hugo-enable-draft) 19 | -------------------------------------------------------------------------------- /config/emacs/lisp/zkj-lisp.el: -------------------------------------------------------------------------------- 1 | ;;;; © 2012 Michael Stapelberg (BSD-licensed) 2 | ;;;; 3 | ;;;; ~/.emacs.d/lisp/zkj-lisp.el sets LISP/SCHEME specific 4 | ;;;; configuration. 5 | 6 | (provide 'zkj-lisp) 7 | 8 | ;;;; auto-indent for lisp modes 9 | (defun set-newline-and-indent () 10 | (local-set-key (kbd "RET") 'newline-and-indent)) 11 | (add-hook 'emacs-lisp-mode-hook 'set-newline-and-indent) 12 | (add-hook 'lisp-mode-hook 'set-newline-and-indent) 13 | (add-hook 'scheme-mode-hook 'set-newline-and-indent) 14 | 15 | ;;;; chicken-slime 16 | (add-to-list 'load-path "/var/lib/chicken/6/") 17 | (autoload 'chicken-slime "chicken-slime" "SWANK backend for Chicken" t) 18 | 19 | (add-hook 'scheme-mode-hook 20 | (lambda () 21 | (require 'slime) 22 | (slime-setup '(slime-fancy)) 23 | (slime-mode t))) 24 | -------------------------------------------------------------------------------- /config/emacs/lisp/zkj-live-reload.el: -------------------------------------------------------------------------------- 1 | (provide 'zkj-live-reload) 2 | 3 | (add-to-list 4 | 'auto-mode-alist 5 | '("\\.asciidoc\\'" . 6 | (lambda () 7 | ;; Enable livereload-mode if not already enabled 8 | (or livereload-mode (livereload-mode)) 9 | ;; Pretend we’re using http://localhost/ instead of a file:// URI, 10 | ;; and pretend asciidoc was HTML. 11 | (setq-local 12 | livereload-potential-targets 13 | (lambda (url) 14 | (let ((url (replace-regexp-in-string "^file://" "http://localhost/" url)) 15 | (buffer-file-name (replace-regexp-in-string "\.asciidoc$" ".html" buffer-file-name))) 16 | (livereload-default-potential-targets url)))) 17 | (add-hook 18 | 'livereload-notify-hook 19 | (lambda (url) 20 | (let ((target (concat "file://" (replace-regexp-in-string "\.asciidoc$" ".html" buffer-file-name)))) 21 | (shell-command (concat "asciidoctor " buffer-file-name)) 22 | (livereload-notify (list target)) 23 | t)) 24 | nil 25 | t)))) 26 | -------------------------------------------------------------------------------- /config/emacs/lisp/zkj-notmuch.el: -------------------------------------------------------------------------------- 1 | ;;;; © 2012-2013 Michael Stapelberg (BSD-licensed) 2 | ;;;; 3 | ;;;; ~/.emacs.d/lisp/zkj-notmuch.el sets notmuch-specific 4 | ;;;; configuration. 5 | 6 | (provide 'zkj-notmuch) 7 | 8 | (require 'notmuch) 9 | (require 'notmuch-address) 10 | ;; for mail-add-attachment 11 | (require 'sendmail) 12 | 13 | (when (not (string= system-name "midna")) 14 | (setq notmuch-command "/home/michael/configfiles/remote-notmuch.sh")) 15 | 16 | ;; Rebind C-c C-a to use the attachment function which does NOT 17 | ;; explicitly ask for type and disposition, and defaults to attachment 18 | ;; instead of inline :). 19 | (define-key message-mode-map (kbd "C-c C-a") 'mail-add-attachment) 20 | 21 | ;; Also replace the corresponding menu item, otherwise C-c C-a will 22 | ;; not show up in the menu at all. Furthermore, using it from the menu 23 | ;; will open a GTK file dialog. 24 | (define-key mml-mode-map [menu-bar Attachments Attach\ File...] 25 | '("Attach File..." . mail-add-attachment)) 26 | 27 | ;; Attach an entire directory. Adapted from 28 | ;; http://www.emacswiki.org/emacs/MessageMode 29 | (defun message-attach-all-files-from-folder(&optional dir-to-attach) 30 | "create the mml code to attach all files found in a given directory" 31 | (interactive) 32 | 33 | (if (eq dir-to-attach nil) 34 | (setq dir-to-attach (read-directory-name "Select a folder to attach: "))) 35 | 36 | (if (not (string-match "/$" dir-to-attach)) 37 | (setq dir-to-attach (concat dir-to-attach "/"))) 38 | 39 | (dolist (file (directory-files dir-to-attach)) 40 | (when (and (not (string= "." file)) (not (string= ".." file))) 41 | (let (full-file-path mime-type) 42 | (setq full-file-path (concat dir-to-attach file)) 43 | (if (file-readable-p full-file-path) 44 | (if (file-directory-p full-file-path) 45 | (message-attach-all-files-from-folder full-file-path) 46 | (setq mime-type (substring (shell-command-to-string (concat "file --mime-type --brief " (shell-quote-argument (expand-file-name full-file-path)))) 0 -1)) 47 | (insert-string (concat "<#part type=\"" mime-type "\" filename=\"" full-file-path "\" disposition=attachment>\n")))))))) 48 | 49 | (define-key mml-mode-map [menu-bar Attachments Attach\ Directory...] 50 | '("Attach Directory..." . message-attach-all-files-from-folder)) 51 | 52 | ;; Process PGP/MIME. Needs gpg-agent working, with pinentry-gtk. 53 | (setq notmuch-crypto-process-mime t) 54 | 55 | ;; When stumbling upon an inline GPG message, call 56 | ;; notmuch-decrypt-inline and tell the sender to switch to PGP/MIME. 57 | (defun notmuch-decrypt-inline () 58 | (interactive) 59 | (epa-decrypt-armor-in-region (point-min) (point-max))) 60 | 61 | ;; Close mail buffers after sending. 62 | (setq message-kill-buffer-on-exit t) 63 | 64 | ;; Don’t display killed threads in my inbox. 65 | (setq notmuch-saved-searches (quote (("inbox" . "tag:inbox -tag:killed")))) 66 | 67 | ;; When starting, don’t load notmuch-hello, but jump directly to inbox. 68 | (defun notmuch () 69 | (interactive) 70 | (notmuch-search (cdr (first notmuch-saved-searches)))) 71 | 72 | ;; Use sendmail(1) to send emails. 73 | (setq message-send-mail-function (quote message-send-mail-with-sendmail)) 74 | (setq send-mail-function (quote sendmail-send-it)) 75 | 76 | ;; The default breaks some notmuch features (for example 'v' for view 77 | ;; message or 'w' for save all attachments), so use w3m to render 78 | ;; text/html MIME parts. 79 | (setq mm-text-html-renderer 'shr) 80 | (add-to-list 'mm-text-html-renderer-alist 81 | '(true-w3m mm-inline-render-with-stdin 82 | nil "w3m" "-T" "text/html")) 83 | 84 | 85 | ;; Required to make mail routing work in my setup 86 | (setq message-sendmail-envelope-from "michael@stapelberg.de") 87 | ;;(setq message-sendmail-envelope-from "stapelberg@debian.org") 88 | ;;(setq message-sendmail-envelope-from "p5p@zekjur.net") 89 | 90 | ;; My folder is called "Sent", not "sent". 91 | (setq notmuch-fcc-dirs "Sent") 92 | 93 | ;; Remove messages from inbox to which I replied. 94 | (setq notmuch-message-replied-tags '("replied" "-inbox")) 95 | 96 | ;; Show newest messages at the top. 97 | (setq notmuch-search-oldest-first nil) 98 | 99 | ;; Hide text/html parts in multipart-messages by default. 100 | (setq notmuch-show-all-multipart/alternative-parts nil) 101 | 102 | ;; Make the search result lines look a bit more like sup. 103 | (setq notmuch-search-result-format 104 | `(("date" . "%12s ") 105 | ("count" . "%-7s ") 106 | ("authors" . "%-15s ") 107 | ("tags" . "%s ") 108 | ("subject" . "%s "))) 109 | 110 | ;; Address completion. 111 | (setq notmuch-address-command "/home/michael/notmuch/nottoomuch-addresses.sh") 112 | (notmuch-address-message-insinuate) 113 | 114 | ;;;; Mail body generation 115 | 116 | ;;; Returns everything before the first space (if any), or just the 117 | ;;; whole name if there are no spaces (most likely a nickname, then). 118 | (defun shorten-realname (name) 119 | (if (stringp name) 120 | (if (string-match "\\([^ ]+\\)" name) 121 | (match-string 0 name) 122 | name) 123 | "")) 124 | 125 | (defun get-recipient-for-body () 126 | (let ((to (message-fetch-field "To"))) 127 | (if to 128 | (shorten-realname (nth 0 (mail-extract-address-components to))) 129 | ""))) 130 | 131 | (defun my-fill-body () 132 | (let ((recipient (get-recipient-for-body))) 133 | (save-excursion 134 | (goto-char (point-max)) 135 | (insert (format "Hi %s,\n\n" recipient))))) 136 | 137 | (add-hook 'message-signature-setup-hook 'my-fill-body) 138 | 139 | ;;;; Automatic sender address selection. 140 | 141 | ;;; returns a list of all values of the given plist 142 | (defun plist-values (plist) 143 | (if (null plist) 144 | nil 145 | (append (list (nth 1 plist)) (plist-values (cdr (cdr plist)))))) 146 | 147 | ;;; returns nil if PATTERN is not contained in any member of HEADERS 148 | (defun any-value-matches (pattern headers) 149 | (if (null headers) 150 | nil 151 | (or 152 | (string-match pattern (car headers)) 153 | (any-value-matches pattern (cdr headers))))) 154 | 155 | (defun determine-sender-and-reply (reply-all) 156 | (let* ((headers (notmuch-show-get-prop :headers nil)) 157 | (values (plist-values headers)) 158 | (sender (cond 159 | ((any-value-matches "debian\\.org" values) "Michael Stapelberg ") 160 | ((any-value-matches "i3" values) "Michael Stapelberg ") 161 | (t nil)))) 162 | (notmuch-mua-reply (notmuch-show-get-message-id) sender reply-all))) 163 | 164 | (define-key notmuch-show-mode-map "r" 165 | (lambda () 166 | (interactive) 167 | (determine-sender-and-reply nil))) 168 | 169 | (define-key notmuch-show-mode-map "R" 170 | (lambda () 171 | (interactive) 172 | (determine-sender-and-reply t))) 173 | 174 | (define-key notmuch-show-mode-map "3" 175 | (lambda () 176 | "Merge this patch into ~/i3" 177 | (interactive) 178 | (let ((id (notmuch-show-get-message-id)) 179 | (tempfile (make-temp-file "i3-patch")) 180 | (buf (get-buffer-create "*notmuch-last-i3-merge*"))) 181 | (switch-to-buffer buf) 182 | (cd "/home/michael/i3") 183 | (with-temp-file tempfile 184 | (call-process notmuch-command nil t nil "show" "--format=raw" id)) 185 | (call-process "git" nil buf nil "am" "-3" "--whitespace=fix" tempfile)))) 186 | 187 | (define-key notmuch-show-mode-map "4" 188 | (lambda () 189 | "Merge this patch into ~/i3status" 190 | (interactive) 191 | (let ((id (notmuch-show-get-message-id)) 192 | (tempfile (make-temp-file "i3status-patch")) 193 | (buf (get-buffer-create "*notmuch-last-i3status-merge*"))) 194 | (switch-to-buffer buf) 195 | (cd "/home/michael/i3status") 196 | (with-temp-file tempfile 197 | (call-process notmuch-command nil t nil "show" "--format=raw" id)) 198 | (call-process "git" nil buf nil "am" "-3" "--whitespace=fix" tempfile)))) 199 | 200 | (define-key notmuch-search-mode-map "S" 201 | (lambda () 202 | "mark messages in thread as spam" 203 | (interactive) 204 | (if (member "is-spam" (notmuch-search-get-tags)) 205 | (notmuch-search-tag '("-is-spam" "+inbox")) 206 | (notmuch-search-tag '("+is-spam" "-inbox"))))) 207 | 208 | ;; Removes submit@bugs.debian.org from the recipients of a reply-all message. 209 | (defun debian-remove-submit (recipients) 210 | (delq nil 211 | (mapcar (lambda (recipient) 212 | (and (not (string-equal (nth 1 recipient) "submit@bugs.debian.org")) 213 | recipient)) 214 | recipients))) 215 | 216 | (defun debian-add-bugrecipient (recipients bugnumber) 217 | (let* ((bugstr (format "%s" bugnumber)) 218 | (bugaddress (concat bugstr "@bugs.debian.org")) 219 | (addresses (mapcar (lambda (x) (nth 1 x)) recipients)) 220 | (exists (member bugaddress addresses))) 221 | (if exists 222 | recipients 223 | (append (list (list (concat "Bug " bugstr) bugaddress)) recipients)))) 224 | 225 | ;; TODO: msg should be made optional and it should default to the latest message in the bugreport. 226 | ;; NB: bugnumber and msg are both strings. 227 | (defun debian-bts-reply (bugnumber msg) 228 | ;; Download the message to ~/mail-copy-fs/imported. 229 | (let ((msgpath (format "~/mail-copy-fs/imported/bts_%s_msg_%s.msg" bugnumber msg))) 230 | (let* ((url (format "http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=%s;mbox=yes;bug=%s" msg bugnumber)) 231 | (download-buffer (url-retrieve-synchronously url))) 232 | (save-excursion 233 | (set-buffer download-buffer) 234 | (goto-char (point-min)) ; just to be safe 235 | (if (not (string-equal 236 | (buffer-substring (point) (line-end-position)) 237 | "HTTP/1.1 200 OK")) 238 | (error "Could not download the message from the Debian BTS")) 239 | ;; Delete the HTTP headers and the first "From" line (in order to 240 | ;; make this a message, not an mbox). 241 | (re-search-forward "^$" nil 'move) 242 | (forward-char) 243 | (forward-line 1) 244 | (delete-region (point-min) (point)) 245 | ;; Store the message on disk. 246 | (write-file msgpath) 247 | (kill-buffer))) 248 | ;; Import the mail into the notmuch database. 249 | (let ((msgid (with-temp-buffer 250 | (call-process "~/.local/bin/notmuch-import.py" nil t nil (expand-file-name msgpath)) 251 | (buffer-string)))) 252 | (notmuch-mua-reply (concat "id:" msgid) "Michael Stapelberg " t) 253 | ;; Remove submit@bugs.debian.org, add @bugs.debian.org. 254 | (let* ((to (message-fetch-field "To")) 255 | (recipients (mail-extract-address-components to t)) 256 | (recipients (debian-remove-submit recipients)) 257 | (recipients (debian-add-bugrecipient recipients bugnumber)) 258 | (recipients-str (mapconcat (lambda (x) (concat (nth 0 x) " <" (nth 1 x) ">")) recipients ", "))) 259 | (save-excursion 260 | (message-goto-to) 261 | (message-delete-line) 262 | (insert "To: " recipients-str "\n"))) 263 | ;; Our modifications don’t count as modifications. 264 | (set-buffer-modified-p nil)))) 265 | -------------------------------------------------------------------------------- /config/emacs/lisp/zkj-perl.el: -------------------------------------------------------------------------------- 1 | ;;;; © 2012 Michael Stapelberg (BSD-licensed) 2 | ;;;; 3 | ;;;; ~/.emacs.d/lisp/zkj-perl.el sets Perl-specific 4 | ;;;; configuration. 5 | 6 | (provide 'zkj-perl) 7 | 8 | (add-to-list 'load-path "~/.emacs.d/cperl-mode/") 9 | (autoload 'cperl-mode "cperl-mode" "CPerl mode" t) 10 | 11 | (defalias 'perl-mode 'cperl-mode) 12 | 13 | ;;;; auto-indent for perl 14 | (defun set-newline-and-indent () 15 | (local-set-key (kbd "RET") 'newline-and-indent)) 16 | (add-hook 'cperl-mode-hook 'set-newline-and-indent) 17 | 18 | ;;;; indentation settings 19 | (setq 20 | cperl-continued-statement-offset 4 21 | cperl-indent-level 4 22 | cperl-indent-parens-as-block t 23 | cperl-tabs-always-indent t 24 | cperl-indent-subs-specially nil) 25 | 26 | ;;;; perltidy function from http://www.emacswiki.org/emacs/PerlTidyElisp 27 | ;;;; (fixed up according to (gofmt) wrt window configuration/point/mark) 28 | (defun perltidy-dwim (arg) 29 | "Perltidy a region of the entire buffer" 30 | (interactive "P") 31 | (let ((old-point (point)) 32 | (old-mark (mark t)) 33 | (old-window-start (window-start)) 34 | (old-window-hscroll (window-hscroll)) 35 | (currconf (current-window-configuration)) 36 | (buffer (generate-new-buffer "*perltidy*")) 37 | (start) 38 | (end)) 39 | (if (and mark-active transient-mark-mode) 40 | (setq start (region-beginning) 41 | end (region-end)) 42 | (setq start (point-min) 43 | end (point-max))) 44 | ;; set the PERLTIDY environment variable to the closest instance 45 | ;; of .perltidyrc, but keep its value if it was set before. 46 | (let ((old-perltidy-env (getenv "PERLTIDY"))) 47 | (setenv "PERLTIDY" (or old-perltidy-env 48 | (expand-file-name 49 | (locate-dominating-file (buffer-file-name) ".perltidyrc")))) 50 | (shell-command-on-region start end "perltidy" buffer) 51 | (setenv "PERLTIDY" old-perltidy-env)) 52 | (delete-region start end) 53 | (insert-buffer buffer) 54 | (kill-buffer buffer) 55 | (goto-char (min old-point (point-max))) 56 | (if old-mark (push-mark (min old-mark (point-max)) t)) 57 | (set-window-configuration currconf) 58 | (set-window-start nil old-window-start) 59 | (set-window-hscroll nil old-window-hscroll))) 60 | 61 | (add-hook 'cperl-mode-hook 62 | (lambda () 63 | (local-set-key (kbd "C-c f") 'perltidy-dwim))) 64 | 65 | ;;;; function to run the testcases using "make test" 66 | (defun zkj-perl-tests () 67 | "Runs perl testcases" 68 | (interactive) 69 | (setq compilation-read-command nil) 70 | (setq compile-command "make test") 71 | (let ((default-directory (locate-dominating-file 72 | (buffer-file-name) 73 | "Makefile.PL"))) 74 | (call-interactively 'compile))) 75 | 76 | (add-hook 'cperl-mode-hook 77 | (lambda () 78 | (local-set-key (kbd "C-c t") 'zkj-perl-tests))) 79 | -------------------------------------------------------------------------------- /config/emacs/lisp/zkj-protobuf.el: -------------------------------------------------------------------------------- 1 | (provide 'zkj-protobuf) 2 | 3 | ;; NOTE: (setq jit-lock-defer-time 0.01) makes the distri build of 4 | ;; e.g. networkmanager hang. 5 | 6 | (add-to-list 7 | 'auto-mode-alist 8 | '("\\.textproto\\'" . 9 | (lambda () 10 | ;; Enable protobuf mode. 11 | (protobuf-mode) 12 | (setq-local compile-command "distri <&-") 13 | ;; Compile without colors (faster): 14 | (add-hook 'compilation-mode-hook 15 | (lambda() 16 | ;; TODO: scope setting to only this compilation, not all 17 | ;; compilations. 18 | (font-lock-mode -1))) 19 | ))) 20 | -------------------------------------------------------------------------------- /config/fontconfig/fonts.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | serif 6 | 7 | DejaVu Serif 8 | 9 | 10 | 11 | sans-serif 12 | 13 | DejaVu Sans 14 | 15 | 16 | 17 | monospace 18 | 19 | DejaVu Sans Mono 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /config/gtk-3.0/settings.ini: -------------------------------------------------------------------------------- 1 | [Settings] 2 | gtk-toolbar-style=GTK_TOOLBAR_ICONS 3 | gtk-font-name=Cantarell 11 4 | -------------------------------------------------------------------------------- /config/i3/config: -------------------------------------------------------------------------------- 1 | # -*- compile-command: "i3 reload" -*- 2 | # i3 config file (v4) 3 | # 4 | # Please see https://i3wm.org/docs/userguide.html for a complete reference! 5 | 6 | set $mod Mod4 7 | 8 | # Font for window titles. Will also be used by the bar unless a different font 9 | # is used in the bar {} block below. 10 | font pango:monospace 8 11 | 12 | # This font is widely installed, provides lots of unicode glyphs, right-to-left 13 | # text rendering and scalability on retina/hidpi displays (thanks to pango). 14 | #font pango:DejaVu Sans Mono 8 15 | 16 | # Use Mouse+$mod to drag floating windows to their wanted position 17 | floating_modifier $mod 18 | 19 | for_window [class="Teensy"] floating enable 20 | 21 | for_window [class=".*"] title_window_icon padding 3px 22 | 23 | # Right mouse click release copies the window title to the clipboard 24 | bindsym --release button3 exec --no-startup-id ~/go/bin/copy-title-for-i3 25 | 26 | # https://github.com/stapelberg/wsmgr-for-i3 27 | bindsym $mod+Tab exec GTK_IM_MODULE=ibus SWT_GTK3=1 GDK_SCALE=2 GDK_DPI_SCALE=0.5 GDK_SYNCHRONIZE=1 PATH=$HOME/go/bin:$PATH wsmgr 28 | 29 | set_from_resource $dpi Xft.dpi 96 30 | 31 | bindsym $mod+m exec --no-startup-id rofimoji --skin-tone=neutral --selector-args="-dpi $dpi" 32 | 33 | ################################################################################ 34 | # OBS (Open Broadcaster Software, https://obsproject.com/) 35 | # related settings: 36 | ################################################################################ 37 | 38 | # TODO: this should be restricted to OBS. Maybe we can just resize new dialog 39 | # windows and hope for the best? 40 | #floating_minimum_size 2000 x 1500 41 | 42 | for_window [class="obs" title="Settings" window_type="dialog"] move position mouse 43 | 44 | ################################################################################ 45 | 46 | for_window [window_type="dialog"] move position mouse 47 | 48 | # Wireshark’s (Qt’s?) file chooser dialog windows are always too small, 49 | # and will not remember the size you give them. These resize commands 50 | # will set them to a more reasonable size (in my 7680 x 4320 resolution). 51 | for_window [class="Wireshark" window_type="dialog" title="Open"] resize set 2500 3000 52 | for_window [class="Wireshark" window_type="dialog" title="Save"] resize set 2500 3000 53 | for_window [class="Wireshark" window_type="dialog" title="Export"] resize set 2500 3000 54 | 55 | workspace_layout stacked 56 | 57 | # continuously pulls temperature from homematic into i3status 58 | exec --no-startup-id exec ~/go/bin/scrape-temperature 59 | 60 | # continuously pulls upstream traffic from router7 into i3status 61 | exec --no-startup-id exec ~/go/bin/scrape-forwarded 62 | 63 | # when opening new workspaces, populate them with a 50/50 layout with 2 urxvts 64 | exec --no-startup-id exec ~/go/bin/workspace-populate-for-i3 65 | 66 | # prompt for new workspace name 67 | bindsym $mod+g exec i3-msg \"rename workspace to \\\"$(rofi -dmenu -p rename)\\\"\" 68 | 69 | # https://github.com/stapelberg/next-chrome-for-i3 70 | bindsym $mod+b exec --no-startup-id ~/go/bin/next-chrome-for-i3 71 | 72 | # https://github.com/Merovius/shellex 73 | bindsym $mod+p exec --no-startup-id shellex 74 | 75 | # close current dunst notification 76 | bindsym $mod+period exec --no-startup-id dunstctl close 77 | 78 | # jump to irssi from anywhere 79 | bindsym $mod+i [title="irssi: "] focus 80 | 81 | # https://github.com/i3/i3/pull/3748 82 | set $i3lock ~/i3lock/build/i3lock --image ~/graffiti.rgb --raw 3840x2160:rgb 83 | exec --no-startup-id xss-lock --transfer-sleep-lock -- $i3lock --nofork 84 | 85 | # Try starting nm-applet, the most popular way to manage wireless networks. 86 | exec --no-startup-id nm-applet 87 | 88 | set $refresh_i3status killall -SIGUSR1 i3status 89 | bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +5% && $refresh_i3status 90 | bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -5% && $refresh_i3status 91 | bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle && $refresh_i3status 92 | bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle && $refresh_i3status 93 | bindsym XF86AudioPrev exec --no-startup-id playerctl previous 94 | bindsym XF86AudioNext exec --no-startup-id playerctl next 95 | bindsym $mod+F9 exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle && $refresh_i3status 96 | 97 | # https://manpages.debian.org/brightnessctl 98 | # see also https://chaos.social/@vidister/109794861242265589 99 | bindsym XF86MonBrightnessDown exec --no-startup-id brightnessctl -- set '-10%' 100 | bindsym XF86MonBrightnessUp exec --no-startup-id brightnessctl -- set '+10%' 101 | 102 | # start a terminal 103 | bindsym $mod+Return exec exec ~/go/bin/wsmgr-cwd urxvtc -title 'midna: ~' 104 | bindsym $mod+Shift+Return exec exec urxvt -fn 'xft:Bitstream Vera Sans Mono:size=16' 105 | 106 | # kill focused window 107 | bindsym $mod+Shift+x kill 108 | 109 | # start j4-dmenu-desktop, which is a faster version of i3-dmenu-desktop, which 110 | # is a wrapper around dmenu that only displays .desktop files (as opposed to 111 | # executable files in $PATH like dmenu_run). 112 | bindsym $mod+a exec j4-dmenu-desktop || i3-dmenu-desktop 113 | 114 | # change focus 115 | bindsym $mod+n focus left 116 | bindsym $mod+r focus down 117 | bindsym $mod+t focus up 118 | bindsym $mod+d focus right 119 | 120 | # alternatively, you can use the cursor keys: 121 | bindsym $mod+Left focus left 122 | bindsym $mod+Down focus down 123 | bindsym $mod+Up focus up 124 | bindsym $mod+Right focus right 125 | 126 | # move focused window 127 | bindsym $mod+Shift+n move left 128 | bindsym $mod+Shift+r move down 129 | bindsym $mod+Shift+t move up 130 | bindsym $mod+Shift+d move right 131 | 132 | # alternatively, you can use the cursor keys: 133 | bindsym $mod+Shift+Left move left 134 | bindsym $mod+Shift+Down move down 135 | bindsym $mod+Shift+Up move up 136 | bindsym $mod+Shift+Right move right 137 | 138 | # split in horizontal orientation 139 | bindsym $mod+s split h 140 | 141 | # enter fullscreen mode for the focused container 142 | bindsym $mod+e fullscreen toggle 143 | 144 | # lock screen 145 | bindsym $mod+l exec --no-startup-id loginctl lock-session 146 | 147 | # toggle tiling / floating 148 | bindsym $mod+Shift+space floating toggle 149 | 150 | # change focus between tiling / floating windows 151 | bindsym $mod+space focus mode_toggle 152 | 153 | # focus the parent container 154 | bindsym $mod+u focus parent 155 | 156 | # move the currently focused window to the scratchpad 157 | bindsym $mod+Shift+minus move scratchpad 158 | 159 | # Show the next scratchpad window or hide the focused scratchpad window. 160 | # If there are multiple scratchpad windows, this command cycles through them. 161 | bindsym $mod+minus scratchpad show 162 | bindsym $mod+c scratchpad show 163 | 164 | # focus the child container 165 | #bindsym $mod+d focus child 166 | 167 | # Define names for default workspaces for which we configure key bindings later on. 168 | # We use variables to avoid repeating the names in multiple places. 169 | set $ws1 "1" 170 | set $ws2 "2" 171 | set $ws3 "3" 172 | set $ws4 "4" 173 | set $ws5 "5" 174 | set $ws6 "6" 175 | set $ws7 "7" 176 | set $ws8 "8" 177 | set $ws9 "9" 178 | set $ws10 "10" 179 | 180 | # switch to workspace 181 | bindsym $mod+1 workspace number $ws1 182 | bindsym $mod+2 workspace number $ws2 183 | bindsym $mod+3 workspace number $ws3 184 | bindsym $mod+4 workspace number $ws4 185 | bindsym $mod+5 workspace number $ws5 186 | bindsym $mod+6 workspace number $ws6 187 | bindsym $mod+7 workspace number $ws7 188 | bindsym $mod+8 workspace number $ws8 189 | bindsym $mod+9 workspace number $ws9 190 | bindsym $mod+0 workspace number $ws10 191 | 192 | # move focused container to workspace 193 | bindsym $mod+Shift+1 move container to workspace number $ws1 194 | bindsym $mod+Shift+2 move container to workspace number $ws2 195 | bindsym $mod+Shift+3 move container to workspace number $ws3 196 | bindsym $mod+Shift+4 move container to workspace number $ws4 197 | bindsym $mod+Shift+5 move container to workspace number $ws5 198 | bindsym $mod+Shift+6 move container to workspace number $ws6 199 | bindsym $mod+Shift+7 move container to workspace number $ws7 200 | bindsym $mod+Shift+8 move container to workspace number $ws8 201 | bindsym $mod+Shift+9 move container to workspace number $ws9 202 | bindsym $mod+Shift+0 move container to workspace number $ws10 203 | 204 | # reload the configuration file 205 | bindsym $mod+Shift+adiaeresis reload 206 | # restart i3 inplace (preserves your layout/session, can be used to upgrade i3) 207 | bindsym $mod+Shift+c restart 208 | # exit i3 (logs you out of your X session) 209 | bindsym $mod+Shift+l exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'" 210 | 211 | mode "liecht" { 212 | bindsym 1 exec --no-startup-id ~/go/bin/liecht -dim 10; mode "default" 213 | bindsym 5 exec --no-startup-id ~/go/bin/liecht -dim 100; mode "default" 214 | bindsym 9 exec --no-startup-id ~/go/bin/liecht -dim 254; mode "default" 215 | bindsym 0 exec --no-startup-id ~/go/bin/liecht -dim 0; mode "default" 216 | bindsym Return mode "default" 217 | bindsym Escape mode "default" 218 | } 219 | bindsym $mod+z mode "liecht" 220 | 221 | mode "volume" { 222 | bindsym $mod+v exec --no-startup-id ~/.config/i3/toggle-output.sh; mode "default" 223 | 224 | bindsym --release Left exec --no-startup-id xdotool key XF86AudioPrev; mode "default" 225 | bindsym --release Right exec --no-startup-id xdotool key XF86AudioNext; mode "default" 226 | 227 | bindsym 1 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ 10\% && killall -USR1 i3status; mode "default" 228 | bindsym 2 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ 20\% && killall -USR1 i3status; mode "default" 229 | bindsym 3 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ 30\% && killall -USR1 i3status; mode "default" 230 | bindsym 4 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ 40\% && killall -USR1 i3status; mode "default" 231 | bindsym 5 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ 50\% && killall -USR1 i3status; mode "default" 232 | bindsym 6 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ 60\% && killall -USR1 i3status; mode "default" 233 | bindsym 7 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ 70\% && killall -USR1 i3status; mode "default" 234 | bindsym 8 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ 80\% && killall -USR1 i3status; mode "default" 235 | bindsym 9 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ 90\% && killall -USR1 i3status; mode "default" 236 | bindsym 0 exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ 100\% && killall -USR1 i3status; mode "default" 237 | # back to normal: Enter or Escape 238 | bindsym Return mode "default" 239 | bindsym Escape mode "default" 240 | } 241 | bindsym $mod+v mode "volume" 242 | 243 | # Start i3bar to display a workspace bar (plus the system information i3status 244 | # finds out, if available) 245 | bar { 246 | status_command i3status 247 | } 248 | -------------------------------------------------------------------------------- /config/i3status/config: -------------------------------------------------------------------------------- 1 | general { 2 | colors = true 3 | interval = 1 4 | } 5 | 6 | order += "read_file door" 7 | order += "read_file wohnzimmer" 8 | order += "ipv6" 9 | order += "disk /" 10 | order += "ethernet _first_" 11 | order += "volume master" 12 | order += "load" 13 | order += "memory" 14 | order += "read_file upstream" 15 | order += "time" 16 | 17 | ipv6 { 18 | format_up = "%ip" 19 | } 20 | 21 | read_file upstream { 22 | format = "upstream: %content" 23 | format_bad = "" 24 | path = "/run/user/1000/i3status/upstream.traffic" 25 | } 26 | 27 | read_file door { 28 | format = "nuki: %content" 29 | format_bad = "" 30 | path = "/run/user/1000/i3status/nuki.temp" 31 | } 32 | 33 | read_file wohnzimmer { 34 | format = "wohnzimmer: %content ℃" 35 | format_bad = "" 36 | path = "/run/user/1000/i3status/wohnzimmer.temp" 37 | } 38 | 39 | volume master { 40 | device = "default" 41 | format = "♪ %volume, default: %devicename" 42 | } 43 | 44 | ethernet _first_ { 45 | format_up = "E: %ip (%speed)" 46 | format_down = "E: down" 47 | } 48 | 49 | time { 50 | format = "%Y-%m-%d %H:%M:%S" 51 | } 52 | 53 | load { 54 | format = "load: %5min" 55 | } 56 | 57 | 58 | disk "/" { 59 | format = "disk: %free" 60 | } 61 | 62 | memory { 63 | format = "mem: %available" 64 | } 65 | -------------------------------------------------------------------------------- /config/systemd/user/hugo.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=hugo 3 | StartLimitIntervalSec=0 4 | 5 | [Service] 6 | Restart=always 7 | RestartSec=1s 8 | WorkingDirectory=/home/michael/hugo 9 | # Force native Go resolver 10 | Environment=GODEBUG=netdns=go 11 | ExecStartPre=/bin/sh -c 'cd /tmp && sudo tailscale cert midna.monkey-turtle.ts.net && sudo chown michael *.crt *.key' 12 | # Specifying --port explicitly makes hugo not fall back 13 | # to a different port when listening fails, but retry 14 | # due to the systemd Restart=always setting. 15 | ExecStart=/home/michael/go/bin/hugo \ 16 | serve \ 17 | -D \ 18 | --bind midna.monkey-turtle.ts.net \ 19 | --port 1313 \ 20 | --baseURL https://midna.monkey-turtle.ts.net:1313/ \ 21 | --tlsCertFile /tmp/midna.monkey-turtle.ts.net.crt \ 22 | --tlsKeyFile /tmp/midna.monkey-turtle.ts.net.key 23 | 24 | [Install] 25 | WantedBy=default.target 26 | -------------------------------------------------------------------------------- /cwd-spawn: -------------------------------------------------------------------------------- 1 | # urxvt prepends "use strict; use utf8;\n", screwing with our line numbers 2 | #line 3 3 | 4 | =head1 NAME 5 | 6 | cwd-spawn - open a new urxvt within the current working directory. 7 | 8 | 9 | =head1 INSTALLATION 10 | 11 | 12 | 1) adjust your F<.Xresources> 13 | 14 | URxvt*perl-lib: /home/user/.urxvt 15 | URxvt*perl-ext: cwd-spawn 16 | URxvt*keysym.M-o: perl:cwd-spawn 17 | 18 | 2) copy/symlink this script into F 19 | 20 | 3) adjust your shell config to include these functions 21 | (known to work with zsh/bash/ksh) 22 | 23 | cwd_to_urxvt() { 24 | local update="\0033]777;cwd-spawn;path;$PWD\0007" 25 | 26 | case $TERM in 27 | screen*) 28 | # pass through to parent terminal emulator 29 | update="\0033P$update\0033\\";; 30 | esac 31 | 32 | echo -ne "$update" 33 | } 34 | 35 | cwd_to_urxvt # execute upon startup to set initial directory 36 | 37 | ssh_connection_to_urxvt() { 38 | # don't propagate information to urxvt if ssh is used non-interactive 39 | [ -t 0 ] || [ -t 1 ] || return 40 | 41 | local update="\0033]777;cwd-spawn;ssh;$1\0007" 42 | 43 | case $TERM in 44 | screen*) 45 | # pass through to parent terminal emulator 46 | update="\0033P$update\0033\\";; 47 | esac 48 | 49 | echo -ne "$update" 50 | } 51 | 52 | 4) adjust F<.ssh/config> 53 | 54 | Host * 55 | PermitLocalCommand yes 56 | LocalCommand ssh_connection_to_urxvt "%r %h %p" 57 | 58 | 5) execute cwd_to_urxvt each time you change your directory. 59 | 60 | # zsh supports hooks which execute each time you change your cwd: 61 | chpwd_functions=(${chpwd_functions} cwd_to_urxvt) 62 | 63 | Support for other shells are left as an exercise for the reader ;-) 64 | 65 | 66 | =head1 BUGS 67 | 68 | C doesn’t invoke LocalCommand if you connect through “master” mode. 69 | Thus C always copies the connection information into the new terminal. 70 | While this works fine for a single connection, it fails if you nest ssh connections (as a slave through “master” mode). 71 | As a workaround, manually invoke C. 72 | 73 | 74 | =head1 COPYRIGHT AND LICENSE 75 | 76 | Copyright (C) 2011 Maik Fischer L 77 | 78 | This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. 79 | 80 | 81 | =cut 82 | 83 | sub _octal_escape { 84 | my ($string) = @_; 85 | 86 | my $escape = sub { 87 | my ($char) = @_; 88 | ord($char) > 127 89 | ? $char 90 | : sprintf("\0%.3o", $char) 91 | }; 92 | 93 | $string =~ s!([^A-Za-z0-9/_-])!$escape->($1)!sge; 94 | return $string; 95 | } 96 | 97 | use Encode; 98 | my $utf8 = Encode::find_encoding('UTF-8'); 99 | 100 | sub on_osc_seq_perl { 101 | my ($self, $osc, $resp) = @_; 102 | 103 | return unless $osc =~ s/^cwd-spawn;//; 104 | 105 | # decode raw bytestring into utf8 106 | local $@; 107 | $osc = eval { $utf8->decode($osc, Encode::FB_CROAK) }; 108 | if ($@) { 109 | warn "cwd-spawn: called with garbage: $@"; 110 | return; 111 | } 112 | 113 | return unless $osc =~ s/^(path|ssh);//; 114 | my $cmd = $1; 115 | 116 | my $storage = $self->{'cwd-spawn'} ||= {}; 117 | 118 | if ($cmd eq 'path') { 119 | # path sanitizing is context specific, we do that in on_user_command 120 | $storage->{path} = $osc; 121 | 122 | } else { 123 | my ($user, $host, $port) = split ' ', $osc; 124 | 125 | # user and port are arguments to parameters, we can pass them as-is 126 | # host may be used to pass arbitrary parameters to ssh 127 | return if $host =~ /^-/; 128 | 129 | @{$storage}{qw/user host port/} = ($user, $host, $port); 130 | } 131 | 132 | $self->_dump if $ENV{DEBUG_URXVT_CWDSPAWN}; 133 | return 1; 134 | } 135 | 136 | sub on_user_command { 137 | my ($self, $cmd) = @_; 138 | 139 | return unless $cmd eq 'cwd-spawn'; 140 | 141 | $self->_dump if $ENV{DEBUG_URXVT_CWDSPAWN}; 142 | 143 | my $storage = $self->{'cwd-spawn'} 144 | or return; 145 | 146 | my ($cwd, $user, $host, $port) = @{$storage}{qw/path user host port/}; 147 | 148 | my $name = 'URxvt'; # hardcode for now 149 | 150 | my @args; 151 | if ($host) { 152 | # escape $path here since it is subject to shell-expansion 153 | my $path = _octal_escape($cwd); 154 | @args = ( 155 | '-e', 156 | 'ssh', '-t', '-p', $port, '-l', $user, $host, 157 | "cd \"$path\"; exec \$SHELL -l" 158 | ) 159 | } else { 160 | @args = ('-cd', $cwd); 161 | } 162 | 163 | warn "cwd-spawn: would start urxvt with: @args" 164 | if $ENV{DEBUG_URXVT_CWDSPAWN}; 165 | 166 | my $term = urxvt::term->new($self->env, $name, @args); 167 | 168 | # ssh doesn't execute LocalCommand if used through ControlMaster 169 | # see BUGS in POD 170 | $term->cmd_parse("\e]777;cwd-spawn;ssh;$user $host $port\a") if $host; 171 | 172 | return; 173 | } 174 | 175 | sub _dump { 176 | my $storage = shift->{'cwd-spawn'}; 177 | warn 'cwd-spawn: $storage is empty!' unless $storage; 178 | warn sprintf('cwd-spawn: ' . ('%s: "%s" ' x keys %$storage), %$storage); 179 | } 180 | 181 | # vim: set ts=4 sw=4 sts=4 ft=perl expandtab: 182 | -------------------------------------------------------------------------------- /devscripts: -------------------------------------------------------------------------------- 1 | BTS_SENDMAIL_COMMAND="/usr/sbin/sendmail -oem -ti -f michael@stapelberg.de" 2 | DEBSIGN_KEYID="424E14D703E7C6D43D9D6F364E7160ED4AC8EE1D" 3 | -------------------------------------------------------------------------------- /diff-rel: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # vim:ts=4:sw=4:expandtab 3 | # diffs two release tarballs 4 | 5 | use strict; 6 | use warnings; 7 | use File::Temp qw(tempfile); 8 | use File::Basename qw(basename); 9 | use File::Spec; 10 | use v5.10; 11 | 12 | my $old = shift; 13 | my $new = shift; 14 | 15 | sub get_file_list { 16 | my ($name) = @_; 17 | 18 | my @files = split("\n", qx(tar tf "$name" | sort)); 19 | return map { s,^[^/]+/,,g; $_ } @files; 20 | } 21 | 22 | sub write_list_to_tmp { 23 | my ($origname, $list) = @_; 24 | my ($fh, $name) = tempfile( 25 | basename($origname) . '-XXXXXX', 26 | UNLINK => 1, 27 | DIR => File::Spec->tmpdir() 28 | ); 29 | say $fh join("\n", @$list); 30 | close($fh); 31 | return $name; 32 | } 33 | 34 | my @oldfiles = get_file_list($old); 35 | my @newfiles = get_file_list($new); 36 | 37 | system("diff", "-u", "--report-identical-files", 38 | write_list_to_tmp($old, \@oldfiles), 39 | write_list_to_tmp($new, \@newfiles)); 40 | -------------------------------------------------------------------------------- /dupload.conf: -------------------------------------------------------------------------------- 1 | package config; 2 | 3 | # Copied from /etc/dupload.conf, but with passive => 1 4 | $cfg{'anonymous-ftp-master'} = { 5 | fqdn => "ftp.upload.debian.org", 6 | incoming => "/pub/UploadQueue/", 7 | # The dinstall on ftp-master sends emails itself 8 | dinstall_runs => 1, 9 | passive => 1, 10 | }; 11 | 12 | 1; 13 | -------------------------------------------------------------------------------- /gbp.conf: -------------------------------------------------------------------------------- 1 | # The following documentation is largely for myself. I intend to publish a nicer 2 | # write-up once this is a smoother workflow. 3 | # 4 | # 1. Create the expected directory structure: 5 | # % mkdir -p ~/d/{pkg,out} 6 | # 7 | # 2. Add the following to your ~/.zshrc: 8 | # # Define $pkg and $out whenever working in a sub directory of ~/d/pkg/: 9 | # chpwd_profiles() { 10 | # if [[ "$PWD" =~ "$HOME/d/(pkg|out)/([^/]*)" ]] 11 | # then 12 | # export pkg=$HOME/d/pkg/$match[2] 13 | # export out=$HOME/d/out/$match[2] 14 | # else 15 | # unset pkg 16 | # unset out 17 | # fi 18 | # } 19 | # chpwd_functions=( ${chpwd_functions[@]} chpwd_profiles ) 20 | # chpwd_profiles # subshells (e.g. VIM’s :sh) never call chpwd_functions 21 | # 22 | # # Clones the git sources of a Debian package 23 | # # needs debcheckout from devscripts and gbp-clone from git-buildpackage 24 | # d-clone() { 25 | # local package=$1 26 | # if ! debcheckout --auth --print $package >/dev/null 27 | # then 28 | # echo "debcheckout $package failed. Is $package missing Vcs tags?" 29 | # return 30 | # fi 31 | # 32 | # set -- $(debcheckout --auth --print $package) 33 | # if [ "$1" != "git" ] 34 | # then 35 | # echo "$package does not use git, but $1 instead." 36 | # return 37 | # fi 38 | # 39 | # echo "cloning $2" 40 | # gbp clone --pristine-tar $2 || return 41 | # 42 | # # Change to the newest git repository 43 | # cd $(dirname $(ls -1td */.git | head -1)) || return 44 | # 45 | # echo "d-clone set up everything successfully." 46 | # } 47 | # 48 | # 3. Create a Debian package directory within ~/d/pkg: 49 | # ~/d/pkg % d-clone acmetool 50 | # 51 | # 4. Build the Debian package using: 52 | # ~/d/pkg/acmetool % gbp buildpackage --git-export-dir=$out 53 | # 54 | # 5. Create a changelog entry with an updated version number since the last tagged 55 | # version: 56 | # ~/d/pkg/acmetool % gbp dch -R --commit 57 | # 58 | # 6. Upload the resulting package: 59 | # ~/d/pkg/acmetool % cd $out 60 | # ~/d/out/acmetool % less *_source.changes 61 | # # TODO: how can one debdiff against the archive? 62 | # ~/d/out/acmetool % debdiff _source.changes _source.changes # if you have old builds 63 | # ~/d/out/acmetool % dput 64 | # ~/d/out/acmetool % cd $pkg 65 | # ~/d/pkg/acmetool % gbp push 66 | 67 | [clone] 68 | # Ensure the correct orig tarball is present. 69 | postclone=origtargz 70 | 71 | [buildpackage] 72 | # Sign tags when running e.g. gbp buildpackage --git-tag-only 73 | sign-tags = True 74 | 75 | # sbuild: 76 | # --source-only-changes 77 | # In addition to the binary .changes file, also create a _source.changes 78 | # file which can be used for a source-only upload. 79 | # -s: build the source package. 80 | # Without this flag, packages such as 81 | # src:golang-github-thomsonreuterseikon-go-ntlm will not get an 82 | # *_amd64.changes file which can actually be uploaded (instead, the 83 | # changes file would just contain *_all.deb and *.buildinfo) 84 | # -A: also build “arch: all” packages 85 | # (sbuild defaults to architecture-specific binaries) 86 | # For source-only uploads, “arch: all” are built by the buildds, but 87 | # let’s build them anyways to cover non-source-only upload as well. 88 | # -v: verbose 89 | # --no-clean-source: don’t require build-deps on the host (only within 90 | # sbuild). cleaning is unnecessary, as we use gbp’s --git-export-dir anyway. 91 | builder = sbuild --source-only-changes -s -v -A --no-clean-source 92 | 93 | postbuild = echo Running lintian $GBP_CHANGES_FILE: && lintian $(echo $GBP_CHANGES_FILE | sed 's,_all\.changes$,_amd64.changes,g') 94 | 95 | # Pick up the orig tarballs created by the origtargz postclone hook. 96 | tarball-dir = .. 97 | -------------------------------------------------------------------------------- /gdbinit: -------------------------------------------------------------------------------- 1 | set history save 2 | set print pretty on 3 | set prompt \001\033[01;31m\002gdb $ \001\033[0m\002 4 | 5 | define dtailq 6 | set $next = $arg0.tqh_first 7 | while ($next != 0) 8 | p $next 9 | p *$next 10 | set $next = $next.$arg1.tqe_next 11 | end 12 | end 13 | 14 | define dslist 15 | set $next = $arg0.slh_first 16 | while ($next != 0) 17 | p $next 18 | set $next = $next.$arg1.sle_next 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /gitconfig: -------------------------------------------------------------------------------- 1 | [alias] 2 | a = add 3 | ca = commit -a 4 | c = commit 5 | co = checkout 6 | d = diff 7 | l = log 8 | rh = reset --hard 9 | s = status 10 | t = tag 11 | 12 | [color] 13 | ui = auto 14 | 15 | [push] 16 | default = tracking 17 | 18 | [diff] 19 | renames = copies 20 | mnemonicprefix = true 21 | compactionHeuristic = true 22 | 23 | [user] 24 | name = Michael Stapelberg 25 | email = michael@stapelberg.de 26 | signingkey = 4E7160ED4AC8EE1D 27 | 28 | [rebase] 29 | autoStash = true 30 | 31 | [pager] 32 | diff = LESS=RS less -c 33 | 34 | [core] 35 | excludesfile = ~/configfiles/gitignore 36 | 37 | [http] 38 | cookiefile = ~/.gitcookies 39 | [url "git@gitlab.com:ipng.ch"] 40 | insteadOf = https://gitlab.com/ipng.ch 41 | [url "git.debian.org:/git/"] 42 | insteadOf = https://anonscm.debian.org/git/ 43 | [url "git@salsa.debian.org:"] 44 | insteadOf = https://salsa.debian.org/ 45 | [github] 46 | user = stapelberg 47 | [init] 48 | defaultBranch = main 49 | [credential "https://github.com"] 50 | helper = 51 | helper = !/usr/bin/gh auth git-credential 52 | -------------------------------------------------------------------------------- /gitignore: -------------------------------------------------------------------------------- 1 | # vim/emacs tags/TAGS 2 | 3 | /tags 4 | /TAGS 5 | 6 | # https://raw.githubusercontent.com/github/gitignore/master/Global/Vim.gitignore 7 | 8 | [._]*.s[a-w][a-z] 9 | [._]s[a-w][a-z] 10 | *.un~ 11 | Session.vim 12 | .netrwhist 13 | *~ 14 | 15 | # https://raw.githubusercontent.com/github/gitignore/master/Global/Emacs.gitignore 16 | 17 | *~ 18 | \#*\# 19 | /.emacs.desktop 20 | /.emacs.desktop.lock 21 | *.elc 22 | auto-save-list 23 | tramp 24 | .\#* 25 | 26 | # Org-mode 27 | .org-id-locations 28 | *_archive 29 | 30 | # flymake-mode 31 | *_flymake.* 32 | 33 | # eshell files 34 | /eshell/history 35 | /eshell/lastdir 36 | 37 | # elpa packages 38 | /elpa/ 39 | 40 | # reftex files 41 | *.rel 42 | 43 | # AUCTeX auto folder 44 | /auto/ 45 | 46 | # cask packages 47 | .cask/ 48 | -------------------------------------------------------------------------------- /gocode/bin/configfiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stapelberg/configfiles/95def678d9119b99a7d478863b6b113114a6aea4/gocode/bin/configfiles -------------------------------------------------------------------------------- /gocode/bin/configfiles.amd64: -------------------------------------------------------------------------------- 1 | configfiles -------------------------------------------------------------------------------- /gocode/bin/configfiles.arm64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stapelberg/configfiles/95def678d9119b99a7d478863b6b113114a6aea4/gocode/bin/configfiles.arm64 -------------------------------------------------------------------------------- /gocode/src/configfiles/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: update 2 | 3 | all: 4 | 5 | update: 6 | CGO_ENABLED=0 GOARCH=amd64 go build 7 | mv configfiles ../../bin 8 | CGO_ENABLED=0 GOARCH=arm64 go build 9 | mv configfiles ../../bin/configfiles.arm64 10 | -------------------------------------------------------------------------------- /gocode/src/configfiles/configfiles-updater.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=configfiles updater 3 | 4 | [Service] 5 | ExecStart=/home/michael/configfiles/gocode/bin/configfiles -daemon 6 | 7 | [Install] 8 | WantedBy=multi-user.target 9 | -------------------------------------------------------------------------------- /gocode/src/configfiles/gitresolve.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "net" 7 | "net/url" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | // Resolves the revision to which HEAD of the specified git URL points to. 13 | // This function can be used to skip executing git pull (which is typically 14 | // more expensive due to involving SSH or HTTPS). 15 | // 16 | // For details an the git pack protocol, see 17 | // https://github.com/git/git/blob/master/Documentation/technical/pack-protocol.txt 18 | func gitResolve(giturl string) (string, error) { 19 | u, err := url.Parse(giturl) 20 | if err != nil { 21 | return "", err 22 | } 23 | 24 | // Add git port unless |giturl| already contained a port. 25 | if _, _, err := net.SplitHostPort(u.Host); err != nil { 26 | u.Host = u.Host + ":git" 27 | } 28 | 29 | conn, err := net.Dial("tcp", u.Host) 30 | if err != nil { 31 | return "", err 32 | } 33 | defer conn.Close() 34 | conn.SetDeadline(time.Now().Add(1 * time.Minute)) 35 | req := fmt.Sprintf("%04xgit-upload-pack %s\x00host=%s\x00", 0, u.Path, u.Host) 36 | fmt.Fprintf(conn, "%04x%s", len(req), req[4:]) 37 | 38 | suffix := " refs/heads/master\n" 39 | 40 | r := bufio.NewReader(conn) 41 | // Skip the first line, which is separated by a 0-byte. 42 | if _, err := r.ReadString('\x00'); err != nil { 43 | return "", err 44 | } 45 | for { 46 | line, err := r.ReadString('\n') 47 | if err != nil { 48 | return "", err 49 | } 50 | if strings.HasSuffix(line, suffix) { 51 | // The first 4 bytes are the length of the line. 52 | return line[4 : len(line)-len(suffix)], nil 53 | } 54 | if strings.HasPrefix(line, "0000") { 55 | break 56 | } 57 | } 58 | return "", fmt.Errorf("git protocol error: no line ended in %q", suffix) 59 | } 60 | -------------------------------------------------------------------------------- /gocode/src/configfiles/go.mod: -------------------------------------------------------------------------------- 1 | module configfiles 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/godbus/dbus v4.1.0+incompatible 7 | github.com/nightlyone/lockfile v1.0.0 8 | ) 9 | -------------------------------------------------------------------------------- /gocode/src/configfiles/go.sum: -------------------------------------------------------------------------------- 1 | github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4= 2 | github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= 3 | github.com/nightlyone/lockfile v1.0.0 h1:RHep2cFKK4PonZJDdEl4GmkabuhbsRMgk/k3uAmxBiA= 4 | github.com/nightlyone/lockfile v1.0.0/go.mod h1:rywoIealpdNse2r832aiD9jRk8ErCatROs6LzC841CI= 5 | -------------------------------------------------------------------------------- /gocode/src/configfiles/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "io" 7 | "io/ioutil" 8 | "log" 9 | "os" 10 | "os/exec" 11 | "path/filepath" 12 | "sort" 13 | "strconv" 14 | "strings" 15 | "time" 16 | 17 | "github.com/godbus/dbus" 18 | "github.com/nightlyone/lockfile" 19 | ) 20 | 21 | var ( 22 | force = flag.Bool("force", 23 | false, 24 | "Force an update, even though local/remote are at the same revision and/or the config files were recently updated.") 25 | 26 | quiet = flag.Bool("quiet", 27 | false, 28 | "Do not print any log messages to stderr.") 29 | 30 | daemonMode = flag.Bool("daemon", 31 | false, 32 | "If true, will run in an endless loop, updating config files once an hour and whenever network connectivity (as communicated by NetworkManager) changes.") 33 | 34 | configfilesDir = flag.String("configfiles_dir", 35 | "/home/michael/configfiles", 36 | "Path to the configuration files working copy") 37 | 38 | readOnlyGitRemote = flag.String("read_only_git_remote", 39 | "git://code.stapelberg.de/configfiles", 40 | "git:// URL to the config file repository (read-only)") 41 | ) 42 | 43 | // From libnm-util/NetworkManager.h 44 | const ( 45 | NM_DEVICE_STATE_ACTIVATED = 100 46 | ) 47 | 48 | func filterStateChanges(in <-chan *dbus.Signal, out chan<- bool) { 49 | for signal := range in { 50 | if len(signal.Body) != 3 { 51 | log.Panicf("protocol error: NetworkManager sent a StateChanged signal with %d members, expected 3\n", len(signal.Body)) 52 | } 53 | newState, ok := signal.Body[0].(uint32) 54 | if !ok { 55 | log.Panicf("protocol error: NetworkManager sent a StateChanged signal where members are not uint32\n") 56 | } 57 | if newState != NM_DEVICE_STATE_ACTIVATED { 58 | continue 59 | } 60 | // We don’t use NetworkManager’s CheckConnectivity method because it 61 | // has many false-positives (at least with NetworkManager 1.0.6), i.e. 62 | // it will say you have full connectivity, even though you are 63 | // connected to an Android tethering hotspot without upstream 64 | // connectivity. So, we save the code complexity of dealing with an API 65 | // that doesn’t provide us useful data. 66 | 67 | // Trigger a check if we can. If we can’t, the implication is that a 68 | // check is currently running, which is fine as well. 69 | select { 70 | case out <- true: 71 | default: 72 | } 73 | } 74 | } 75 | 76 | func daemon() { 77 | conn, err := dbus.SystemBus() 78 | if err != nil { 79 | log.Fatal(err) 80 | } 81 | 82 | // Subscribe to device state changes so that we get notified when a device 83 | // gets activated. We can then trigger a connectivity check. 84 | if err := conn.BusObject().Call( 85 | "org.freedesktop.DBus.AddMatch", 86 | 0, 87 | "type='signal',"+ 88 | "interface='org.freedesktop.NetworkManager.Device',"+ 89 | "member='StateChanged'").Err; err != nil { 90 | log.Fatal(err) 91 | } 92 | 93 | connectivityChanged := make(chan bool) 94 | 95 | // If filterStateChanges does not read signals fast enough, i.e. the signal 96 | // channel write blocks, godbus will panic. The intention of the channel 97 | // buffer (which was arbitrarily sized) is to make that situation as 98 | // unlikely as possible. 99 | signals := make(chan *dbus.Signal, 100) 100 | conn.Signal(signals) 101 | go filterStateChanges(signals, connectivityChanged) 102 | 103 | for { 104 | select { 105 | case <-connectivityChanged: 106 | log.Printf("Connectivity changed. Waiting for the situation to settle (1m without changes).\n") 107 | 108 | Settled: 109 | for { 110 | select { 111 | case <-connectivityChanged: 112 | log.Printf("Connectivity changed again, waiting another 1m.\n") 113 | case <-time.After(1 * time.Minute): 114 | break Settled 115 | } 116 | } 117 | 118 | log.Printf("could check for an update now\n") 119 | if err := pull(); err != nil { 120 | log.Fatal(err) 121 | } 122 | 123 | case <-time.After(1 * time.Hour): 124 | log.Printf("check opportunistically for an update now\n") 125 | if err := pull(); err != nil { 126 | log.Fatal(err) 127 | } 128 | } 129 | } 130 | } 131 | 132 | func copyFile(src, dest string) error { 133 | in, err := os.Open(src) 134 | if err != nil { 135 | return err 136 | } 137 | defer in.Close() 138 | fi, err := in.Stat() 139 | if err != nil { 140 | return err 141 | } 142 | // Remove the destination file in case it is read-only (packfiles of git 143 | // submodules are read-only). 144 | if err := os.Remove(dest); err != nil && !os.IsNotExist(err) { 145 | return err 146 | } 147 | out, err := os.OpenFile(dest, os.O_CREATE|os.O_RDWR, fi.Mode()) 148 | if err != nil { 149 | return err 150 | } 151 | if _, err := io.Copy(out, in); err != nil { 152 | return err 153 | } 154 | if err := out.Close(); err != nil { 155 | return nil 156 | } 157 | return os.Chtimes(dest, time.Now(), fi.ModTime()) 158 | } 159 | 160 | func copyAll(src, dest string) error { 161 | return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { 162 | if err != nil { 163 | return err 164 | } 165 | if info.IsDir() { 166 | return os.MkdirAll(strings.Replace(path, src, dest, 1), info.Mode()) 167 | } 168 | if !info.Mode().IsRegular() { 169 | return nil 170 | } 171 | return copyFile(path, strings.Replace(path, src, dest, 1)) 172 | }) 173 | } 174 | 175 | func gitTrackedFiles(dir string, stderr io.Writer) (map[string]bool, error) { 176 | cmd := exec.Command("git", "ls-files") 177 | cmd.Dir = dir 178 | cmd.Stderr = stderr 179 | out, err := cmd.Output() 180 | if err != nil { 181 | return nil, err 182 | } 183 | tracked := make(map[string]bool) 184 | for _, filename := range strings.Split(string(out), "\n") { 185 | if strings.TrimSpace(filename) == "" { 186 | continue 187 | } 188 | tracked[filename] = true 189 | } 190 | return tracked, nil 191 | } 192 | 193 | func copyGitTracked(src, dest string) error { 194 | tracked, err := gitTrackedFiles(src, ioutil.Discard) 195 | if err != nil { 196 | return err 197 | } 198 | return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { 199 | if err != nil { 200 | return err 201 | } 202 | relative := strings.Replace(path, src+"/", "", 1) 203 | if !tracked[relative] { 204 | return nil 205 | } 206 | if info.IsDir() { 207 | return os.MkdirAll(strings.Replace(path, src, dest, 1), info.Mode()) 208 | } 209 | if !info.Mode().IsRegular() { 210 | return nil 211 | } 212 | 213 | destfn := strings.Replace(path, src, dest, 1) 214 | if err := os.MkdirAll(filepath.Dir(destfn), 0755); err != nil { 215 | return err 216 | } 217 | 218 | return copyFile(path, destfn) 219 | }) 220 | } 221 | 222 | func moveGitFiles(src, dest string, errLog io.Writer) error { 223 | tracked, err := gitTrackedFiles(dest, errLog) 224 | if err != nil { 225 | return err 226 | } 227 | return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { 228 | if info.IsDir() { 229 | return os.MkdirAll(strings.Replace(path, src, dest, 1), info.Mode()) 230 | } 231 | if !info.Mode().IsRegular() { 232 | return nil 233 | } 234 | relative := strings.Replace(path, src+"/", "", 1) 235 | if !tracked[relative] { 236 | return nil 237 | } 238 | return os.Rename(path, dest+"/"+relative) 239 | }) 240 | 241 | } 242 | 243 | func judgeErrors() error { 244 | logs, err := os.Open(filepath.Join(*configfilesDir, ".logs")) 245 | if err != nil { 246 | return err 247 | } 248 | defer logs.Close() 249 | 250 | names, err := logs.Readdirnames(-1) 251 | if err != nil { 252 | return err 253 | } 254 | 255 | sort.Sort(sort.Reverse(sort.StringSlice(names))) 256 | 257 | seenSuccess := false 258 | for _, name := range names { 259 | if !seenSuccess && strings.HasSuffix(name, ".success") { 260 | seenSuccess = true 261 | } 262 | last := strings.LastIndex(name, ".") 263 | if last == -1 { 264 | last = len(name) 265 | } 266 | epoch, err := strconv.ParseInt(name[:last], 0, 64) 267 | if err != nil { 268 | return err 269 | } 270 | if time.Since(time.Unix(epoch, 0)) > 5*time.Hour { 271 | break 272 | } 273 | } 274 | if !seenSuccess { 275 | log.Printf("No success within the last 5 hours, creating ERROR file\n") 276 | f, err := os.Create(filepath.Join(*configfilesDir, "ERROR")) 277 | if err != nil { 278 | return err 279 | } 280 | return f.Close() 281 | } 282 | return nil 283 | } 284 | 285 | func pullStashed(twd string, errLog io.Writer) error { 286 | cmd := exec.Command("git", "stash") 287 | cmd.Dir = twd 288 | cmd.Stdout = errLog 289 | cmd.Stderr = errLog 290 | if err := cmd.Run(); err != nil { 291 | return err 292 | } 293 | 294 | cmd = exec.Command("git", "pull", "--ff-only") 295 | cmd.Dir = twd 296 | cmd.Stdout = errLog 297 | cmd.Stderr = errLog 298 | if err := cmd.Run(); err != nil { 299 | return err 300 | } 301 | 302 | // Check if there are stashed changes at all, since “git stash pop” returns 303 | // with non-zero exit code when called with no stashed changes. 304 | cmd = exec.Command("git", "stash", "list") 305 | cmd.Dir = twd 306 | out, err := cmd.Output() 307 | if err != nil { 308 | return err 309 | } 310 | if strings.TrimSpace(string(out)) == "" { 311 | return nil 312 | } 313 | 314 | cmd = exec.Command("git", "stash", "pop") 315 | cmd.Dir = twd 316 | cmd.Stdout = errLog 317 | cmd.Stderr = errLog 318 | return cmd.Run() 319 | } 320 | 321 | func pull() error { 322 | logTime := strconv.FormatInt(time.Now().Unix(), 10) 323 | gitDir := filepath.Join(*configfilesDir, ".git") 324 | fi, err := os.Stat(gitDir) 325 | if err != nil { 326 | return fmt.Errorf("cannot stat %q: %v\n", err) 327 | } 328 | if !*force && time.Since(fi.ModTime()) < 1*time.Hour { 329 | log.Printf("%q was modified within the last hour, skipping update\n", gitDir) 330 | return nil 331 | } 332 | 333 | // Skip update if the remote git points to the same commit as the local 334 | // repository. 335 | log.Printf("Resolving HEAD of %q\n", *readOnlyGitRemote) 336 | remoteHead, err := gitResolve(*readOnlyGitRemote) 337 | if err != nil { 338 | log.Printf("Skipping this update, as resolving git HEAD failed: %v\n", err) 339 | f, err := os.Create(filepath.Join(*configfilesDir, ".logs", logTime+".skipped")) 340 | if err != nil { 341 | return err 342 | } 343 | return f.Close() 344 | } 345 | 346 | cmd := exec.Command("git", "log", "--format=%H", "--max-count=1") 347 | cmd.Dir = *configfilesDir 348 | out, err := cmd.Output() 349 | if err != nil { 350 | return fmt.Errorf("Could not run git log: %v\n", err) 351 | } 352 | if !*force && strings.TrimSpace(string(out)) == remoteHead { 353 | log.Printf("Already up-to-date (both local and remote are at %s)\n", remoteHead) 354 | return nil 355 | } 356 | 357 | // Lock to guard against multiple updater processes running at the same 358 | // time, potentially stepping on eath other’s toes. 359 | lockPath := filepath.Join(*configfilesDir, "update_lock") 360 | lock, err := lockfile.New(lockPath) 361 | if err != nil { 362 | return err 363 | } 364 | if err := lock.TryLock(); err != nil { 365 | return fmt.Errorf("Could not lock %q: %v", lockPath, err) 366 | } 367 | defer lock.Unlock() 368 | 369 | // Copy configfiles to a temporary working directory (|twd|), so that we 370 | // can update it without overwriting configfiles. 371 | abs, err := filepath.Abs(*configfilesDir) 372 | if err != nil { 373 | return err 374 | } 375 | twd := filepath.Join(filepath.Dir(abs), "."+filepath.Base(abs)+".TMP") 376 | 377 | log.Printf("Cloning configfiles from %q to %q\n", abs, twd) 378 | 379 | if err := os.RemoveAll(twd); err != nil { 380 | return err 381 | } 382 | if err := os.MkdirAll(filepath.Dir(abs), 0755); err != nil { 383 | return err 384 | } 385 | 386 | if err := copyGitTracked(abs, twd); err != nil { 387 | return err 388 | } 389 | if err := copyAll(filepath.Join(abs, ".git"), filepath.Join(twd, ".git")); err != nil { 390 | return err 391 | } 392 | 393 | if err := os.MkdirAll(filepath.Join(*configfilesDir, ".logs"), 0755); err != nil { 394 | return err 395 | } 396 | 397 | errLogPath := filepath.Join(*configfilesDir, ".logs", logTime+".failure") 398 | errLog, err := os.Create(errLogPath) 399 | if err != nil { 400 | return err 401 | } 402 | defer errLog.Close() 403 | 404 | log.Printf("Pulling new changes via git\n") 405 | 406 | if err := pullStashed(twd, errLog); err != nil { 407 | return err 408 | } 409 | 410 | log.Printf("Moving new files to %q\n", *configfilesDir) 411 | 412 | if err := moveGitFiles(twd, *configfilesDir, errLog); err != nil { 413 | return err 414 | } 415 | 416 | successLogPath := errLogPath[:len(errLogPath)-len(".failure")] + ".success" 417 | if err := os.Rename(errLogPath, successLogPath); err != nil { 418 | return err 419 | } 420 | 421 | log.Printf("Update done successfully\n") 422 | 423 | if err := copyAll(filepath.Join(twd, ".git"), filepath.Join(*configfilesDir, ".git")); err != nil { 424 | return err 425 | } 426 | 427 | return judgeErrors() 428 | } 429 | 430 | func main() { 431 | flag.Parse() 432 | 433 | if *quiet { 434 | os.Stderr.Close() 435 | } 436 | 437 | if *daemonMode { 438 | daemon() 439 | } 440 | 441 | if err := pull(); err != nil { 442 | log.Fatal(err) 443 | } 444 | } 445 | -------------------------------------------------------------------------------- /gpg.conf: -------------------------------------------------------------------------------- 1 | # If you have more than 1 secret key in your keyring, you may want to 2 | # uncomment the following option and set your preferred keyid. 3 | 4 | default-key 4AC8EE1D 5 | 6 | # If you do not pass a recipient to gpg, it will ask for one. Using 7 | # this option you can encrypt to a default key. Key validation will 8 | # not be done in this case. The second form uses the default key as 9 | # default recipient. 10 | 11 | #default-recipient some-user-id 12 | #default-recipient-self 13 | 14 | # By default GnuPG creates version 3 signatures for data files. This 15 | # is not strictly OpenPGP compliant but PGP 6 and most versions of PGP 16 | # 7 require them. To disable this behavior, you may use this option 17 | # or --openpgp. 18 | 19 | #no-force-v3-sigs 20 | 21 | # Because some mailers change lines starting with "From " to ">From " 22 | # it is good to handle such lines in a special way when creating 23 | # cleartext signatures; all other PGP versions do it this way too. 24 | # To enable full OpenPGP compliance you may want to use this option. 25 | 26 | #no-escape-from-lines 27 | 28 | charset utf-8 29 | 30 | #keyserver hkp://wwwkeys.de.pgp.net 31 | #keyserver pool.sks-keyservers.net 32 | keyserver-options auto-key-retrieve 33 | use-agent 34 | 35 | # Use stronger cryptographic hash algorithms than SHA-1 for signing 36 | personal-digest-preferences SHA512 37 | cert-digest-algo SHA512 38 | default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed 39 | -------------------------------------------------------------------------------- /initialize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # © 2009 Michael Stapelberg, Public Domain 4 | # 5 | # Creates links for the configuration files in this directory, 6 | # also linking host-specific stuff without the host-prefix itself 7 | # (x200/foo -> .foo) if available. 8 | # 9 | # If a configuration file does not follow the scheme of just being 10 | # named .foorc you can specify custom mappings in the file MAPPINGS. 11 | # For mplayer, the line would look like this: 12 | # mplayer.config ~/.mplayer/config 13 | # Which means that the file called mplayer.config would be put 14 | # into ~/.mplayer/config and ~/.mplayer would be created if necessary 15 | 16 | # Get the directory this script lives in 17 | dir="$(cd "${0%/*}" && pwd -P)" 18 | 19 | link_dir() { 20 | for path in $(find $dir/$1 -maxdepth 1 -type f \ 21 | ! -regex ".*\(Makefile\|MAPPING\|initialize.sh\|update.sh\)") 22 | do 23 | file=$(basename $path) 24 | # Check if we got a custom mapping 25 | DEST=$(grep "^$file " $dir/MAPPING | cut -d ' ' -f 2-) 26 | if [ -z "$DEST" ] 27 | then 28 | # Standard location: ~/.filename 29 | DEST="$HOME/.$file" 30 | else 31 | # replace ~ with $HOME 32 | DEST=${DEST/\~/$HOME} 33 | # Ensure the target directory exists 34 | mkdir -p "$(dirname "$DEST")" 35 | fi 36 | 37 | # Preserve the file, if it already exists 38 | [[ -e "$DEST" && ! -L "$DEST" ]] && { 39 | if [ ! -d "$HOME/.configfiles.bak" ] 40 | then 41 | mkdir -p "$HOME/.configfiles.bak" || exit 1 42 | fi 43 | mv "$DEST" "$HOME/.configfiles.bak/" 44 | } 45 | 46 | # Skip the file, if it is already a link 47 | [[ -e "$DEST" && -L "$DEST" ]] && continue 48 | 49 | # Create the symlink 50 | echo "Linking $DEST" 51 | ln -s "$dir/$1/$file" "$DEST" 52 | done 53 | } 54 | 55 | [ -d "$(hostname)" ] && link_dir "$(hostname)" 56 | link_dir 57 | -------------------------------------------------------------------------------- /lintianrc: -------------------------------------------------------------------------------- 1 | display-info = yes 2 | display-experimental = yes 3 | pedantic = yes 4 | show-overrides = no 5 | color = auto 6 | -------------------------------------------------------------------------------- /midna/Xmodmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stapelberg/configfiles/95def678d9119b99a7d478863b6b113114a6aea4/midna/Xmodmap -------------------------------------------------------------------------------- /mplayer.config: -------------------------------------------------------------------------------- 1 | # MPlayer-configuration (~/.mplayer/config) 2 | noborder="1" 3 | nojoystick="1" 4 | # Enable zoommode when using mplayer without GUI 5 | zoom="1" 6 | ao=pulse 7 | nolirc="1" 8 | vo="gl" 9 | softvol="1" 10 | softvol-max="800" 11 | -------------------------------------------------------------------------------- /poc-template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * vim:ts=4:sw=4:expandtab 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | } 13 | -------------------------------------------------------------------------------- /poc-template.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "os" 7 | ) 8 | 9 | func logic() error { 10 | os.Open() 11 | } 12 | 13 | func main() { 14 | flag.Parse() 15 | if err := logic(); err != nil { 16 | log.Fatal(err) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /poc-template.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # vim:ts=4:sw=4:expandtab 3 | 4 | use strict; 5 | use warnings; 6 | use Data::Dumper; 7 | use AnyEvent; 8 | use v5.10; 9 | 10 | -------------------------------------------------------------------------------- /screen-logs-session.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | tmp=$(mktemp) 4 | cat ~/.screenrc > "${tmp}" 5 | cat >> "${tmp}" <<'EOT' 6 | screen -t 'midna syslog' /home/michael/configfiles/screenrc-syslog.zsh 7 | screen -t 'all mqtt' /home/michael/configfiles/screenrc-mqtt.zsh 8 | screen -t 'router7 serial' /home/michael/configfiles/screenrc-router7-serial.zsh 9 | EOT 10 | screen -c "${tmp}" 11 | rm "${tmp}" 12 | -------------------------------------------------------------------------------- /screenrc: -------------------------------------------------------------------------------- 1 | startup_message off 2 | vbell_msg "!" 3 | vbell off 4 | autodetach on 5 | activity "activity in %n (%t) [%w:%s]~" 6 | msgwait 10 7 | bindkey -d -k kD stuff "\177" 8 | 9 | # Titel korrekt durchreichen 10 | termcapinfo xterm-color OP 11 | termcapinfo xterm-color ti@:te@ 12 | termcapinfo xterm-color hs:ts=\E]0;:fs=\007:ds=\E]0;\007 13 | 14 | # Anstelle von hardstatus caption benutzen, damit das mit dem Titel klappt 15 | defhstatus "screen " 16 | hardstatus off 17 | caption always "%{Yb}%-w%{} %{kr} %n %f %{-} %+w %=%H %{kg} %l %{-} %Y-%m-%d %c:%s" 18 | 19 | # Allowing scrolling back up to 25k lines. The default is 100. 20 | scrollback 25000 21 | -------------------------------------------------------------------------------- /screenrc-mqtt.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | print -rn -- $'\e'"]2;all mqtt"$'\a' 4 | mosquitto_sub --id 'midna_all' --verbose -h dr -t "#" 5 | -------------------------------------------------------------------------------- /screenrc-router7-serial.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | print -rn -- $'\e'"]2;router7 serial"$'\a' 4 | journalctl --user -f -u router7-serial -n 500 --all 5 | -------------------------------------------------------------------------------- /screenrc-syslog.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | print -rn -- $'\e'"]2;midna syslog"$'\a' 4 | journalctl -t kernel -f -n 500 | grep -v audit 5 | -------------------------------------------------------------------------------- /tex-template-slides.tex: -------------------------------------------------------------------------------- 1 | % vim:ts=4:sw=4:expandtab 2 | % © 2011-2012 Michael Stapelberg 3 | % 4 | % use lualatex %< 5 | % 6 | \documentclass[usepdftitle=false,compress]{beamer} 7 | \usepackage{fontspec} 8 | \usepackage{listings} 9 | \setmainfont{Trebuchet MS} 10 | \setmonofont[SmallCapsFont={DejaVu Sans Mono}]{DejaVu Sans Mono} 11 | \usetheme{default} 12 | 13 | \hypersetup{pdfencoding=auto,% 14 | pdfinfo={% 15 | Title={Scaling Apache/PHP/PostgreSQL},% 16 | Subject={Slides of my presentation at NoName e.V.},% 17 | Keywords={ccchd,NoName,Apache,PHP,PostgreSQL,nginx,scaling,web},% 18 | Author={Michael Stapelberg},% 19 | CreationDate={20120816200000+02},% 20 | }} 21 | 22 | % white-ish on black-ish 23 | \definecolor{myblack}{rgb}{0.08,0.08,0.08} 24 | \definecolor{mywhite}{rgb}{0.85,0.85,0.85} 25 | 26 | \setbeamertemplate{frametitle}{ 27 | \color{mywhite} 28 | \vspace*{0.5cm} 29 | \hspace*{0.25cm} 30 | \textbf{\insertframetitle} 31 | \par 32 | } 33 | 34 | \setbeamercolor{background canvas}{bg=myblack} 35 | \setbeamercolor{normal text}{fg=mywhite} 36 | 37 | % Hide the navigation icons at the bottom of the page 38 | \setbeamertemplate{navigation symbols}{} 39 | % Slide numbers at the bottom of the page 40 | \setbeamerfont{footline}{size=\fontsize{9}{11}\selectfont} 41 | \setbeamertemplate{footline}[frame number] 42 | 43 | \begin{document} 44 | 45 | % slide with bullet points 46 | \newcommand{\mslide}[2]{ 47 | \begin{frame}{#1} 48 | \begin{list}{$\bullet$}{\itemsep=1em} 49 | #2 50 | \end{list} 51 | \end{frame} 52 | } 53 | 54 | \frame{ 55 | \begin{center} 56 | \vspace{1.5cm} 57 | {\huge systemd}\\ 58 | {\large ein init-replacement}\\ 59 | \vspace{2cm} 60 | c¼h von sECuRE\\ 61 | \vspace{0.5cm} 62 | NoName e.V., 2011-08-18\\ 63 | \vspace{0.5cm} 64 | powered by \LaTeX 65 | \end{center} 66 | } 67 | 68 | \begin{frame}{} 69 | \begin{center} 70 | {\Huge Teil 1: Was ist init?} 71 | \end{center} 72 | \end{frame} 73 | 74 | \mslide{init}{ 75 | \item PID 1, vom Kernel gestartet 76 | \item startet daemons, inklusive X11 bzw. xdm 77 | \item adoptiert elternlose Prozesse (fork),\\ 78 | startet sie ggf. neu (z.B. getty) 79 | } 80 | 81 | \begin{frame}[fragile]{SysV init Beispiel: /etc/init.d/thinkfan (1/9)} 82 | \begin{verbatim} 83 | #! /bin/sh 84 | ### BEGIN INIT INFO 85 | # Provides: thinkfan 86 | # Required-Start: $remote_fs 87 | # Required-Stop: $remote_fs 88 | # Default-Start: 2 3 4 5 89 | # Default-Stop: 0 1 6 90 | # Short-Description: thinkfan initscript 91 | # Description: starts thinkfan if enabled in /etc/default/thinkfan 92 | ### END INIT INFO 93 | 94 | # Author: Evgeni Golov 95 | 96 | # Do NOT "set -e" 97 | \end{verbatim} 98 | \end{frame} 99 | 100 | \begin{frame}[fragile]{systemd-analyze} 101 | \begin{figure} 102 | \includegraphics[width=0.5\textwidth]{plot.pdf} 103 | \caption{\texttt{systemd-analyze plot > plot.svg}} 104 | \end{figure} 105 | \end{frame} 106 | 107 | \end{document} 108 | -------------------------------------------------------------------------------- /tmux.conf: -------------------------------------------------------------------------------- 1 | # Make key bindings more familiar to GNU screen 2 | set-option -g prefix C-a 3 | bind-key a send-prefix 4 | bind-key Space next-window 5 | bind-key BSpace previous-window 6 | bind-key k confirm-before kill-window 7 | 8 | set -g history-limit 20000 9 | 10 | # Style the status line at the bottom of the screen 11 | set-window-option -g window-status-current-style "bg=red,fg=black" 12 | set-window-option -g window-status-current-bg red 13 | set-window-option -g window-status-current-fg black 14 | set-window-option -g window-status-format " #I " 15 | set-window-option -g window-status-current-format " #I " 16 | set -g status-bg blue 17 | set -g status-fg yellow 18 | set -g status-right "#[bg=green,fg=black] #H #[default] %Y-%m-%d %H:%M:%S" 19 | set -g status-interval 1 20 | 21 | set -g set-titles on 22 | set -g set-titles-string "#T" 23 | -------------------------------------------------------------------------------- /travis/Dockerfile: -------------------------------------------------------------------------------- 1 | # vim:ft=Dockerfile 2 | FROM debian:sid 3 | 4 | RUN echo force-unsafe-io > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup 5 | # Paper over occasional network flakiness of some mirrors. 6 | RUN echo 'APT::Acquire::Retries "5";' > /etc/apt/apt.conf.d/80retry 7 | 8 | # NOTE: I tried exclusively using gce_debian_mirror.storage.googleapis.com 9 | # instead of httpredir.debian.org, but the results (Fetched 123 MB in 36s (3357 10 | # kB/s)) are not any better than httpredir.debian.org (Fetched 123 MB in 34s 11 | # (3608 kB/s)). Hence, let’s stick with httpredir.debian.org (default) for now. 12 | 13 | RUN apt-get update && \ 14 | DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ 15 | emacs ca-certificates git && \ 16 | rm -rf /var/lib/apt/lists/* 17 | 18 | WORKDIR /root/configfiles 19 | -------------------------------------------------------------------------------- /travis/emacs-starts-up.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eux 4 | 5 | wd=$PWD 6 | ln -sf $HOME/configfiles/config/emacs .emacs.d 7 | git config --global --add safe.directory /root/configfiles/.git 8 | git clone /root/configfiles configfiles.clone 9 | cd configfiles.clone 10 | # Explicitly load init.el because --batch implies -q. 11 | # Run magit-status, which triggers more delayed package 12 | # installation. 13 | emacs \ 14 | --debug-init \ 15 | --batch \ 16 | --eval="(load-file \"$wd/.emacs.d/init.el\")" \ 17 | --eval="(magit-status)" \ 18 | --kill 19 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/zsh 2 | # vim:ts=4:sw=4:expandtab 3 | # 4 | # © 2011-2013 Michael Stapelberg, Public Domain 5 | 6 | cfgfiles=$(dirname $(readlink ~/.zshrc)) 7 | 8 | fail_update() { 9 | echo "$1" >&2 10 | # If this file exists, there is a nagging warning in the zsh prompt. 11 | touch "$cfgfiles/ERROR" 12 | exit 1 13 | } 14 | 15 | # Ensure only one instance of this script is running (mkdir is atomic). 16 | if ! mkdir "$cfgfiles/update_lock" 2>/dev/null; then 17 | # Two things could’ve happened: 18 | # 1) Another instance of the script is running. 19 | # 2) $cfgfiles is not writable (e.g. a user ran initialize.sh from another 20 | # user’s checkout, or the filesystem is read-only). 21 | # To catch the second case, we try to create a temporary directory. 22 | tempdir=$(mktemp -d --tmpdir="$cfgfiles" 2>/dev/null) 23 | [[ $? -ne 0 ]] && fail_update "$cfgfiles is not writable" 24 | rm -r "$tempdir" 25 | 26 | # By now, case 2 is handled, so another instance of the script must be 27 | # running. 28 | exit 0 29 | fi 30 | 31 | echo "NOTE: updating git for $cfgfiles" 32 | 33 | update_git() { 34 | # Cleanup the lock on exit/signal 35 | trap 'rm -rf "$cfgfiles/update_lock"' 0 36 | 37 | # use e.g. ~/.configfiles.TMP as temporary copy to perform the update in 38 | new_location=$(dirname "$cfgfiles")/.$(basename "$cfgfiles").TMP 39 | [ -d "$new_location" ] && fail_update "new_location $new_location already exists" 40 | mkdir "$new_location" || fail_update "new_location $new_location could not be created" 41 | 42 | # Copy all the files from the current directory to the new location 43 | (cd "$cfgfiles" >/dev/null && tar cp .) | tar x --directory "$new_location" 44 | 45 | ( 46 | cd "$new_location" >/dev/null 47 | 48 | git config gc.auto 0 || fail_update "could not disable auto gc" 49 | 50 | echo "--- git stash ---" 51 | git stash || fail_update "could not “git stash” the current changes" 52 | 53 | echo "--- git pull ---" 54 | if git remote | grep -q readonly 55 | then 56 | git pull --ff-only readonly master || fail_update "new changes could not be applied" 57 | else 58 | git pull --ff-only || fail_update "new changes could not be applied" 59 | fi 60 | 61 | if [[ $(git stash list | wc -l) -ne 0 ]]; then 62 | echo "--- git stash pop ---" 63 | git stash pop || fail_update "could not pop old changes with “git stash pop”" 64 | fi 65 | ) >$cfgfiles/last-update.log 2>&1 66 | 67 | # Move files from the updated copy to the original folder. 68 | IFS=$'\n' 69 | for file in $(cd "$new_location" >/dev/null && git ls-files); do 70 | mv "$new_location/$file" "$cfgfiles/$file" || fail_update "could not move “$file”" 71 | done 72 | 73 | # Copy .git to the original folder 74 | (cd "$new_location" >/dev/null && tar cp .git) | tar x --directory "$cfgfiles" 75 | 76 | rm -rf "$new_location" 77 | } 78 | 79 | update_git & 80 | -------------------------------------------------------------------------------- /urxvt-fonts: -------------------------------------------------------------------------------- 1 | =begin void 2 | 3 | Author: Maik Fischer 4 | 5 | preliminary instructions: 6 | 7 | 1) save/symlink this file to eg. ~/.urxvt/fonts 8 | 2) cat >> Xdefaults << END 9 | 10 | URxvt.fonts.0: -misc-fixed-medium-r-normal--10-100-75-75-c-60-iso10646-1 11 | URxvt.fonts.1: -misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1 12 | URxvt.fonts.2: -misc-fixed-medium-r-normal--14-130-75-75-c-70-iso10646-1 13 | URxvt.fonts.3: -xos4-terminus-medium-r-normal--24-240-72-72-c-120-iso10646-1 14 | ! and so on... 15 | URxvt.keysym.M-9: perl:fonts:plus 16 | URxvt.keysym.M-0: perl:fonts:minus 17 | URxvt.perl-lib: /home/foo/.urxvt 18 | URxvt.perl-ext: fonts 19 | 20 | END 21 | 22 | Note: either set URxvt.fonts.0 or URxvt.font, the former overrides the latter 23 | 24 | =end void 25 | 26 | =cut 27 | 28 | sub on_start { 29 | my $self = shift; 30 | 31 | $self->{fonts_idx} = 0; 32 | my @fonts; 33 | my @default = $self->resource('font'); 34 | for (my $i = 0; 35 | defined(my $font = $self->x_resource("fonts.$i") || $default[$i]); 36 | $i++) 37 | { 38 | push @fonts, $font; 39 | } 40 | $self->set_font($fonts[0]); 41 | $self->{fonts} = [ @fonts ]; 42 | undef @fonts; 43 | return () 44 | } 45 | 46 | sub on_user_command { 47 | my ($self, $cmd) = @_; 48 | return () unless $cmd =~ /^fonts:(plus|minus)/; 49 | 50 | my @fonts = @{ $self->{fonts} }; 51 | for ($self->{fonts_idx}) { 52 | $_ = $1 eq 'plus'? ($_ + 1) % @fonts: 53 | $1 eq 'minus'? ($_ - 1) % @fonts: 54 | (); 55 | 56 | $self->set_font( $fonts[ $_ ] ); 57 | } 58 | 59 | return (); 60 | } 61 | 62 | sub set_font { 63 | my ($self, $font) = @_; 64 | $self->cmd_parse("\033]710;$font\007"); # yuck! 65 | } 66 | 67 | # vim: set ts=4 sts=4 ft=perl expandtab: 68 | -------------------------------------------------------------------------------- /urxvt-for-emacs: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | exec /usr/bin/urxvtc -keysym.C-grave string:\*b -keysym.S-C-grave string:\*c -keysym.C-M-grave string:\*f -keysym.S-C-M-grave string:\*g -keysym.C-1 string:+B -keysym.S-C-1 string:+C -keysym.C-M-1 string:+F -keysym.S-C-M-1 string:+G -keysym.C-2 string:,\" -keysym.S-C-2 string:,# -keysym.C-M-2 string:,\& -keysym.S-C-M-2 string:,\' -keysym.C-3 string:,b -keysym.S-C-3 string:,c -keysym.C-M-3 string:,f -keysym.S-C-M-3 string:,g -keysym.C-4 string:-B -keysym.S-C-4 string:-C -keysym.C-M-4 string:-F -keysym.S-C-M-4 string:-G -keysym.C-5 string:.\" -keysym.S-C-5 string:.# -keysym.C-M-5 string:.\& -keysym.S-C-M-5 string:.\' -keysym.C-6 string:.b -keysym.S-C-6 string:.c -keysym.C-M-6 string:.f -keysym.S-C-M-6 string:.g -keysym.C-7 string:/B -keysym.S-C-7 string:/C -keysym.C-M-7 string:/F -keysym.S-C-M-7 string:/G -keysym.C-8 string:0\" -keysym.S-C-8 string:0# -keysym.C-M-8 string:0\& -keysym.S-C-M-8 string:0\' -keysym.C-9 string:0b -keysym.S-C-9 string:0c -keysym.C-M-9 string:0f -keysym.S-C-M-9 string:0g -keysym.C-0 string:1B -keysym.S-C-0 string:1C -keysym.C-M-0 string:1F -keysym.S-C-M-0 string:1G -keysym.C-minus string:2\" -keysym.S-C-minus string:2# -keysym.C-M-minus string:2\& -keysym.S-C-M-minus string:2\' -keysym.C-equal string:2b -keysym.S-C-equal string:2c -keysym.C-M-equal string:2f -keysym.S-C-M-equal string:2g -keysym.S-BackSpace string:3A -keysym.C-BackSpace string:3B -keysym.S-C-BackSpace string:3C -keysym.S-M-BackSpace string:3E -keysym.C-M-BackSpace string:3F -keysym.S-C-M-BackSpace string:3G -keysym.C-Tab string:4\" -keysym.S-C-Tab string:4# -keysym.C-M-Tab string:4\& -keysym.S-C-M-Tab string:4\' -keysym.C-Q string:4c -keysym.C-M-Q string:4g -keysym.C-W string:5C -keysym.C-M-W string:5G -keysym.C-E string:6# -keysym.C-M-E string:6\' -keysym.C-R string:6c -keysym.C-M-R string:6g -keysym.C-T string:7C -keysym.C-M-T string:7G -keysym.C-Y string:8# -keysym.C-M-Y string:8\' -keysym.C-U string:8c -keysym.C-M-U string:8g -keysym.C-I string:9C -keysym.C-M-I string:9G -keysym.C-O string::# -keysym.C-M-O string::\' -keysym.C-P string::c -keysym.C-M-P string::g -keysym.C-bracketleft string:\;B -keysym.S-C-bracketleft string:\;C -keysym.C-M-bracketleft string:\;F -keysym.S-C-M-bracketleft string:\;G -keysym.C-bracketright string:\<\" -keysym.S-C-bracketright string:\<# -keysym.C-M-bracketright string:\<\& -keysym.S-C-M-bracketright string:\<\' -keysym.S-Return string:\# -keysym.C-M-A string:\>\' -keysym.C-S string:\>c -keysym.C-M-S string:\>g -keysym.C-D string:\?C -keysym.C-M-D string:\?G -keysym.C-F string:@# -keysym.C-M-F string:@\' -keysym.C-G string:@c -keysym.C-M-g string:@f -keysym.C-M-G string:@g -keysym.C-H string:AC -keysym.C-M-H string:AG -keysym.C-J string:B# -keysym.C-M-J string:B\' -keysym.C-K string:Bc -keysym.C-M-K string:Bg -keysym.C-L string:CC -keysym.C-M-L string:CG -keysym.C-semicolon string:D\" -keysym.S-C-semicolon string:D# -keysym.C-M-semicolon string:D\& -keysym.S-C-M-semicolon string:D\' -keysym.C-apostrophe string:Db -keysym.S-C-apostrophe string:Dc -keysym.C-M-apostrophe string:Df -keysym.S-C-M-apostrophe string:Dg -keysym.C-backslash string:F\" -keysym.S-C-backslash string:F# -keysym.C-M-backslash string:F\& -keysym.S-C-M-backslash string:F\' -keysym.C-Z string:Fc -keysym.C-M-Z string:Fg -keysym.C-X string:GC -keysym.C-M-X string:GG -keysym.C-C string:H# -keysym.C-M-C string:H\' -keysym.C-V string:Hc -keysym.C-M-V string:Hg -keysym.C-B string:IC -keysym.C-M-B string:IG -keysym.C-N string:J# -keysym.C-M-N string:J\' -keysym.C-M string:Jc -keysym.C-M-M string:Jg -keysym.C-comma string:KB -keysym.S-C-comma string:KC -keysym.C-M-comma string:KF -keysym.S-C-M-comma string:KG -keysym.C-period string:L\" -keysym.S-C-period string:L# -keysym.C-M-period string:L\& -keysym.S-C-M-period string:L\' -keysym.C-slash string:Lb -keysym.S-C-slash string:Lc -keysym.C-M-slash string:Lf -keysym.S-C-M-slash string:Lg -keysym.C-space string:P\" -keysym.S-C-space string:P# -keysym.C-M-space string:P\& -keysym.S-C-M-space string:P\' -keysym.Menu 'string:R ' -keysym.S-Menu string:R\! -keysym.C-Menu string:R\" -keysym.S-C-Menu string:R# -keysym.M-Menu string:R\$ -keysym.S-M-Menu string:R% -keysym.C-M-Menu string:R\& -keysym.S-C-M-Menu string:R\' -keysym.S-C-Up string:SC -keysym.M-Up string:SD -keysym.S-M-Up string:SE -keysym.C-M-Up string:SF -keysym.S-C-M-Up string:SG -keysym.S-C-Down string:T# -keysym.M-Down string:T\$ -keysym.S-M-Down string:T% -keysym.C-M-Down string:T\& -keysym.S-C-M-Down string:T\' -keysym.S-C-Left string:Tc -keysym.M-Left string:Td -keysym.S-M-Left string:Te -keysym.C-M-Left string:Tf -keysym.S-C-M-Left string:Tg -keysym.S-C-Right string:UC -keysym.M-Right string:UD -keysym.S-M-Right string:UE -keysym.C-M-Right string:UF -keysym.S-C-M-Right string:UG -keysym.S-C-Home string:WC -keysym.M-Home string:WD -keysym.S-M-Home string:WE -keysym.C-M-Home string:WF -keysym.S-C-M-Home string:WG -keysym.S-C-End string:X# -keysym.M-End string:X\$ -keysym.S-M-End string:X% -keysym.C-M-End string:X\& -keysym.S-C-M-End string:X\' -keysym.S-Prior string:Xa -keysym.S-C-Prior string:Xc -keysym.M-Prior string:Xd -keysym.S-M-Prior string:Xe -keysym.C-M-Prior string:Xf -keysym.S-C-M-Prior string:Xg -keysym.S-Next string:YA -keysym.S-C-Next string:YC -keysym.M-Next string:YD -keysym.S-M-Next string:YE -keysym.C-M-Next string:YF -keysym.S-C-M-Next string:YG 3 | -------------------------------------------------------------------------------- /urxvt-mark-yank-urls: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | # ---------------------------------------- 4 | 5 | # same url as used in "selection" 6 | my $url_matcher = 7 | qr{( 8 | (?:https?://|ftp://|news://|mailto:|file://)[ab-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27(),~#]+ 9 | [ab-zA-Z0-9\-\@;\/?:&=%\$_+!*\x27()~] # exclude some trailing characters (heuristic) 10 | )}x; 11 | 12 | sub on_start { 13 | my ($term) = @_; 14 | 15 | $term->{have_Clipboard} = eval { require Clipboard; }; 16 | if ($term->{have_Clipboard}) { 17 | import Clipboard; 18 | } 19 | 20 | $term->{browser} = $term->x_resource ("urlLauncher") || "x-www-browser"; 21 | 22 | () 23 | } 24 | 25 | sub on_line_update { 26 | my ($term, $row) = @_; 27 | 28 | # fetch the line that has changed 29 | my $line = $term->line ($row); 30 | my $text = $line->t; 31 | 32 | # find all urls (if any) 33 | while ($text =~ /$url_matcher/g) { 34 | my $rend = $line->r; 35 | 36 | # mark all characters as underlined. we _must_ not toggle underline, 37 | # as we might get called on an already-marked url. 38 | if ($term->x_resource ("underlineURLs") eq "true") { 39 | $_ |= urxvt::RS_Uline 40 | for @{$rend}[ $-[1] .. $+[1] - 1]; 41 | 42 | $line->r ($rend); 43 | } 44 | } 45 | 46 | () 47 | } 48 | 49 | 50 | #sub on_scroll_back { 51 | # my ($term, $lines, $saved) = @_; 52 | # 53 | # if ($lines > $url_selected && $url_selected>0) { 54 | # move_highlight ($term, 1); 55 | # } 56 | # 57 | # for (my $n=0; $n<$lines; $n++) { 58 | # shift @url_db 59 | # } 60 | # 61 | # () 62 | #} 63 | 64 | # ---------------------------------------- 65 | 66 | my $mark_mode_active = 0; 67 | my %mod = ( 'control' => 0, 'shift' => 0 ); 68 | my $url_selected = -1; 69 | my @url_db = (); 70 | 71 | # ---------------------------------------- 72 | 73 | sub do_scan_for_urls { 74 | my ($term) = @_; 75 | 76 | @url_db = (); 77 | 78 | my $row_start = $term->top_row; 79 | my $row_end = $term->nrow; 80 | 81 | for (my $row=$row_start; $row<=$row_end; $row++) { 82 | 83 | # fetch the line that has changed 84 | my $line = $term->line ($row); 85 | my $text = $line->t; 86 | 87 | # find all urls (if any) 88 | while ($text =~ /$url_matcher/g) { 89 | my $rend = $line->r; 90 | my $url = $1; 91 | 92 | my %h = ( 'row' => $row, 93 | 'col_from' => $-[1], 94 | 'col_to' => $+[1] - 1, 95 | 'url' => $url); 96 | push @url_db, \%h; 97 | } 98 | } 99 | 100 | # 0 for none, positive count otherwise 101 | return $#url_db + 1; 102 | } 103 | 104 | sub on_user_command { 105 | my ($term, $cmd) = @_; 106 | 107 | $cmd eq "mark-yank-urls:activate_mark_mode" 108 | and activate_mark_mode($term); 109 | 110 | () 111 | } 112 | 113 | sub on_key_press { 114 | my ($term, $event, $keysym, $octets) = @_; 115 | 116 | ($keysym == 65507) && { $mod{control} = 1 }; 117 | ($keysym == 65505) && { $mod{shift} = 1 }; 118 | 119 | # ignore all input when we are active 120 | $mark_mode_active && return 1; 121 | 122 | () 123 | } 124 | 125 | sub on_key_release { 126 | my ($term, $event, $keysym, $octets) = @_; 127 | 128 | if ($mark_mode_active) { 129 | my $ch = chr($keysym); 130 | 131 | if ($keysym == 65307) { # 132 | deactivate_mark_mode ($term); 133 | return 1; 134 | 135 | } elsif ($keysym == 65293) { # 136 | my $url = get_active_url($term); 137 | $url =~ s/\(["|><&()]\)/\\$1/; 138 | $term->exec_async ($term->{browser}, $url); 139 | deactivate_mark_mode ($term); 140 | return 1; 141 | 142 | } elsif ($keysym == 65507) { # 143 | $mod{control} = 0; 144 | return 1; 145 | 146 | } elsif ($keysym == 65505) { # 147 | $mod{shift} = 0; 148 | return 1; 149 | 150 | } elsif ($mod{control} && (($ch eq 'n') || ($ch eq 'p'))) { 151 | # ^n and ^p to cycle list 152 | my $dir = ($ch eq 'n') ? 1 : -1; 153 | move_highlight ($term, $dir); 154 | 155 | } elsif ($ch eq 'y') { # y 156 | do_copy ($term); 157 | deactivate_mark_mode ($term); 158 | return 1; 159 | 160 | } 161 | 162 | return 1; 163 | } 164 | 165 | () 166 | } 167 | 168 | sub get_active_url { 169 | my ($term) = @_; 170 | my $max = $#url_db + 1; 171 | 172 | return if $url_selected < 0 || $url_selected >= $max; 173 | return if not defined $url_db[$url_selected]; 174 | my $o = $url_db[$url_selected]; 175 | my %h = %$o; 176 | 177 | return $h{url}; 178 | } 179 | 180 | sub do_copy { 181 | my ($term) = @_; 182 | 183 | my $text = get_active_url ($term); 184 | 185 | if ($term->{have_Clipboard}) { 186 | Clipboard->copy($text); 187 | } else { 188 | $text =~ s/\(["|><&()]\)/\\$1/; 189 | system ("echo -n \"$text\" | xclip -i"); 190 | } 191 | } 192 | 193 | sub move_highlight { 194 | my ($term, $dir) = @_; 195 | my $max = $#url_db + 1; 196 | 197 | do_highlight ($term, 0); 198 | 199 | $url_selected = ($max + $url_selected + $dir) % $max; 200 | 201 | do_highlight ($term, 1); 202 | 203 | $term->want_refresh; 204 | } 205 | 206 | sub do_highlight { 207 | my ($term, $enable) = @_; 208 | my $max = $#url_db + 1; 209 | 210 | return if $url_selected < 0 || $url_selected >= $max; 211 | return if not defined $url_db[$url_selected]; 212 | 213 | my $o = $url_db[$url_selected]; 214 | my %h = %$o; 215 | 216 | my $row = $h{row}; 217 | my $line = $term->line ($row); 218 | my $text = $line->t; 219 | my $rend = $line->r; 220 | 221 | if ($enable) { 222 | $_ |= urxvt::RS_RVid 223 | for @{$rend}[ $h{col_from} .. $h{col_to}]; 224 | 225 | # make it visible 226 | $term->view_start ( $row < 0 ? $row : 0 ); 227 | 228 | } else { 229 | $_ &= ~urxvt::RS_RVid 230 | for @{$rend}[ $h{col_from} .. $h{col_to}]; 231 | } 232 | 233 | $line->r ($rend); 234 | } 235 | 236 | sub activate_mark_mode { 237 | my ($term) = @_; 238 | 239 | if ($mark_mode_active) { 240 | 241 | move_highlight ($term, -1); 242 | 243 | } elsif ( do_scan_for_urls ($term) ) { 244 | 245 | $term->{save_view_start} = $term->view_start; 246 | 247 | move_highlight ($term, 0); 248 | 249 | $mark_mode_active=1 if ($url_selected > -1); 250 | } 251 | } 252 | 253 | sub deactivate_mark_mode { 254 | my ($term) = @_; 255 | 256 | do_highlight ($term, 0); 257 | 258 | $mark_mode_active = 0; 259 | $url_selected = -1; 260 | 261 | $term->view_start ($term->{save_view_start}); 262 | $term->want_refresh; 263 | } 264 | 265 | # vim: set et ts=4 sw=4: 266 | -------------------------------------------------------------------------------- /vimrc: -------------------------------------------------------------------------------- 1 | if v:progname != 'vim' && v:progname != 'nvim' 2 | finish 3 | endif 4 | 5 | " Remove fedora and redhat default vimrc additions. 6 | augroup fedora 7 | autocmd! 8 | augroup END 9 | 10 | augroup redhat 11 | autocmd! 12 | augroup END 13 | 14 | " Restore the last cursor position when opening files. 15 | function! RestoreCursor() 16 | if line("'\"") <= line("$") 17 | normal! g`" 18 | return 1 19 | endif 20 | endfunction 21 | autocmd BufReadPost * call RestoreCursor() 22 | " …except for git commit messages, where that doesn’t make any sense. 23 | autocmd BufReadPost COMMIT_EDITMSG exe "normal! gg" 24 | 25 | " Don’t ensure compatibility with vi at all cost. This needs to be set first 26 | " because it modifies the values of some other options (such as modeline). 27 | set nocompatible 28 | " Enable modelines, even as root 29 | set modeline 30 | " More flexible backspace 31 | set backspace=indent,eol,start 32 | " Dark background 33 | set bg=dark 34 | set hlsearch 35 | " Set the terminals title 36 | set title 37 | " Don’t abbreviate the filename in terminal titles, which is useful for 38 | " time-tracking programs that care about the file path. 39 | set titlelen=0 40 | " Always show a status line 41 | set laststatus=2 42 | " Automatically indent, and do it smart 43 | set autoindent smartindent 44 | " Enhanced mode for command-line completion 45 | set wildmenu 46 | " Enable listing possible completions when completing file names 47 | set wildmode=longest,list:longest,list:full 48 | " Skip binaries when completing 49 | set wildignore=*.o,*.a,*.la,*.lo,*.swp,*.tab.c,*.tab.h,*.yy.c,.svn,.git 50 | " Don’t jump to the matching bracket automatically 51 | set noshowmatch 52 | " Enable ruler 53 | set ruler 54 | " Use UTF-8 55 | set fileencoding=utf-8 56 | " Disable folding completely 57 | set nofen 58 | " Default printer is laserjet 59 | set printdevice=kyocera 60 | " Get rid of the annoying delays (when directory browsing or switching modes). 61 | " Leads to vim being unable to differentiate between bindings such as ,d and 62 | " ,dv – which I don’t use anyway :). 63 | set timeout timeoutlen=1000 ttimeoutlen=100 64 | " We use rxvt-unicode-256color, explicitly tell vim that 65 | set t_Co=256 66 | " Disable mouse support (enabled by default in neovim). 67 | set mouse= 68 | 69 | " Enable syntax highlighting 70 | syntax on 71 | 72 | " Most accurate highlighting, but might be slow: 73 | autocmd BufEnter * :syntax sync fromstart 74 | 75 | " Enable file type-specific indention rules 76 | "filetype indent on 77 | filetype plugin on 78 | 79 | " ECPG-files are C-code, too 80 | autocmd BufNewFile,BufRead *.pgc setf c 81 | autocmd BufNewFile,BufRead *.pmc setf c 82 | " systemd service and socket files are freedesktop files 83 | autocmd BufNewFile,BufRead *.service setf desktop 84 | autocmd BufNewFile,BufRead *.socket setf desktop 85 | " indent settings for ruby 86 | autocmd BufNewFile,BufRead *.rb set ts=2 sw=2 expandtab 87 | autocmd BufNewFile,BufRead *.c,*.h set ts=4 sw=4 noexpandtab 88 | autocmd BufNewFile,BufRead *.sh,*.pl,*.pm,*.rb set cin cinkeys=0{,0},0),:,!^F,o,O,e 89 | 90 | " prolog files also use .pl, but they are only in a certain directory 91 | autocmd BufNewFile,BufRead /home/michael/prolog/*.pl set ft=prolog 92 | 93 | " Go files 94 | let g:go_fmt_command="goimports" 95 | autocmd BufRead,BufNewFile *.go set ts=4 sw=4 noexpandtab makeprg=go\ build 96 | autocmd QuickFixCmdPost [^l]* nested cwindow 97 | autocmd QuickFixCmdPost l* nested lwindow 98 | 99 | " For C-files, enable C-indenting, also set makeprg to disable warnings via 100 | " CFLAGS 101 | autocmd BufNewFile,BufRead *.c,*.y,*.l,*.pgc,*.cc,*.cpp,*.h,*.hh,*.hpp set cin 102 | autocmd BufNewFile,BufRead *.c,*.y,*.l,*.pgc,*.cc,*.cpp,*.h,*.hh,*.hpp set fo-=t fo+=croql comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// 103 | autocmd BufNewFile,BufRead *.c,*.y,*.l,*.pgc,*.cc,*.cpp,*.h,*.hh,*.hpp set makeprg=make\ -j4 104 | 105 | " Enable expandtab, since debian/control files indent with spaces. 106 | autocmd BufNewFile,BufRead debian/control set et 107 | 108 | " Enable filetype plugins (vim-LaTeX for example) 109 | "filetype plugin on 110 | 111 | " View the current tex-document (F4 for pdflatex, F5 for ps-compatible 112 | " dvipdf) 113 | map :!pdflatex % && xpdf %<.pdf 114 | map :!latex % && dvipdf %<.dvi && xpdf %<.pdf 115 | map :!xelatex % && xpdf -fullscreen %<.pdf 116 | 117 | " Just tex it (if you already have an open viewer) 118 | command! T write!xelatex % 119 | 120 | " When opening .tex-files, don’t treat them as plaintext if there are no LaTeX 121 | " commands inside yet 122 | let g:tex_flavor='latex' 123 | 124 | " is_bash accepts $(..) which is POSIX compliant 125 | let is_bash=1 126 | 127 | if filereadable("./make.sh") 128 | set mp=./make.sh 129 | endif 130 | 131 | " Searches TODO/FIXME in all files (except for hidden ones) in all directories 132 | " (up to 100 levels) and displays them in the quickfix window, see :help quickfix 133 | function! TODO() 134 | :vimgrep /TODO\|FIXME/ **/* 135 | :cwindow 136 | endfunction 137 | 138 | let mapleader = "," 139 | 140 | " _x_ to compile, because it’s on the left hand, while comma (leader) is on 141 | " the right hand. 142 | map x :make 143 | map t :!go test dcs/... 144 | map f :Fmt 145 | map w :Fmt:w 146 | map p "*p 147 | map M :set makeprg=make\ -j4:make 148 | " _r_un a proof-of-concept 149 | map r :!make $(basename % .c) && ./$(basename % .c) 150 | map h :nohlsearch 151 | map n :cn 152 | map a :Ack 153 | 154 | " Make Ctrl-e/y go faster 155 | nnoremap 3 156 | nnoremap 3 157 | 158 | " Make Ctrl-a go to the beginning of the command line 159 | cnoremap 160 | 161 | " Needed for Vroom::Vroom 162 | set exrc 163 | 164 | " see https://github.com/ConradIrwin/vim-bracketed-paste 165 | " enter/leave bracketed paste mode when entering/leaving insert mode 166 | function! WrapForTmux(s) 167 | if !exists('$TMUX') 168 | return a:s 169 | endif 170 | 171 | let tmux_start = "\Ptmux;" 172 | let tmux_end = "\\\" 173 | 174 | return tmux_start . substitute(a:s, "\", "\\", 'g') . tmux_end 175 | endfunction 176 | 177 | function! WrapForScreen(s) 178 | if exists('$TMUX') || match($TERM, "screen")==-1 179 | return a:s 180 | endif 181 | 182 | let screen_start = "\P" 183 | let screen_end = "\\\" 184 | 185 | return screen_start . a:s . screen_end 186 | endfunction 187 | 188 | function! WrapSequenceForMultiplexer(s) 189 | return WrapForTmux(WrapForScreen(a:s)) 190 | endfunction 191 | 192 | let &t_SI .= WrapSequenceForMultiplexer("\[?2004h") 193 | let &t_EI .= WrapSequenceForMultiplexer("\[?2004l") 194 | 195 | " make bracketed paste mode sequences trigger / 196 | execute "set =\[200~" 197 | execute "set =\[201~" 198 | 199 | function! XTermPasteBegin(ret) 200 | set pastetoggle= 201 | set paste 202 | return a:ret 203 | endfunction 204 | 205 | map XTermPasteBegin("i") 206 | imap XTermPasteBegin("") 207 | vmap XTermPasteBegin("c") 208 | cmap 209 | cmap 210 | 211 | let vundle_readme=expand('~/.vim/bundle/Vundle.vim/README.md') 212 | if filereadable(vundle_readme) 213 | filetype off " required 214 | 215 | " set the runtime path to include Vundle and initialize 216 | set rtp+=~/.vim/bundle/Vundle.vim 217 | call vundle#begin() 218 | 219 | " let Vundle manage Vundle, required 220 | Plugin 'gmarik/Vundle.vim' 221 | 222 | Plugin 'fatih/vim-go' 223 | 224 | Plugin 'mileszs/ack.vim' 225 | 226 | Plugin 'luochen1990/rainbow' 227 | 228 | Plugin 'epeli/slimux' 229 | 230 | Plugin 'benekastah/neomake' 231 | 232 | Plugin 'bogado/file-line' 233 | 234 | " All of your Plugins must be added before the following line 235 | call vundle#end() " required 236 | filetype plugin on 237 | 238 | let g:rainbow_active = 1 239 | 240 | map s :SlimuxREPLSendLine 241 | map b :SlimuxREPLSendBuffer 242 | vmap s :SlimuxREPLSendSelection 243 | map a :SlimuxShellLast 244 | map k :SlimuxSendKeysLast 245 | 246 | let g:slimux_select_from_current_window = 1 247 | endif 248 | 249 | if filereadable(expand('~/.vimrc_host')) 250 | source ~/.vimrc_host 251 | endif 252 | -------------------------------------------------------------------------------- /xsession: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Vanilla xdm does not do this by default: 4 | xrdb $HOME/.Xresources 5 | 6 | # Enable zapping (C-A- kills X) 7 | # Using setxkbmap -option terminate:ctrl_alt_bksp binds NoSymbol to Backspace 8 | # on the higher levels so that CapsLock+Backspace (Backspace on Level3) doesn’t 9 | # work with the NEO layout. 10 | xmodmap -e 'keycode 22 = BackSpace BackSpace BackSpace BackSpace BackSpace BackSpace Terminate_Server BackSpace BackSpace Terminate_Server' 11 | 12 | # Run redshift, but don’t fail if it’s not (yet) available 13 | if command -V redshift >/dev/null 2>&1; then 14 | redshift -m randr -l 47.31:8.50 -t 6000:5300 -b 0.8 & 15 | fi 16 | 17 | xrandr --dpi 192̂ 18 | 19 | INPUT_DEVICES=$(xinput list --name-only) 20 | TRACKBALL="Logitech M570" 21 | TRACKPOINT="TPPS/2 IBM TrackPoint" 22 | TRACKPOINT_ELAN="TPPS/2 Elan TrackPoint" 23 | TOUCHPAD="SynPS/2 Synaptics TouchPad" 24 | DELLTOUCHPAD="DLL082A:01 06CB:76AF Touchpad" 25 | 26 | if [[ "$HOST" = "midna.zekjur.net" || "$HOSTNAME" = "midna.zekjur.net" || "$HOSTNAME" = "midna" ]]; then 27 | HOST="midna" 28 | fi 29 | 30 | if [[ "$HOSTNAME" == pacna.* ]] 31 | then 32 | xrandr --output DP-5.8 --auto --right-of DP-5.9 33 | xrandr --setmonitor up2414q auto DP-5.8,DP-5.9 34 | fi 35 | 36 | if [[ "$HOST" = "midna" ]] 37 | then 38 | xrandr --setmonitor up3218k auto DP-4,DP-2 39 | fi 40 | 41 | setxkbmap de -variant neo 42 | 43 | if echo "$INPUT_DEVICES" | grep -qF "$TRACKBALL"; then 44 | xinput set-ptr-feedback "$TRACKBALL" 10 16 15 45 | xinput set-prop "$TRACKBALL" 'Device Accel Profile' 2 46 | xinput set-prop "$TRACKBALL" 'Device Accel Adaptive Deceleration' 1.2 47 | # multiply cursor movement by 2x for hidpi 48 | xinput set-prop "$TRACKBALL" "Device Accel Constant Deceleration" 0.5 49 | fi 50 | 51 | if echo "$INPUT_DEVICES" | grep -qF "$TRACKPOINT"; then 52 | # Enable scrolling on thinkpad 53 | xinput set-prop "$TRACKPOINT" "Evdev Wheel Emulation Button" 2 54 | xinput set-prop "$TRACKPOINT" "Evdev Wheel Emulation Axes" 6 7 4 5 55 | xinput set-prop "$TRACKPOINT" "Evdev Wheel Emulation" 1 56 | fi 57 | 58 | if echo "$INPUT_DEVICES" | grep -qF "$TRACKPOINT_ELAN"; then 59 | xinput set-prop "TPPS/2 Elan TrackPoint" "Evdev Wheel Emulation" 1 60 | xinput set-prop "TPPS/2 Elan TrackPoint" "Evdev Wheel Emulation Button" 2 61 | xinput set-prop "TPPS/2 Elan TrackPoint" "Evdev Wheel Emulation Timeout" 200 62 | xinput set-prop "TPPS/2 Elan TrackPoint" "Evdev Wheel Emulation Axes" 6 7 4 5 63 | fi 64 | 65 | # xps 13 9360 66 | if echo "$INPUT_DEVICES" | grep -qF "SynPS/2 Synaptics TouchPad"; then 67 | synclient TapButton1=1 68 | synclient TapButton2=3 69 | synclient TapButton3=2 70 | synclient VertScrollDelta=-113 71 | synclient HorizScrollDelta=-113 72 | fi 73 | 74 | # ThinkPad X1 Extreme 75 | if echo "$INPUT_DEVICES" | grep -qF "Synaptics TM3512-010"; then 76 | xinput set-prop "Synaptics TM3512-010" "libinput Natural Scrolling Enabled" 1 77 | fi 78 | 79 | if echo "$INPUT_DEVICES" | grep -qF "$DELLTOUCHPAD"; then 80 | synclient TapButton3=2 81 | synclient VertScrollDelta=-27 82 | synclient HorizScrollDelta=-27 83 | else 84 | if echo "$INPUT_DEVICES" | grep -qF "$TOUCHPAD"; then 85 | # Older Xorg setups: 86 | synclient VertScrollDelta=-150 87 | synclient HorizScrollDelta=-150 88 | synclient VertTwoFingerScroll=1 89 | synclient HorizTwoFingerScroll=1 90 | 91 | # libinput-based Xorg setups: 92 | xinput set-prop "$TOUCHPAD" 'libinput Natural Scrolling Enabled' 1 93 | fi 94 | fi 95 | 96 | # needed for toggle_layout 97 | touch /tmp/neo_active 98 | 99 | # Allow local connections from all users, so that when using 'sudo vim' we can 100 | # get access to the X clipboard. 101 | xhost +local: 102 | 103 | # X settings: disable DPMS, disable audible bell 104 | xset -dpms s off -b 105 | 106 | # increase key repeat rate 107 | xset r rate 250 30 108 | 109 | # Set correct locales 110 | unset LC_ALL 111 | export LANG=de_DE.UTF-8 112 | export LC_MESSAGES=C 113 | export LC_TIME=en_DK.UTF-8 114 | 115 | # set PAGER/EDITOR for things not started by a shell 116 | export PAGER=less 117 | export EDITOR=vim 118 | 119 | # # Make Java SWT use GTK3, which has better hidpi support: 120 | # export SWT_GTK3=1 121 | 122 | # Needed for GTK3 programs like Evince, Geeqie, GIMP 3, … to scale correctly: 123 | # 124 | # NOTE: Chrome 131+ scales incorrectly when GDK_SCALE is set: 125 | # https://mas.to/@zekjur/113475631028231867 126 | # …but that needs to be worked around in Chrome, 127 | # e.g. by using --force-device-scale-factor=3 in ~/.config/chrome-flags.conf 128 | export GDK_SCALE=2 129 | export GDK_DPI_SCALE=0.5 130 | # Needed for some Qt programs like Wireshark to scale correctly: 131 | # The default depends on whether the program was updated apparently. 132 | # Most programs I tried behaved as if QT_AUTO_SCREEN_SCALE_FACTOR=1, 133 | # but not Wireshark. 134 | export QT_AUTO_SCREEN_SCALE_FACTOR=1 135 | 136 | # Background color 137 | xsetroot -solid "#333333" -cursor_name left_ptr 138 | 139 | # Start urxvtd 140 | urxvt256c-mld -q -f -o || urxvtd -q -f -o 141 | 142 | #cd /tmp 143 | #rm xsession.log 144 | #export DISPLAY=:0 145 | #xtrace -o xsession.log & 146 | #sleep 1 147 | #export DISPLAY=:9 148 | #cd /home/michael 149 | 150 | # Fedora’s Xsession ends up in /, not in $HOME 151 | cd $HOME 152 | 153 | # Remove comment to prefer the working directory’s compiled version: 154 | #[ -x ~/i3/build/i3 ] && exec ~/i3/build/i3 155 | 156 | # Restart i3 if killed so that the session might survive. 157 | exec i3 158 | -------------------------------------------------------------------------------- /zmacsclient: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # readahead: read files while Emacs is starting up 4 | cat -- "$@" >/dev/null 2>/dev/null & 5 | 6 | start_daemon_and_connect=--alternate-editor="" 7 | 8 | # CitC workspace, see also the Google monorepo paper: 9 | # https://dl.acm.org/doi/pdf/10.1145/2854146?download=true 10 | if [[ "$PWD" == /google/src/cloud/$USER/* ]] 11 | then 12 | _citc=${PWD#/google/src/cloud/$USER/} 13 | _citc=${_citc/\/*/} 14 | unset EMACS_SERVER_FILE 15 | exec emacsclient --socket-name=$_citc --create-frame $start_daemon_and_connect "$@" 16 | fi 17 | 18 | # The environment may override our logic: 19 | if [[ -n "$EMACS_SERVER_FILE" ]] 20 | then 21 | exec emacsclient --create-frame $start_daemon_and_connect "$@" 22 | fi 23 | 24 | workspaces=$(i3-msg -t get_workspaces 2>&-) 25 | if [[ $? -eq 0 ]] 26 | then 27 | namedws=$(echo "$workspaces" | jq -r 'map(select(.focused))[0].name' | sed 's,^[^:]*:\s*,,g') 28 | if [[ -n "$namedws" ]] 29 | then 30 | exec emacsclient --socket-name=$namedws --create-frame $start_daemon_and_connect "$@" 31 | fi 32 | fi 33 | 34 | # Fallback: do not set a socket name. This path is taken for example when using 35 | # SSH X11 forwarding, where there is no running i3 on the SSH $DISPLAY. 36 | exec emacsclient --create-frame $start_daemon_and_connect "$@" 37 | -------------------------------------------------------------------------------- /zshenv: -------------------------------------------------------------------------------- 1 | ssh_connection_to_urxvt() { 2 | # don't propagate information to urxvt if ssh is used non-interactive 3 | [ -t 0 ] || [ -t 1 ] || return 4 | 5 | local update="\0033]777;cwd-spawn;ssh;$1\0007" 6 | 7 | case $TERM in 8 | screen*) 9 | # pass through to parent terminal emulator 10 | update="\0033P$update\0033\\";; 11 | esac 12 | 13 | echo -ne "$update" 14 | } 15 | -------------------------------------------------------------------------------- /zshrc: -------------------------------------------------------------------------------- 1 | # vim:ts=4:sw=4:expandtab 2 | # Load 4000 lines of history, but save O(∞) 3 | HISTSIZE=4000 4 | HISTFILE=~/.zsh_history 5 | SAVEHIST=10000000 6 | # Print timing statistics for everything which takes longer than 5 seconds of 7 | # user + system time ('sleep 6' does not work because of 0% user/system time!). 8 | REPORTTIME=5 9 | # Do not save duplicate entries 10 | setopt HIST_IGNORE_DUPS 11 | setopt INC_APPEND_HISTORY 12 | setopt COMPLETE_IN_WORD 13 | # For the git branch stuff later on. 14 | setopt EXTENDED_GLOB 15 | # Do not check mail, I don’t use mail that way. 16 | unsetopt mail_warning 17 | unset MAILCHECK 18 | # Do not share history (enabled by default in NixOS’s /etc/zshrc). 19 | unsetopt SHARE_HISTORY 20 | 21 | setopt short_loops 22 | 23 | # All unquoted arguments of the form `anything=expression' appearing after the 24 | # command name have filename expansion (that is, where expression has a leading 25 | # `~' or `=') performed on expression as if it were a parameter assignment. 26 | setopt MAGIC_EQUAL_SUBST 27 | 28 | export EDITOR=~/configfiles/zmacsclient 29 | export VISUAL=$EDITOR 30 | export PAGER='less -R' 31 | export VTYSH_PAGER='cat' 32 | # long date format in ls(1) 33 | export TIME_STYLE=long-iso 34 | # prefer library/system calls/programming manuals 35 | export MANSECT="8:3:2:3posix:3pm:3perl:1:n:l:5:4:9:6:7" 36 | 37 | export LESS_TERMCAP_mb=$'\E[01;31m' 38 | export LESS_TERMCAP_md=$'\E[01;31m' 39 | export LESS_TERMCAP_me=$'\E[0m' 40 | export LESS_TERMCAP_se=$'\E[0m' 41 | export LESS_TERMCAP_ue=$'\E[0m' 42 | export LESS_TERMCAP_us=$'\E[00;32m' 43 | 44 | # Explicitly select Emacs line editing mode (independent of zsh’s best guess 45 | # based on EDITOR/VISUAL). 46 | bindkey -e 47 | 48 | # Make M- delete to (e.g.) the previous slash, just like Emacs. 49 | autoload -U select-word-style 50 | select-word-style bash 51 | # For compatibility with my previous config: 52 | bindkey "^T" backward-kill-word 53 | 54 | bindkey "^X^F" push-line 55 | 56 | # Press C-x C-e to edit the command line in emacs. 57 | autoload -z edit-command-line 58 | zle -N edit-command-line 59 | bindkey "^X^E" edit-command-line 60 | 61 | # NO BEEPING! 62 | setopt no_BEEP 63 | 64 | # Don't display an error if there are no matches, I know what I am doing 65 | setopt no_NOMATCH 66 | 67 | # Leave processes open when closing a shell with background processes 68 | setopt no_HUP 69 | 70 | # Skip .o-files when completing for vi 71 | fignore=(.o) 72 | 73 | # On debian, App::Ack is installed as ack-grep, so alias it. 74 | # Where ag (silversearcher) is available, prefer that (much faster). 75 | local _ack_location="$(\unalias -a; command -v ag ack ack-grep 2>/dev/null | head -1)" 76 | [ $? = 0 ] && alias ack="$_ack_location" 77 | 78 | # On mac, use GNU coreutils ls if installed (e.g. from homebrew). 79 | if command -V gls >/dev/null 2>&1 80 | then 81 | alias ls='gls --color=auto' 82 | else 83 | alias ls='ls --color=auto' 84 | fi 85 | 86 | export LS_COLORS='di=01;94:ln=01;96:pi=33:so=01;95:bd=01;93:cd=01;93:ex=01;92:do=01;95:su=37;41:sg=30;43:st=37;44:ow=34;42:tw=30;42:ca=30;41' 87 | alias spr="curl -F 'sprunge=<-' http://sprunge.us" 88 | 89 | # Requires liburi-perl and xclip. 90 | up() { 91 | for file in $*; do 92 | # Ensure the file is world-readable before uploading 93 | chmod o+r $file 94 | scp $file ex622:htdocs/ 95 | # Echo and try to put this into the X11 clipboard, too 96 | perl -MURI::Escape -E 'print "https://t.zekjur.net/" . uri_escape(shift)' \ 97 | "$(basename "$file")" | tee >(xclip) && echo 98 | done 99 | } 100 | 101 | # Clones the git sources of a Debian package 102 | # needs debcheckout from devscripts and gbp-clone from git-buildpackage 103 | d-clone() { 104 | local package=$1 105 | if ! debcheckout --auth --print $package >/dev/null 106 | then 107 | echo "debcheckout $package failed. Is $package missing Vcs tags?" 108 | return 109 | fi 110 | 111 | set -- $(debcheckout --auth --print $package) 112 | if [ "$1" != "git" ] 113 | then 114 | echo "$package does not use git, but $1 instead." 115 | return 116 | fi 117 | 118 | echo "cloning $2" 119 | gbp clone --pristine-tar $2 || return 120 | 121 | # Change to the newest git repository 122 | cd $(dirname $(ls -1td */.git | head -1)) || return 123 | 124 | echo "d-clone set up everything successfully." 125 | } 126 | 127 | # Nicer output of ls 128 | alias ll='ls -hl' 129 | alias l='ll' 130 | alias rt='ls -hltr' 131 | alias L='dpkg -L' 132 | alias v='vim' 133 | alias V='sudo vim' 134 | e() { ~/configfiles/zmacsclient "$@" } 135 | E() { e /sudo::${1} } 136 | alias m='make' 137 | alias mp='mpv' 138 | # disable gdb welcome message 139 | alias gdb='gdb -q' 140 | alias sctl='s systemctl' 141 | alias j='journalctl --full -e -u' 142 | alias d='~/go/bin/distri' 143 | alias D='sudo distri' 144 | # Find files in current folder 145 | f() { 146 | q="*$1*" 147 | find . -iname $q 148 | } 149 | alias h='cat ~/.zsh_history{_*,} | grep --text --color ' 150 | lsusb() { 151 | (command -V lsusb.py >/dev/null 2>&1 && lsusb.py "$@") || =lsusb "$@" 152 | } 153 | 154 | # write $1 to the inserted sdcard 155 | sdcard() { 156 | sudo dd of=/dev/disk/by-id/usb-Generic-_USB3.0_CRW_-SD_201006010301-0:0 bs=64k oflag=dsync status=progress if="$1" 157 | } 158 | 159 | # Edit a temporary file with my template for a C proof-of-concept 160 | alias cpoc='cd /tmp && FN=$(mktemp --suffix=.c) && cp ~/configfiles/poc-template.c $FN && vi $FN && echo "Proof-of-concept stored in $FN"' 161 | 162 | alias bc='bc -ql' 163 | alias diff='diff --color' 164 | 165 | alias cal='cal -y' 166 | 167 | # More passwords, faster! 168 | alias pw='pwgen -s 23 1' 169 | 170 | alias pd="perldoc" 171 | 172 | alias ripcd='cdparanoia -Bs 1-' 173 | 174 | x() { xclip -i <<< $($*) } 175 | 176 | alias asdf='/home/michael/toggle_layout.sh' 177 | alias uiae='/home/michael/toggle_layout.sh' 178 | 179 | # A nicer ps-output. We need to specify user:12 because otherwise usernames 180 | # such as 'sphinxsearch' or 'libvirt-qemu' are displayed as user IDs. According 181 | # to the procps source, this is specified in The Open Group Base Specifications 182 | # Issue 6 (IEEE Std 1003.1, 2004 Edition). 183 | alias p='ps -A f -o user:12,pid,priority,ni,pcpu,pmem,args' 184 | 185 | alias nh='unset HISTFILE' 186 | 187 | alias acs='apt-cache search' 188 | alias acsn='apt-cache search --names-only' 189 | alias acp='apt-cache policy' 190 | alias acsh='apt-cache show' 191 | alias ac='apt-cache' 192 | agi() { sudo apt install $* } 193 | _da() { _deb_packages uninstalled; } 194 | alias agu='sudo apt update' 195 | alias agdu='sudo apt full-upgrade' 196 | alias tmp-irssi='irssi -! --config=/tmp/irssi/config --home=/tmp/irssi' 197 | 198 | alias smi='sudo make install' 199 | 200 | git() { =git $* && git_branch_chdir } 201 | alias g='git' 202 | alias s='sudo' 203 | # make filename absolute, i.e. prepend current working directory 204 | abs() { echo -n $PWD/$1 } 205 | alias 6='s ip -6' 206 | alias 4='s ip -4' 207 | alias -g T="| tail" 208 | alias -g G="| grep" 209 | alias -g H="| head" 210 | # copy to clipboard 211 | alias -g C="| xclip -selection clipboard" 212 | alias user='systemctl --user' 213 | alias ju='journalctl --user' 214 | 215 | # run command in an i3 tabbed split container 216 | t() { i3-msg -q split vertical, layout tabbed && $@; i3-msg -q move up } 217 | 218 | ping() { 219 | if [ $# -eq 0 ] 220 | then 221 | =ping google.ch 222 | else 223 | =ping "$@" 224 | fi 225 | } 226 | 227 | # Replaces prompt (hostname, pwd) by "% " in each line in the clipboard 228 | alias strip-xclip-prompt="xclip -out | sed 's,^$HOST [^\$]* \\\$ ,% ,g' | xclip" 229 | 230 | # Use ~sl in any command, for example less ~sl 231 | hash -d pb=/var/cache/pbuilder/result 232 | hash -d dcs=~/go/src/github.com/Debian/dcs 233 | hash -d pk4=~/go/src/github.com/Debian/pk4 234 | hash -d ratt=~/go/src/github.com/Debian/ratt 235 | hash -d rirc=~/go/src/github.com/robustirc/robustirc 236 | hash -d router7=~/go/src/github.com/rtr7/router7 237 | hash -d gokrazy=~/go/src/github.com/gokrazy/gokrazy 238 | hash -d scan2drive=~/go/src/github.com/stapelberg/scan2drive 239 | hash -d debiman=~/go/src/github.com/Debian/debiman 240 | hash -d rsync=~/go/src/github.com/gokrazy/rsync 241 | hash -d gus=~/go/src/github.com/gokrazy/gus 242 | hash -d sys=/etc/systemd/system 243 | hash -d net=/etc/systemd/network 244 | hash -d bull=~/go/src/github.com/gokrazy/bull 245 | 246 | # This brings “make test” in ~rsync down from 20s to 10s! 247 | make() { 248 | echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor 249 | =make $* 250 | echo powersave | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor 251 | } 252 | 253 | set_termtitle() { 254 | # escape '%' chars in $1, make nonprintables visible 255 | local a=${(V)1//\%/\%\%} 256 | 257 | # Truncate command, and join lines. 258 | a=${a//[$'\r'$'\n']/} 259 | 260 | [ "$a" = "zsh" ] && { a=${(%)${:-%~}} } 261 | 262 | case $TERM in 263 | screen*) 264 | # plain xterm title 265 | print -rn -- $'\e'"]2;${(%)${:-%m}}: $a"$'\a' 266 | 267 | # screen title (in ^A") 268 | print -rn -- $'\e'"k$a"$'\e'$'\\' 269 | 270 | # screen location 271 | print -rn -- $'\e'"_${(%)${:-%m}}: $a"$'\e'$'\\' 272 | ;; 273 | xterm*|rxvt*) 274 | # plain xterm title 275 | print -rn -- $'\e'"]2;${(%)${:-%m}}: $a"$'\a' 276 | ;; 277 | esac 278 | } 279 | 280 | my_prompt_precmd() { 281 | set_termtitle "zsh" 282 | } 283 | 284 | my_prompt_preexec() { 285 | set_termtitle "$1" 286 | } 287 | 288 | typeset -ga precmd_functions 289 | precmd_functions+=my_prompt_precmd 290 | 291 | typeset -ga preexec_functions 292 | preexec_functions+=my_prompt_preexec 293 | 294 | cwd_to_urxvt() { 295 | local update="\0033]777;cwd-spawn;path;$PWD\0007" 296 | 297 | case $TERM in 298 | screen*) 299 | # pass through to parent terminal emulator 300 | update="\0033P$update\0033\\";; 301 | esac 302 | 303 | echo -ne "$update" 304 | } 305 | 306 | cwd_to_urxvt # execute upon startup to set initial directory 307 | chpwd_functions=(${chpwd_functions[@]} cwd_to_urxvt) 308 | 309 | # Define prompt 310 | fg_green=$'%{\e[1;32m%}' 311 | fg_light_blue=$'%{\e[1;36m%}' 312 | fg_light_silver=$'%{\e[1;37m%}' 313 | fg_white=$'%{\e[1;37m%}' 314 | fg_no_colour=$'%{\e[0m%}' 315 | lvl=$SHLVL 316 | case $TERM in 317 | screen) 318 | lvl=$((lvl-1)) 319 | ;; 320 | esac 321 | 322 | cfgfiles=${${:-~/.zshrc}:A:h} 323 | 324 | export __CURRENT_GIT_PROMPT= 325 | 326 | setup_prompt() { 327 | local _main_fmt 328 | local _cfg_nag 329 | 330 | if [ $USER = "michael" -o $USER = "stapelberg" ]; then 331 | _main_fmt="%m" 332 | else 333 | _main_fmt="%n@%m" 334 | fi 335 | 336 | if [ -f "${cfgfiles}/ERROR" ]; then 337 | _cfg_nag="%F{red}cfg-git-error%f " 338 | else 339 | _cfg_nag="" 340 | fi 341 | 342 | if [ $lvl -ge 2 ] ; then 343 | PROMPT="%K{cyan}%F{black}$_main_fmt%k%f ${fg_green}%~${fg_no_colour} ${__CURRENT_GIT_PROMPT}$lvl $_cfg_nag%% " 344 | else 345 | PROMPT="%K{cyan}%F{black}$_main_fmt%k%f ${fg_green}%~${fg_no_colour} ${__CURRENT_GIT_PROMPT}$_cfg_nag%% " 346 | fi 347 | 348 | # For tramp (emacs). 349 | if [ "$TERM" = "dumb" ]; then 350 | unset PROMPT 351 | PS1='$ ' 352 | unsetopt zle 353 | fi 354 | } 355 | 356 | # show the git branch in prompt 357 | typeset -a __CURRENT_GIT_DIR 358 | parse_git_branch() { 359 | local fg_dark_blue=$'%{\e[0;36m%}' 360 | local fg_no_colour=$'%{\e[0m%}' 361 | 362 | if [ -f ${__CURRENT_GIT_DIR[1]}/HEAD ] 363 | then 364 | local branch=$(sed 's/ref: refs\/heads\///g' ${__CURRENT_GIT_DIR[1]}/HEAD) 365 | __CURRENT_GIT_PROMPT="${fg_dark_blue}${branch}${fg_no_colour} " 366 | else 367 | __CURRENT_GIT_PROMPT="" 368 | fi 369 | } 370 | 371 | git_branch_chdir() { 372 | __CURRENT_GIT_DIR=((../)#.git) 373 | parse_git_branch 374 | setup_prompt 375 | } 376 | 377 | git_branch_chdir 378 | chpwd_functions=(${chpwd_functions[@]} git_branch_chdir) 379 | 380 | setup_prompt 381 | 382 | # Export language 383 | unset LC_ALL 384 | export LANG=de_DE.UTF-8 385 | export LC_MESSAGES=C 386 | # Skip costly locale -a | grep on machines which are known to have reasonable 387 | # locales configured. 388 | if [ "$HOST" = "midna" ] 389 | then 390 | export LC_TIME=en_DK.UTF-8 391 | else 392 | if locale -a | grep -q en_DK.UTF-8; then 393 | export LC_TIME=en_DK.UTF-8 394 | fi 395 | fi 396 | 397 | # TODO: remove once Go ≥ 1.8 is widespread enough (which defaults to ~/go) 398 | export GOPATH=~/go 399 | # Expand path to /usr/sbin and /sbin (because i know which binaries i can call) 400 | # Add $GOPATH/bin 401 | export PATH=/home/michael/.config/avail:/home/michael/.cargo/bin:$GOPATH/bin:~/.local/bin:~/.bin:$PATH:/usr/sbin:/sbin 402 | 403 | # For debian utilities 404 | export DEBEMAIL="stapelberg@debian.org" 405 | export DEB_BUILD_OPTIONS="parallel=8" 406 | export QUILT_PATCHES=debian/patches 407 | 408 | # System-wide default settings for cmake, so that the default 409 | # “cd build && cmake .. && ninja” invocation works: 410 | # (Requires cmake ≥v3.17.0) 411 | export CMAKE_EXPORT_COMPILE_COMMANDS=ON 412 | export CMAKE_GENERATOR=Ninja 413 | 414 | # When tab-completing, show dots. For fast tab completes, they will be 415 | # overwritten instantly, for long tab-completions, you have feedback. 416 | expand-or-complete-with-dots() { 417 | echo -n -e "\e[37m...\e[0m\033[3D" 418 | zle expand-or-complete 419 | zle redisplay 420 | } 421 | 422 | load-completion() { 423 | fpath=($HOME/.local/share/zsh/functions/Completion $fpath) 424 | autoload compinit 425 | compinit -C 426 | compdef _da agi 427 | 428 | # Eliminate the need for explicit rehash commands after installing software, 429 | # and instead rehash on every completion. Thanks to operating system caches, 430 | # this doesn’t incur a noticeable slow-down. 431 | zstyle ':completion:*' rehash true 432 | 433 | # 'ctrl-x r' will complete the 12 last modified (mtime) files/directories 434 | zle -C newest-files menu-complete _generic 435 | # Use “*newest-files” so that it matches both “newest-files” and 436 | # “load-completion-and-newest-files”. 437 | zstyle ':completion:*newest-files:*' completer _files 438 | zstyle ':completion:*newest-files:*' file-patterns '*(omN[1,12])' 439 | zstyle ':completion:*newest-files:*' menu select yes 440 | zstyle ':completion:*newest-files:*' sort false 441 | zstyle ':completion:*newest-files:*' matcher-list 'b:=*' # important 442 | 443 | # Show all processes when completing kill/killall and enable menu mode 444 | zstyle ':completion:*:processes' command 'ps f -N --ppid=$(pidof kthreadd) --pid=$(pidof kthreadd)' 445 | zstyle ':completion:*:processes-names' command 'ps -aeo comm=' 446 | zstyle ':completion:*:*:kill:*' menu yes select 447 | zstyle ':completion:*:*:killall:*' menu yes select 448 | 449 | # colors for zsh file name completion 450 | zmodload zsh/complist 451 | zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS} 452 | 453 | bindkey '\t' expand-or-complete-with-dots 454 | bindkey '^Xr' newest-files 455 | } 456 | 457 | load-completion-and-expand-or-complete-with-dots() { 458 | load-completion 459 | zle -w expand-or-complete-with-dots 460 | } 461 | 462 | load-completion-and-newest-files() { 463 | load-completion 464 | zle -w newest-files 465 | } 466 | 467 | zle -N expand-or-complete-with-dots 468 | zle -N load-completion-and-expand-or-complete-with-dots 469 | zle -N load-completion-and-newest-files 470 | bindkey '\t' load-completion-and-expand-or-complete-with-dots 471 | bindkey '^Xr' load-completion-and-newest-files 472 | 473 | # Enable url-quote-magic to automatically escape URLs when pasting 474 | autoload -U url-quote-magic 475 | zle -N self-insert url-quote-magic 476 | 477 | # Have a bell-character put out, everytime a command finishes. This will set the urgent-hint, 478 | # if the terminal is configured accordingly 479 | bellchar=$'\a' 480 | zle-line-init () { echo -n "$bellchar" } 481 | zle -N zle-line-init 482 | 483 | # Disable C-s stopping output — triggered way more often accidentally. 484 | stty -ixon 485 | 486 | # Directory specific configuration 487 | chpwd_profiles() { 488 | if [[ "$PWD" =~ "$HOME/i3($|/|/*)" ]] 489 | then 490 | alias m='CC=clang make -j16' 491 | else 492 | alias m='make' 493 | fi 494 | 495 | if [[ "$PWD" =~ "$HOME/d/(pkg|out)/([^/]*)" ]] 496 | then 497 | export pkg=$HOME/d/pkg/$match[2] 498 | export out=$HOME/d/out/$match[2] 499 | else 500 | unset pkg 501 | unset out 502 | fi 503 | } 504 | chpwd_functions=( ${chpwd_functions[@]} chpwd_profiles ) 505 | # Call this function before the first chpwd. This is necessary to get correct 506 | # aliases in subshells (VIM’s :sh for example). 507 | chpwd_profiles 508 | 509 | [ -e "$HOME/.zshrc_host" ] && source ~/.zshrc_host 510 | 511 | # If the configfiles are in a git repository, update if it’s older than one hour. 512 | # On x1/x200, I am running cfgupdater instead which triggers on a network connection. 513 | [ "$HOST" != "x1" -a "$HOST" != "x200" ] && ( sleep 1; exec $cfgfiles/gocode/bin/configfiles.$(go env GOARCH 2>&- || echo 'amd64') -configfiles_dir=$cfgfiles -quiet ) &! 514 | --------------------------------------------------------------------------------