├── .ansible-lint ├── README.md ├── bashrc.bash ├── dotfiles ├── aichat │ └── .config │ │ └── aichat │ │ ├── config.yaml │ │ ├── dark.tmTheme │ │ └── roles │ │ └── technical-writer.md ├── autostart │ └── .config │ │ └── autostart │ │ ├── kitty.desktop │ │ ├── org.gnome.Calendar.desktop │ │ └── org.keepassxc.KeePassXC.desktop ├── config │ └── .config │ │ └── mimeapps.list ├── helix │ └── .config │ │ └── helix │ │ ├── config.toml │ │ └── languages.toml ├── keepassxc │ └── .config │ │ └── keepassxc │ │ └── keepassxc.ini ├── kitty │ └── .config │ │ └── kitty │ │ └── kitty.conf ├── lazygit │ └── .config │ │ └── lazygit │ │ └── config.yml ├── marksman │ └── .config │ │ └── marksman │ │ └── config.toml ├── mpv │ └── .config │ │ └── mpv │ │ ├── input.conf │ │ └── mpv.conf ├── pandoc │ └── .local │ │ └── share │ │ └── pandoc │ │ └── filters │ │ ├── diagram-generator.lua │ │ ├── include-code-files.lua │ │ ├── include-files.lua │ │ ├── pagebreak.lua │ │ └── wordcount.lua ├── shell │ ├── .gitconfig │ ├── .zprofile │ └── .zshrc └── sidplayfp │ └── .local │ └── share │ └── sidplayfp │ ├── basic │ └── kernal ├── extras ├── README.md ├── _aichat ├── compile-helix-playbook.yml ├── install-blender-playbook.yml ├── nasa-Q1p7bh3SHj8-unsplash.jpg ├── nnn_4.9-1_amd64.deb └── showmethekey-1.12.0-compiled.zip ├── images ├── debian_logo.svg └── sources.png ├── install-playbook.yml ├── packages.yml ├── profile.sh └── tasks ├── configure_system_settings.yml ├── install_github_packages.yml ├── install_python_packages.yml ├── install_repo_packages.yml ├── setup-gnome.yml ├── setup_pipewire.yml ├── stow_dotfiles.yml └── update_bashrc.yml /.ansible-lint: -------------------------------------------------------------------------------- 1 | skip_list: 2 | - yaml[indentation] 3 | - risky-file-permissions 4 | - '403' 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Developer Workstation Setup Script Debian Edition 2 | 3 | ![Debian_logo](./images/debian_logo.svg) 4 | 5 | This guide provides instructions for setting up a developer workstation using Debian 12 "Bookworm" or 13 "Trixie" (currently unreleased, but in hard freeze). The Ansible playbook automates the installation of software and configurations. Your version of Debian is detected, and the best package options are chosen for you. 6 | 7 | While the software and setup choices are mainly aimed towards developers, it is also suitable for general use. 8 | 9 | ## Installation 10 | 11 | Before running the playbook, follow these steps to install Debian: 12 | 13 | ### Installing Debian 12 Bookworm or 13 Trixie Testing 14 | 15 | You can use the testing installer until Trixie is released this summer: 16 | 17 | https://cdimage.debian.org/images/daily-builds/daily/current/amd64/iso-cd/debian-testing-amd64-netinst.iso 18 | 19 | > [!NOTE] 20 | > - Do not provide any details for the root account, your user account will then have administrative rights. 21 | > - Leave Gnome as the default desktop environment. 22 | > - If you installed from a DVD ISO use the Software & Updates application or the terminal to remove `cdrom` from `/etc/apt/sources.list`. Look in Other Software: 23 | > ![Software & Updates](./images/sources.png) 24 | 25 | > [!NOTE] 26 | > There is a bug in the Debian 12 installer, if you use the default guided partitioner, you will get a swap partition of only 1 GB regardless of how much RAM you have. To get an uncapped swap partition size, in the grub menu before the Debian installer runs, follow these steps: 27 | > 28 | > 1. Press "e" to edit the default installation option. 29 | > 2. In the line that says `linux /install.amd/vmlinuz vga=788 --- quiet`, add the following separated by a space after `vmlinuz`: 30 | > 31 | > ```sh 32 | > partman-auto/cap-ram=n 33 | > ``` 34 | > 35 | > 3. Press Ctrl-x or F10 to continue. 36 | 37 | ## Setting up Debian 38 | 39 | 1. Open the terminal and run the following command to install Ansible, git, and Flatpak: 40 | ```sh 41 | sudo apt install ansible git flatpak 42 | ``` 43 | 44 | 2. Clone this repository and navigate to it: 45 | ```sh 46 | git clone https://github.com/David-Else/developer-workstation-setup-script-debian 47 | cd developer-workstation-setup-script-debian 48 | ``` 49 | 50 | 3. Customize the software selection by modifying `packages.yml` according to your preferences. 51 | 52 | 4. Run the main installation playbook: 53 | > [!NOTE] 54 | > When prompted for the `BECOME` password in Ansible, enter your user password. Your account must have administrative privileges. 55 | > 56 | > You can add `--check` for a test run or `--diff, -vv` to see more info. 57 | 58 | ```sh 59 | ansible-playbook ./install-playbook.yml -K 60 | ``` 61 | 62 | 5. To enable the preview feature in the `nnn` file manager, run it once with the `-a` flag to create the FIFO file. Install the plugins with `sh -c "$(curl -Ls https://raw.githubusercontent.com/jarun/nnn/master/plugins/getplugs)"`. 63 | 64 | 6. Install showmethekey: 65 | 66 | ```sh 67 | cd extras 68 | unzip showmethekey-1.12.0-compiled.zip 69 | cd showmethekey-1.12.0 70 | sudo ./install-show-me-the-key.sh 71 | ``` 72 | 73 | 7. Install Firefox extensions: 74 | 75 | ```sh 76 | firefox https://addons.mozilla.org/en-GB/firefox/addon/ublock-origin/ \ 77 | https://addons.mozilla.org/en-US/firefox/addon/surfingkeys_ff/ \ 78 | https://addons.mozilla.org/en-US/firefox/addon/keepassxc-browser/ & 79 | ``` 80 | 81 | 8. Compile tt terminal typing test from source: 82 | 83 | ```sh 84 | git clone https://github.com/lemnos/tt 85 | cd tt 86 | make && sudo make install 87 | ``` 88 | 89 | 9. Downgrade the MPV config file for Debian 12 if needed: 90 | 91 | ```sh 92 | profile=gpu-hq 93 | hwdec=auto-safe 94 | fullscreen=yes 95 | input-gamepad=yes 96 | osd-font-size=25 97 | ``` 98 | 99 | 10. Change the visudo editor to vim: `sudo update-alternatives --config editor` 100 | 101 | 11. Install Rust and AIChat: 102 | 103 | ```sh 104 | set -o pipefail && 105 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && 106 | . "$HOME/.cargo/env" && 107 | rustup component add rust-analyzer && 108 | cargo install aichat --version 0.29.0 109 | sudo cp ./extras/_aichat /usr/share/zsh/vendor-completions/ 110 | ``` 111 | 112 | 12. `sudo reboot` 113 | 114 | ## Optional Tweaks 115 | 116 | Depending on your software selection, hardware, and personal preferences, you may want to make the following changes: 117 | 118 | ### Audio 119 | 120 | You can confirm the allowed sample rate settings were changed by the playbook with `pw-metadata -n settings` and watch the sample rates change per application running `pw-top`. 121 | 122 | > [!NOTE] 123 | > More info can be found at: [docs.pipewire.org configuration-file-pipewireconf](https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-PipeWire#configuration-file-pipewireconf) 124 | 125 | ### General 126 | 127 | To perform general tweaks, follow these steps: 128 | 129 | - Set Helix to open in Kitty `sudoedit /usr/share/applications/Helix.desktop`: 130 | 131 | ```sh 132 | Exec=kitty --single-instance hx %F 133 | Terminal=false 134 | ``` 135 | 136 | - Configure Git email and name: 137 | ```sh 138 | git config --global user.email "you@example.com" 139 | git config --global user.name "Your Name" 140 | ``` 141 | Enable GPG signing for commits: 142 | ```sh 143 | git config --global user.signingkey key 144 | git config --global commit.gpgsign true 145 | ``` 146 | 147 | - Install extras: 148 | ```sh 149 | gh extension install yusukebe/gh-markdown-preview 150 | gh extension install dlvhdr/gh-dash 151 | hx ~/.config/gh-dash/config.yml # diff: "delta" 152 | ``` 153 | - `sudo apt install v4l2loopback-dkms v4l2loopback-utils` for virtual video devices 154 | 155 | ## FAQ 156 | 157 | If you would like to use Code for things that Helix still struggles with (like debugging), and still use all the modal keyboard shortcuts, I suggest installing `silverquark.dancehelix` or `asvetliakov.vscode-neovim` and using these settings: 158 | ```jsonc 159 | { 160 | // font size 161 | "editor.fontSize": 15, 162 | "markdown.preview.fontSize": 15, 163 | "terminal.integrated.fontSize": 15, 164 | // asvetliakov.vscode-neovim 165 | "editor.scrollBeyondLastLine": false, 166 | "vscode-neovim.neovimExecutablePaths.linux": "/usr/local/bin/nvim", // for el9 clones, or "/usr/bin/nvim" for Fedora 167 | "workbench.list.automaticKeyboardNavigation": false, 168 | // various 169 | "window.titleBarStyle": "custom", // adjust the appearance of the window title bar for linux 170 | "editor.minimap.enabled": false, // controls whether the minimap is shown 171 | "workbench.activityBar.visible": false, // controls the visibility of the activity bar in the workbench 172 | "window.menuBarVisibility": "hidden", // control the visibility of the menu bar 173 | "files.restoreUndoStack": false, // don't restore the undo stack when a file is reopened 174 | "editor.dragAndDrop": false, // controls whether the editor should allow moving selections via drag and drop 175 | "telemetry.enableTelemetry": false, // disable diagnostic data collection 176 | } 177 | ``` 178 | You might also like to install `ms-vscode.live-server` for live debugging in Code or the browser. 179 | 180 | If you get no bootable device found after installing Debian, try https://itsfoss.com/no-bootable-device-found-ubuntu/. Basically, add `shimx64.efi` as a trusted EFI file to be executed. 181 | > [!NOTE] 182 | > Bonus: If you are using Debian 12 as a VM don't forget to install `spice-vdagent` AND restart to get copy and paste working. It should be installed by default on a Debian 13 guest. You can check it is running with `sudo systemctl status spice-vdagent` and enable at boot if needed with `sudo systemctl enable spice-vdagent`. 183 | 184 | ### Updating from Bookworm to Trixie 185 | 186 | If you already have a clean installation of Bookworm and want to update to Trixie before using this playbook: 187 | 188 | 1. Check you have about 5 gig free disk space with `df -h` 189 | 2. `sudo apt-get update && sudo apt-get dist-upgrade --autoremove -y` 190 | 3. `sudo sed -i 's/bookworm/trixie/g' /etc/apt/sources.list` 191 | 4. `sudo apt-get update && sudo apt-get dist-upgrade --autoremove -y` 192 | 193 | -------------------------------------------------------------------------------- /bashrc.bash: -------------------------------------------------------------------------------- 1 | # Aliases 2 | alias ls="ls -ltha --color --group-directories-first --hyperlink=auto" 3 | alias tree="tree -Catr --noreport --dirsfirst --filelimit 100" 4 | alias ebrc='xdg-open ~/.bashrc && source ~/.bashrc' 5 | alias ai="aichat" 6 | alias n="nnn" 7 | 8 | # Functions 9 | md() { 10 | filename="${1##*/}" 11 | pandoc --self-contained --metadata title="Preview" "$1" -o /tmp/"$filename".html 12 | xdg-open /tmp/"$filename".html 13 | } 14 | 15 | ghpr() { GH_FORCE_TTY=100% gh pr list --limit 300 | 16 | fzf --ansi --preview 'GH_FORCE_TTY=100% gh pr view {1}' --preview-window 'down,70%' --header-lines 3 | 17 | awk '{print $1}' | 18 | xargs gh pr checkout; } 19 | 20 | wordcount() { pandoc --lua-filter wordcount.lua "$@"; } 21 | 22 | # nnn 23 | [ -n "$NNNLVL" ] && PS1="N$NNNLVL $PS1" # prompt you are within a shell that will return you to nnn 24 | 25 | # fzf 26 | source /usr/share/doc/fzf/examples/key-bindings.bash 27 | 28 | # zoxide 29 | eval "$(zoxide init bash)" 30 | 31 | # aichat and aider 32 | export OPENAI_API_KEY="xxx" 33 | export TOGETHERAI_API_KEY="xxx" 34 | export TOGETHER_API_KEY="xxx" 35 | 36 | stty -ixon # disable terminal flow control 37 | -------------------------------------------------------------------------------- /dotfiles/aichat/.config/aichat/config.yaml: -------------------------------------------------------------------------------- 1 | # model: openai:gpt-4o 2 | model: together:meta-llama/Llama-3.3-70B-Instruct-Turbo-Free 3 | keybindings: vi 4 | clients: 5 | # - type: openai 6 | - type: openai-compatible 7 | name: together 8 | api_base: https://api.together.xyz/v1 9 | models: 10 | - name: meta-llama/Llama-3.3-70B-Instruct-Turbo-Free 11 | max_input_tokens: 131072 12 | input_price: 0 13 | output_price: 0 14 | supports_function_calling: true 15 | - name: deepseek-ai/DeepSeek-V3 16 | max_input_tokens: 131072 17 | input_price: 1.25 18 | output_price: 1.25 19 | - name: deepseek-ai/DeepSeek-R1 20 | max_input_tokens: 163840 21 | input_price: 3 22 | output_price: 7 23 | - name: Qwen/Qwen3-235B-A22B-fp8-tput 24 | max_input_tokens: 131072 25 | input_price: 0.2 26 | output_price: 0.6 27 | patch: 28 | body: 29 | chat_template_kwargs: { "enable_thinking": false } 30 | -------------------------------------------------------------------------------- /dotfiles/aichat/.config/aichat/dark.tmTheme: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Visual Studio Dark+ 7 | author 8 | vidann1 9 | settings 10 | 11 | 12 | settings 13 | 14 | background 15 | #1E1E1E 16 | caret 17 | #DCDCDC 18 | foreground 19 | #DCDCDC 20 | invisibles 21 | #FFFFFF40 22 | lineHighlight 23 | #0F0F0F 24 | selection 25 | #264F78 26 | 27 | 28 | 29 | name 30 | Comment 31 | scope 32 | comment 33 | settings 34 | 35 | fontStyle 36 | 37 | foreground 38 | #608B4E 39 | 40 | 41 | 42 | name 43 | Variable 44 | scope 45 | variable 46 | settings 47 | 48 | fontStyle 49 | 50 | foreground 51 | #9CDCFE 52 | 53 | 54 | 55 | name 56 | Keyword 57 | scope 58 | keyword 59 | settings 60 | 61 | fontStyle 62 | 63 | foreground 64 | #C586C0 65 | 66 | 67 | 68 | name 69 | Comparision Operator 70 | scope 71 | keyword.operator.comparison 72 | settings 73 | 74 | fontStyle 75 | 76 | foreground 77 | #DCDCDC 78 | 79 | 80 | 81 | name 82 | Assignment Operator 83 | scope 84 | keyword.operator.assignment 85 | settings 86 | 87 | fontStyle 88 | 89 | foreground 90 | #DCDCDC 91 | 92 | 93 | 94 | name 95 | Arithmetic Operator 96 | scope 97 | keyword.operator.arithmetic 98 | settings 99 | 100 | fontStyle 101 | 102 | foreground 103 | #DCDCDC 104 | 105 | 106 | 107 | name 108 | Number 109 | scope 110 | constant.numeric 111 | settings 112 | 113 | fontStyle 114 | 115 | foreground 116 | #B5CEA8 117 | 118 | 119 | 120 | name 121 | User-defined constant 122 | scope 123 | constant 124 | settings 125 | 126 | fontStyle 127 | 128 | foreground 129 | #B4CEA8 130 | 131 | 132 | 133 | name 134 | Built-in constant 135 | scope 136 | constant.language 137 | settings 138 | 139 | fontStyle 140 | 141 | foreground 142 | #569CD6 143 | 144 | 145 | 146 | name 147 | Boolean 148 | scope 149 | constant.language.boolean 150 | settings 151 | 152 | fontStyle 153 | 154 | foreground 155 | #569CD6 156 | 157 | 158 | 159 | name 160 | String 161 | scope 162 | string 163 | settings 164 | 165 | fontStyle 166 | 167 | foreground 168 | #D69D85 169 | 170 | 171 | 172 | name 173 | String interpolation 174 | scope 175 | constant.character.escape, string source 176 | settings 177 | 178 | fontStyle 179 | 180 | foreground 181 | #E3BBAB 182 | 183 | 184 | 185 | name 186 | Preprocessor line 187 | scope 188 | meta.preprocessor 189 | settings 190 | 191 | fontStyle 192 | 193 | foreground 194 | #9B9B9B 195 | 196 | 197 | 198 | name 199 | Preprocessor directive 200 | scope 201 | keyword.control.import 202 | settings 203 | 204 | fontStyle 205 | 206 | foreground 207 | #C586C0 208 | 209 | 210 | 211 | name 212 | Function name 213 | scope 214 | entity.name.function, keyword.other.name-of-parameter.objc 215 | settings 216 | 217 | fontStyle 218 | 219 | foreground 220 | #DCDCAA 221 | 222 | 223 | 224 | name 225 | Class name 226 | scope 227 | entity.name.type 228 | settings 229 | 230 | fontStyle 231 | 232 | foreground 233 | #4EC9B0 234 | 235 | 236 | 237 | name 238 | Type name 239 | scope 240 | storage.type 241 | settings 242 | 243 | fontStyle 244 | 245 | foreground 246 | #569CD6 247 | 248 | 249 | 250 | name 251 | Type modifier 252 | scope 253 | storage.modifier 254 | settings 255 | 256 | fontStyle 257 | 258 | foreground 259 | #569CD6 260 | 261 | 262 | 263 | name 264 | Inherited class name 265 | scope 266 | entity.other.inherited-class 267 | settings 268 | 269 | fontStyle 270 | 271 | foreground 272 | #4EC9B0 273 | 274 | 275 | 276 | name 277 | Function parameter 278 | scope 279 | variable.parameter 280 | settings 281 | 282 | fontStyle 283 | 284 | 285 | 286 | 287 | name 288 | Function argument and result types 289 | scope 290 | storage.type.method 291 | settings 292 | 293 | fontStyle 294 | 295 | foreground 296 | #70727E 297 | 298 | 299 | 300 | name 301 | Section 302 | scope 303 | meta.section entity.name.section, declaration.section entity.name.section 304 | settings 305 | 306 | fontStyle 307 | 308 | 309 | 310 | 311 | name 312 | Library function 313 | scope 314 | support.function 315 | settings 316 | 317 | fontStyle 318 | 319 | foreground 320 | #DCDCDC 321 | 322 | 323 | 324 | name 325 | Library object 326 | scope 327 | support.class, support.type 328 | settings 329 | 330 | fontStyle 331 | 332 | foreground 333 | #DCDCDC 334 | 335 | 336 | 337 | name 338 | Library constant 339 | scope 340 | support.constant 341 | settings 342 | 343 | fontStyle 344 | 345 | foreground 346 | #B5CEA8 347 | 348 | 349 | 350 | name 351 | Library variable 352 | scope 353 | support.variable 354 | settings 355 | 356 | fontStyle 357 | 358 | foreground 359 | #DCDCDC 360 | 361 | 362 | 363 | name 364 | JS: Operator 365 | scope 366 | keyword.operator.js 367 | settings 368 | 369 | foreground 370 | #687687 371 | 372 | 373 | 374 | name 375 | Invalid 376 | scope 377 | invalid 378 | settings 379 | 380 | foreground 381 | #DCDCAA 382 | 383 | 384 | 385 | name 386 | Invalid trailing whitespace 387 | scope 388 | invalid.deprecated.trailing-whitespace 389 | settings 390 | 391 | background 392 | #ff3333 393 | 394 | 395 | 396 | name 397 | Embedded source 398 | scope 399 | text source, string.unquoted 400 | settings 401 | 402 | background 403 | #282828 404 | 405 | 406 | 407 | name 408 | Markup XML declaration 409 | scope 410 | meta.xml-processing, declaration.xml-processing 411 | settings 412 | 413 | fontStyle 414 | 415 | foreground 416 | #68685B 417 | 418 | 419 | 420 | name 421 | Markup DOCTYPE 422 | scope 423 | meta.doctype, declaration.doctype 424 | settings 425 | 426 | fontStyle 427 | 428 | foreground 429 | #808080 430 | 431 | 432 | 433 | name 434 | Markup DTD 435 | scope 436 | meta.doctype.DTD, declaration.doctype.DTD 437 | settings 438 | 439 | fontStyle 440 | 441 | 442 | 443 | 444 | name 445 | Markup tag 446 | scope 447 | meta.tag, declaration.tag 448 | settings 449 | 450 | fontStyle 451 | 452 | foreground 453 | #808080 454 | 455 | 456 | 457 | name 458 | Markup name of tag 459 | scope 460 | entity.name.tag 461 | settings 462 | 463 | fontStyle 464 | 465 | foreground 466 | #569CD6 467 | 468 | 469 | 470 | name 471 | Markup tag attribute 472 | scope 473 | entity.other.attribute-name 474 | settings 475 | 476 | fontStyle 477 | 478 | foreground 479 | #92CAF4 480 | 481 | 482 | 483 | name 484 | Markup: Attribute Value 485 | scope 486 | string.quoted.double.xml, string.quoted.double.html 487 | settings 488 | 489 | fontStyle 490 | 491 | foreground 492 | #C8C8C8 493 | 494 | 495 | 496 | name 497 | Markup: Heading 498 | scope 499 | markup.heading 500 | settings 501 | 502 | fontStyle 503 | 504 | foreground 505 | #569CD6 506 | 507 | 508 | 509 | name 510 | Markup: Quote 511 | scope 512 | markup.quote 513 | settings 514 | 515 | fontStyle 516 | 517 | foreground 518 | #DCDCDC 519 | 520 | 521 | 522 | name 523 | Markup: List 524 | scope 525 | markup.list 526 | settings 527 | 528 | foreground 529 | #DCDCDC 530 | 531 | 532 | 533 | name 534 | § css tag-name 535 | scope 536 | meta.selector.css entity.name.tag 537 | settings 538 | 539 | foreground 540 | #D7BA7D 541 | 542 | 543 | 544 | name 545 | § css:pseudo-class 546 | scope 547 | meta.selector.css entity.other.attribute-name.tag.pseudo-class 548 | settings 549 | 550 | foreground 551 | #D7BA7D 552 | 553 | 554 | 555 | name 556 | § css#id 557 | scope 558 | meta.selector.css entity.other.attribute-name.id 559 | settings 560 | 561 | foreground 562 | #D7BA7D 563 | 564 | 565 | 566 | name 567 | § css.class 568 | scope 569 | meta.selector.css entity.other.attribute-name.class 570 | settings 571 | 572 | foreground 573 | #D7BA7D 574 | 575 | 576 | 577 | name 578 | § css property-name: 579 | scope 580 | support.type.property-name.css 581 | settings 582 | 583 | foreground 584 | #9CDCFE 585 | 586 | 587 | 588 | name 589 | § css property-value; 590 | scope 591 | meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css 592 | settings 593 | 594 | foreground 595 | #C8C8C8 596 | 597 | 598 | 599 | name 600 | § css @at-rule 601 | scope 602 | meta.preprocessor.at-rule keyword.control.at-rule 603 | settings 604 | 605 | foreground 606 | #87CEFA 607 | 608 | 609 | 610 | name 611 | C#: XML Comment Tags 612 | scope 613 | source.cs comment.block.documentation.source.cs meta.tag.xml, source.cs comment.block.documentation.source.cs meta.tag.xml entity.name.tag.localname.xml, source.cs comment.block.documentation.source.cs meta.tag.xml entity.other.attribute-name 614 | settings 615 | 616 | foreground 617 | #608B4E 618 | 619 | 620 | 621 | name 622 | GitGutter deleted 623 | scope 624 | markup.deleted.git_gutter 625 | settings 626 | 627 | foreground 628 | #F92672 629 | 630 | 631 | 632 | name 633 | GitGutter inserted 634 | scope 635 | markup.inserted.git_gutter 636 | settings 637 | 638 | foreground 639 | #A6E22E 640 | 641 | 642 | 643 | name 644 | GitGutter changed 645 | scope 646 | markup.changed.git_gutter 647 | settings 648 | 649 | foreground 650 | #967EFB 651 | 652 | 653 | 654 | name 655 | GitGutter ignored 656 | scope 657 | markup.ignored.git_gutter 658 | settings 659 | 660 | foreground 661 | #565656 662 | 663 | 664 | 665 | name 666 | GitGutter untracked 667 | scope 668 | markup.untracked.git_gutter 669 | settings 670 | 671 | foreground 672 | #565656 673 | 674 | 675 | 676 | name 677 | Git Modified Line 678 | scope 679 | git.changes.x 680 | settings 681 | 682 | background 683 | #272852 684 | 685 | 686 | 687 | name 688 | Git Added Line 689 | scope 690 | git.changes.+ 691 | settings 692 | 693 | background 694 | #275822 695 | 696 | 697 | 698 | name 699 | Git Remove Line 700 | scope 701 | git.changes.- 702 | settings 703 | 704 | background 705 | #A72822 706 | 707 | 708 | 709 | uuid 710 | 2fd1a8f9-ddfd-11e2-a28f-0800200c9a66 711 | 712 | 713 | -------------------------------------------------------------------------------- /dotfiles/aichat/.config/aichat/roles/technical-writer.md: -------------------------------------------------------------------------------- 1 | Assume the role of a professional technical writer. 2 | Correct all spelling and grammar errors and improve readability. 3 | -------------------------------------------------------------------------------- /dotfiles/autostart/.config/autostart/kitty.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Name=kitty 5 | GenericName=Terminal emulator 6 | Comment=Fast, feature-rich, GPU based terminal 7 | TryExec=kitty 8 | StartupNotify=true 9 | Exec=kitty 10 | Icon=kitty 11 | Categories=System;TerminalEmulator; 12 | -------------------------------------------------------------------------------- /dotfiles/autostart/.config/autostart/org.gnome.Calendar.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name[af]=Kalender 3 | Name[an]=Calandario 4 | Name[ar]=التقويم 5 | Name[be]=Каляндар 6 | Name[be@latin]=Kalandar 7 | Name[bg]=Календар 8 | Name[bs]=Kalendar 9 | Name[ca]=Calendari 10 | Name[ca@valencia]=Calendari 11 | Name[ckb]=ڕۆژژمێر 12 | Name[cs]=Kalendář 13 | Name[da]=Kalender 14 | Name[de]=Kalender 15 | Name[el]=Ημερολόγιο 16 | Name[en_GB]=Calendar 17 | Name[eo]=Kalendaro 18 | Name[es]=Calendario 19 | Name[et]=Kalender 20 | Name[eu]=Egutegia 21 | Name[fa]=تقویم 22 | Name[fi]=Kalenteri 23 | Name[fr]=Agenda 24 | Name[fur]=Calendari 25 | Name[fy]=Kalinder 26 | Name[ga]=Féilire 27 | Name[gd]=Am mìosachan 28 | Name[gl]=Calendario 29 | Name[he]=לוח שנה 30 | Name[hi]=कैलेंडर 31 | Name[hr]=Kalendar 32 | Name[hu]=Naptár 33 | Name[id]=Kalender 34 | Name[is]=Dagatal 35 | Name[it]=Calendario 36 | Name[ja]=カレンダー 37 | Name[ka]=კალენდარი 38 | Name[kab]=Awitay 39 | Name[kk]=Күнтізбе 40 | Name[ko]=달력 41 | Name[lt]=Kalendorius 42 | Name[lv]=Kalendārs 43 | Name[mjw]=Calendar 44 | Name[ml]=കലണ്ടർ 45 | Name[ms]=Kalendar 46 | Name[my]=ပြက္ခဒိန် 47 | Name[nb]=Kalender 48 | Name[ne]=पात्रो 49 | Name[nl]=Agenda 50 | Name[oc]=Agenda 51 | Name[pa]=ਕੈਲੰਡਰ 52 | Name[pl]=Kalendarz 53 | Name[pt]=Calendário 54 | Name[pt_BR]=Calendário 55 | Name[ro]=Calendar 56 | Name[ru]=Календарь 57 | Name[sk]=Kalendár 58 | Name[sl]=Koledar 59 | Name[sr]=Календар 60 | Name[sr@latin]=Kalendar 61 | Name[sv]=Kalender 62 | Name[ta]=நாள்காட்டி 63 | Name[tg]=Тақвим 64 | Name[th]=ปฏิทิน 65 | Name[tr]=Takvim 66 | Name[uk]=Календар 67 | Name[vi]=Lịch 68 | Name[zh_CN]=日历 69 | Name[zh_HK]=行事曆 70 | Name[zh_TW]=行事曆 71 | Name=Calendar 72 | Comment[af]=Kry toegang tot en bestuur jou kalenders 73 | Comment[ar]=انفذ إلى تقاويمك و أدرها 74 | Comment[be]=Доступ і кіраванне календарамі 75 | Comment[be@latin]=Dostup i kiravannie kalendarami 76 | Comment[bg]=Достъп и управление на календари 77 | Comment[ca]=Accedeix i gestiona els calendaris 78 | Comment[ca@valencia]=Accedeix i gestiona els calendaris 79 | Comment[ckb]=بچۆناوەو و ڕۆژژمێرەکەت ڕێکبخە 80 | Comment[cs]=Zobrazte si a spravujte své kalendáře 81 | Comment[da]=Tilgå og håndtér dine kalendere 82 | Comment[de]=Auf Ihre Kalender zugreifen und verwalten 83 | Comment[el]=Πρόσβαση και διαχείριση του ημερολογίου σας 84 | Comment[en_GB]=Access and manage your calendars 85 | Comment[eo]=Aliri kaj viajn kalendarojn 86 | Comment[es]=Acceder y gestionar sus calendarios 87 | Comment[et]=Isiklike kalendrite vaatamine ja haldamine 88 | Comment[eu]=Atzitu eta kudeatu zure egutegiak 89 | Comment[fa]=نمایش و مدیریت تقویم‌هایتان 90 | Comment[fi]=Hallitse aikatauluasi kalenterin avulla 91 | Comment[fr]=Ouvrir et gérer vos agendas 92 | Comment[fur]=Jentre e ministre i tiei calendaris 93 | Comment[fy]=Krij tagong ta en besjoch jo kalinders 94 | Comment[gd]=Inntrig is stiùirich na mìosachain agad 95 | Comment[gl]=Acceder e xestionar un calendario 96 | Comment[he]=גישה וניהול לוחות שנה 97 | Comment[hi]=अपने कैलेंडर तक पहुंचें और प्रबंधित करें 98 | Comment[hr]=Pristupite i upravljajte svojim kalendarom 99 | Comment[hu]=Naptárak elérése és kezelése 100 | Comment[id]=Akses dan kelola kalender Anda 101 | Comment[is]=Skoða og sýsla með dagatöl 102 | Comment[it]=Accede e gestisce i propri calendari 103 | Comment[ja]=カレンダーへのアクセスと管理 104 | Comment[ka]=კალენდრების მართვა 105 | Comment[kab]=Kcem, tesferkeḍ iwitayen-ik 106 | Comment[kk]=Күнтізбелеріңізге қатынау және басқару 107 | Comment[ko]=달력에 접근하고 관리합니다 108 | Comment[lt]=Prieikite ir tvarkykite savo kalendorius 109 | Comment[lv]=Piekļūstiet un pārvaldiet savus kalendārus 110 | Comment[ml]=താങ്കളുടെ കലണ്ടറുകൾ കാണുകയും നിയന്ത്രിക്കുകയും ചെയ്യുക 111 | Comment[ms]=Capai dan urus kalendar anda 112 | Comment[my]=သင့်ပြက္ခဒိန်များကို ဝင်ရောက် စီမံပါ 113 | Comment[nb]=Hold styr på livet ditt 114 | Comment[ne]=पात्रो पहुच र ब्यवस्थापन गर्नुहोस 115 | Comment[nl]=Beheer en gebruik uw agenda’s 116 | Comment[oc]=Dobrir e gerir vòstres agendas 117 | Comment[pa]=ਆਪਣੇ ਕੈਲੰਡਰਾਂ ਨੂੰ ਵਰਤੋਂ ਅਤੇ ਬੰਦੋਬਸਤ ਕਰੋ 118 | Comment[pl]=Wyświetlanie i zarządzanie kalendarzem 119 | Comment[pt]=Aceda e gira os seus calendários 120 | Comment[pt_BR]=Acesse e gerencie seus calendários 121 | Comment[ro]=Accesați și administrați calendarele 122 | Comment[ru]=Доступ и управление календарями 123 | Comment[sk]=Zobrazujte a spravujte svoje kalendáre 124 | Comment[sl]=Upravljanje in urejanje koledarjev 125 | Comment[sr]=Приступите и управљајте календаром 126 | Comment[sr@latin]=Pristupite i upravljajte kalendarom 127 | Comment[sv]=Kom åt och hantera dina kalendrar 128 | Comment[th]=เข้าถึงและจัดการปฏิทินต่างๆ ของคุณ 129 | Comment[tr]=Takvimlerinize erişin ve yönetin 130 | Comment[uk]=Доступ та організування календарів 131 | Comment[vi]=Truy cập và quản lý lịch của mình 132 | Comment[zh_CN]=访问并管理日历 133 | Comment[zh_TW]=存取及管理您的行事曆 134 | Comment=Access and manage your calendars 135 | Exec=gnome-calendar %U 136 | # Translators: Do NOT translate or transliterate this text (this is an icon file name)! 137 | Icon=org.gnome.Calendar 138 | Terminal=false 139 | Type=Application 140 | StartupNotify=true 141 | Categories=GNOME;GTK;Office;Calendar;Core; 142 | # Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! 143 | Keywords[af]=kalender;geleentheid;aanmanings; 144 | Keywords[an]=Calandario;Evento;Recordatorio; 145 | Keywords[ar]=Calendar;Event;Reminder;تقويم;حدث;تذكير; 146 | Keywords[be]=Calendar;Event;Reminder;Каляндар;Падзея;Напамін; 147 | Keywords[be@latin]=Calendar;Event;Reminder;Kalandar;Padzieja;Napamin; 148 | Keywords[bg]=calendar;event;reminder;календар;събития;напомняне;разписание; 149 | Keywords[bs]=Kalendar;Događaj;Podsjetnik; 150 | Keywords[ca]=Calendari;Cita;Recordatori; 151 | Keywords[ca@valencia]=Calendari;Cita;Recordatori; 152 | Keywords[ckb]=Calendar;Event;Reminder; 153 | Keywords[cs]=kalendář;událost;upomínka;připomenutí; 154 | Keywords[da]=Kalender;Begivenhed;Påmindelse; 155 | Keywords[de]=Calendar;Event;Reminder;Kalender;Termin;Erinnerung; 156 | Keywords[el]=Ημερολόγιο;Συμβάν;Υπενθύμιση;Calendar;Event;Reminder; 157 | Keywords[en_GB]=Calendar;Event;Reminder; 158 | Keywords[eo]=Kalendaro;Evento;Memorigilo; 159 | Keywords[es]=Calendario;Evento;Recordatorio; 160 | Keywords[et]=Calendar;Event;Reminder;Kalender;Sündmused;Meeldetuletused;Päevakava; 161 | Keywords[eu]=Egutegia;Gertaera;Oroigarria; 162 | Keywords[fa]=Calendar;Event;Reminder;تقویم;رویداد;یادآوری; 163 | Keywords[fi]=Calendar;Event;Reminder;Kalenteri;Tapahtuma;Muistutus; 164 | Keywords[fr]=Agenda;Évènement;Rappel; 165 | Keywords[fur]=Calendari;Lunari;Event;Events;Promemorie; 166 | Keywords[fy]=Kalinder;Evenemint;Oantinkens; 167 | Keywords[gd]=Calendar;Event;Reminder;mìosachan;tachartas;cuimhneachan; 168 | Keywords[gl]=Calendario;Evento;Recordatorio; 169 | Keywords[he]=לוח שנה;יומן;אירוע;תזכיר;מזכיר;תזכורת;מזכר; 170 | Keywords[hi]=कैलेंडर;कार्यक्रम;अनुस्मारक; 171 | Keywords[hr]=Kalendar;Događaj;Podsjetnik; 172 | Keywords[hu]=Naptár;Esemény;Emlékeztető; 173 | Keywords[id]=Kalender;Acara;Pengingat; 174 | Keywords[is]=dagatal;viðburður;atburður;áminning; 175 | Keywords[it]=Calendario;Evento;Eventi;Promemoria; 176 | Keywords[ja]=Calendar;Event;Reminder;カレンダー;イベント;リマインダー; 177 | Keywords[ka]=Calendar;Event;Reminder; 178 | Keywords[kab]=Awitay;Tadyant;Asmekti; 179 | Keywords[kk]=Calendar;Event;Reminder;Күнтізбе;Оқиға;Естелік; 180 | Keywords[ko]=Calendar;달력;캘린더;Event;행사;이벤트;Reminder;알림; 181 | Keywords[lt]=Kalendorius;Įvykis;Priminimas; 182 | Keywords[lv]=Kalendārs;Notikums;Atgādinājums; 183 | Keywords[mjw]=Calendar;Event;Reminder; 184 | Keywords[ml]=Calendar;Event;Reminder; 185 | Keywords[ms]=Kalendar;Peristiwa;Pemberitahuan; 186 | Keywords[my]=ပြက္ခဒိန်;အစီအစဉ်;သတိပေးချက်; 187 | Keywords[nb]=Kalender;Hendelser;Påminnelser;Timeplan;Tidsskjema;Ukeplan;Aktiviteter;Planlegger; 188 | Keywords[ne]=भित्तेपात्रो; नतिजा; स्मरणपत्र; 189 | Keywords[nl]=Calendar;Agenda;Kalender;Event;Afspraak;Evenement;Gebeurtenis;Reminder;Herinnering; 190 | Keywords[oc]=Agenda;Eveniment;Rapèl; 191 | Keywords[pa]=ਕੈਲੰਡਰ;ਈਵੈਂਟ;ਰੀਮਾਈਡਰ; 192 | Keywords[pl]=Kalendarz;Wydarzenie;Zdarzenie;Przypomnienie;Przypominanie; 193 | Keywords[pt]=Calendário;Evento;Lembrete; 194 | Keywords[pt_BR]=Calendário;Agenda;Evento;Lembrete; 195 | Keywords[ro]=Calendar;Event;Reminder;Eveniment;Memento; 196 | Keywords[ru]=Календарь;Событие;Напоминание; 197 | Keywords[sk]=kalendár;udalosť;pripomienka;pripomenutie; 198 | Keywords[sl]=koledar;dogodki;dogodek;opomnik;opomniki;datum;calendar;task;reminder;date; 199 | Keywords[sr]=Calendar;Event;Reminder;Календар;Догађај;Подсетник;Kalendar;Događaj;Podsetnik;Dogadjaj; 200 | Keywords[sr@latin]=Calendar;Event;Reminder;Kalendar;Događaj;Podsetnik;Kalendar;Događaj;Podsetnik;Dogadjaj; 201 | Keywords[sv]=Kalender;Händelse;Påminnelse; 202 | Keywords[tg]=Тақвим;Рӯйдод;Ёдрасон; 203 | Keywords[th]=ปฏิทิน;งานกิจกรรม;ปลุกเตือน; 204 | Keywords[tr]=Calendar;Event;Reminder;Takvim;Olay;Etkinlik;Anımsatıcı;Hatırlatıcı; 205 | Keywords[uk]=Calendar;Event;Reminder;Календар;Подія;Нагадування; 206 | Keywords[vi]=Calendar;Event;Reminder;Lịch;Lich;Sự kiện;Su kien;Nhắc;Nhac; 207 | Keywords[zh_CN]=Calendar;Event;Reminder;日历;事件;提醒; 208 | Keywords[zh_TW]=Calendar;Event;Reminder;行事曆;事件;事件;活動;提醒;日曆; 209 | Keywords=Calendar;Event;Reminder; 210 | MimeType=text/calendar; 211 | DBusActivatable=true 212 | -------------------------------------------------------------------------------- /dotfiles/autostart/.config/autostart/org.keepassxc.KeePassXC.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=KeePassXC 3 | GenericName=Password Manager 4 | GenericName[ar]=مدير كلمات المرور 5 | GenericName[bg]=Мениджър на пароли 6 | GenericName[ca]=Gestor de contrasenyes 7 | GenericName[cs]=Aplikace pro správu hesel 8 | GenericName[da]=Adgangskodehåndtering 9 | GenericName[de]=Passwortverwaltung 10 | GenericName[es]=Gestor de contraseñas 11 | GenericName[et]=Paroolihaldur 12 | GenericName[fi]=Salasanamanageri 13 | GenericName[fr]=Gestionnaire de mot de passe 14 | GenericName[hu]=Jelszókezelő 15 | GenericName[id]=Pengelola Sandi 16 | GenericName[it]=Gestione password 17 | GenericName[ja]=パスワードマネージャー 18 | GenericName[ko]=암호 관리자 19 | GenericName[lt]=Slaptažodžių tvarkytuvė 20 | GenericName[nb]=Passordhåndterer 21 | GenericName[nl]=Wachtwoordbeheer 22 | GenericName[pl]=Menedżer haseł 23 | GenericName[pt_BR]=Gerenciador de Senhas 24 | GenericName[pt]=Gestor de palavras-passe 25 | GenericName[ro]=Manager de parole 26 | GenericName[ru]=Менеджер паролей 27 | GenericName[sk]=Správca hesiel 28 | GenericName[sv]=Lösenordshanterare 29 | GenericName[th]=แอพจัดการรหัสผ่าน 30 | GenericName[tr]=Parola yöneticisi 31 | GenericName[uk]=Розпорядник паролів 32 | GenericName[zh_CN]=密码管理器 33 | GenericName[zh_TW]=密碼管理員 34 | Comment=Community-driven port of the Windows application “KeePass Password Safe” 35 | Comment[da]=Fællesskabsdrevet port af Windows-programmet “KeePass Password Safe” 36 | Comment[et]=Kogukonna arendatav port Windowsi programmist KeePass Password Safe 37 | Comment[ru]=Разработанный сообществом порт Windows-приложения KeePass Password Safe 38 | Exec=keepassxc %f 39 | TryExec=keepassxc 40 | Icon=keepassxc 41 | StartupWMClass=keepassxc 42 | StartupNotify=true 43 | Terminal=false 44 | Type=Application 45 | Version=1.5 46 | Categories=Utility;Security;Qt; 47 | MimeType=application/x-keepass2; 48 | SingleMainWindow=true 49 | X-GNOME-SingleWindow=true 50 | Keywords=security;privacy;password-manager;yubikey;password;keepass; 51 | Keywords[de]=sicherheit;privatsphäre;passwort-manager;yubikey;passwort;keepass; 52 | -------------------------------------------------------------------------------- /dotfiles/config/.config/mimeapps.list: -------------------------------------------------------------------------------- 1 | [Default Applications] 2 | video/x-matroska=mpv.desktop 3 | video/mp4=mpv.desktop 4 | audio/x-opus+ogg=mpv.desktop 5 | text/vnd.trolltech.linguist=helix.desktop 6 | application/toml=helix.desktop 7 | text/plain=helix.desktop 8 | text/x-python=helix.desktop 9 | application/json=helix.desktop 10 | application/javascript=helix.desktop 11 | audio/flac=mpv.desktop 12 | application/x-shellscript=helix.desktop 13 | audio/prs.sid=sidplayfp.desktop 14 | text/csv=libreoffice-calc.desktop 15 | video/mpeg=mpv.desktop 16 | 17 | [Added Associations] 18 | video/x-matroska=mpv.desktop; 19 | video/mp4=mpv.desktop; 20 | audio/x-opus+ogg=mpv.desktop; 21 | text/vnd.trolltech.linguist=helix.desktop; 22 | application/toml=helix.desktop; 23 | text/plain=helix.desktop; 24 | text/x-python=helix.desktop; 25 | application/json=helix.desktop; 26 | application/javascript=helix.desktop; 27 | audio/flac=mpv.desktop; 28 | application/x-shellscript=helix.desktop; 29 | audio/prs.sid=sidplayfp.desktop; 30 | text/csv=libreoffice-calc.desktop; 31 | video/mpeg=mpv.desktop; 32 | -------------------------------------------------------------------------------- /dotfiles/helix/.config/helix/config.toml: -------------------------------------------------------------------------------- 1 | theme = "dark_plus" 2 | 3 | [keys.normal] 4 | C-j = "page_down" 5 | C-k = ["page_up", "goto_window_top"] 6 | G = "goto_file_end" 7 | C-l = "goto_next_buffer" 8 | C-h = "goto_previous_buffer" 9 | "tab" = "expand_selection" 10 | "S-tab" = "shrink_selection" 11 | "F5" = ":reload" 12 | "@" = ["select_all", ":pipe sort -t@ -k2,2r"] 13 | "+" = ["select_all", ":pipe sort -t+ -k2,2r"] 14 | Z = { Z = ":wq", Q = ":q!" } 15 | 16 | [keys.select] 17 | G = "goto_file_end" 18 | 19 | [keys.normal.space] 20 | w = ":write" 21 | q = ":quit" 22 | l = ":sh kitty @ launch --no-response --cwd=current --type=overlay --copy-env lazygit" 23 | 24 | [keys.normal.space.t] 25 | f = ":toggle auto-format" 26 | "." = ":toggle file-picker.hidden" # toggles ignoring hidden files 27 | i = ":toggle lsp.display-inlay-hints" 28 | s = ":toggle soft-wrap.enable" 29 | z = ":toggle gutters.line-numbers.min-width 52 3" 30 | b = ":toggle bufferline multiple never" 31 | 32 | [keys.normal.C-space] 33 | n = "@:o %" 34 | x = "@:sh rm %" 35 | r = "@:sh mv % %" 36 | g = [":pipe-to cat > /tmp/helix-gpt", ":append-output cat /tmp/helix-gpt | aichat --role technical-writer"] 37 | p = "@:sh pandoc --resource-path % --self-contained --metadata title='Preview' % -o /tmp/md-preview.html && xdg-open /tmp/md-preview.html" 38 | d = ":pipe echo -n $(date +%d-%m-%Y)" 39 | t = ":sh kitty @ focus-window --match 'title:terminal and state:parent_active' || kitty @ launch --no-response --keep-focus --cwd=current --title=terminal" 40 | a = ":sh kitty @ launch --no-response --title=aichat aichat --role technical-writer" 41 | i = ":sh kitty @ signal-child --match 'title:terminal and state:parent_active' SIGINT" 42 | m = { r = ":sh kitty @ send-text --match 'title:terminal and state:parent_active' 'make run\n'", b = ":sh kitty @ send-text --match 'title:terminal and state:parent_active' 'make build\n'", t = ":sh kitty @ send-text --match 'title:terminal and state:parent_active' 'clear\nmake test\n'"} 43 | s = ":pipe-to xargs -I {} kitty @ send-text --match title:terminal and state:parent_active '{}\n'" 44 | 45 | [editor] 46 | color-modes = true 47 | end-of-line-diagnostics = "hint" 48 | bufferline = "multiple" 49 | default-yank-register = "+" 50 | 51 | [editor.whitespace.render] 52 | newline = "all" 53 | 54 | [editor.cursor-shape] 55 | insert = "bar" 56 | 57 | [editor.file-picker] 58 | follow-symlinks = false 59 | hidden = false # don't ignore hidden files 60 | 61 | [editor.statusline] 62 | center = ["version-control"] 63 | 64 | [editor.soft-wrap] 65 | enable = true 66 | wrap-at-text-width = true 67 | 68 | [editor.inline-diagnostics] 69 | cursor-line = "warning" 70 | -------------------------------------------------------------------------------- /dotfiles/helix/.config/helix/languages.toml: -------------------------------------------------------------------------------- 1 | [language-server.rust-analyzer.config] 2 | check.command = "clippy" 3 | 4 | [language-server.ltex-ls-plus.config] 5 | ltex.diagnosticSeverity = "warning" 6 | ltex.disabledRules = { "en-US" = ["PROFANITY"], "en-GB" = ["PROFANITY"] } 7 | ltex.dictionary = { "en-US" = ["builtin"], "en-GB" = ["builtin"] } 8 | 9 | [[language]] 10 | name = "markdown" 11 | text-width = 80 12 | soft-wrap = { wrap-at-text-width = true } 13 | language-servers = ["marksman", "ltex-ls-plus"] 14 | formatter = { command = 'prettier', args = [ 15 | "--parser", 16 | "markdown", 17 | "--prose-wrap", 18 | "never", # 19 | ] } 20 | # auto-format = true 21 | 22 | [[language]] 23 | name = "html" 24 | language-servers = [ "vscode-html-language-server", "tailwindcss-ls" ] 25 | formatter = { command = 'prettier', args = ["--parser", "html"] } 26 | 27 | [[language]] 28 | name = "json" 29 | formatter = { command = 'prettier', args = ["--parser", "json"] } 30 | 31 | [[language]] 32 | name = "css" 33 | language-servers = [ "vscode-css-language-server", "tailwindcss-ls" ] 34 | formatter = { command = 'prettier', args = ["--parser", "css"] } 35 | 36 | [[language]] 37 | name = "yaml" 38 | formatter = { command = 'prettier', args = ["--parser", "yaml"] } 39 | auto-format = true 40 | 41 | [[language]] 42 | name = "javascript" 43 | formatter = { command = 'prettier', args = ["--parser", "typescript"] } 44 | auto-format = true 45 | 46 | [[language]] 47 | name = "typescript" 48 | formatter = { command = 'prettier', args = ["--parser", "typescript"] } 49 | auto-format = true 50 | 51 | [[language]] 52 | name = "bash" 53 | formatter = { command = 'shfmt', args = ["-i", "4"] } 54 | auto-format = true 55 | 56 | [[language]] 57 | name = "git-commit" 58 | language-servers = ["ltex-ls-plus"] 59 | 60 | [[language]] 61 | name = "python" 62 | formatter = { command = "black", args = ["--quiet", "-"] } 63 | auto-format = true 64 | language-servers = ["pyright"] 65 | # pyproject.toml 66 | # [tool.pyright] 67 | # typeCheckingMode = "strict" 68 | -------------------------------------------------------------------------------- /dotfiles/keepassxc/.config/keepassxc/keepassxc.ini: -------------------------------------------------------------------------------- 1 | [Browser] 2 | CustomProxyLocation= 3 | Enabled=true 4 | 5 | [SSHAgent] 6 | Enabled=true 7 | 8 | [Security] 9 | LockDatabaseScreenLock=false 10 | -------------------------------------------------------------------------------- /dotfiles/kitty/.config/kitty/kitty.conf: -------------------------------------------------------------------------------- 1 | font_size 12.0 2 | hide_window_decorations yes 3 | enabled_layouts tall,stack 4 | enable_audio_bell no 5 | wayland_enable_ime no 6 | copy_on_select yes 7 | 8 | tab_bar_edge top 9 | tab_bar_style separator 10 | tab_separator " | " 11 | 12 | allow_remote_control yes 13 | listen_on unix:/tmp/kitty 14 | 15 | map ctrl+= change_font_size all 22.0 16 | map ctrl+enter launch --cwd=current 17 | map ctrl+t new_tab 18 | map ctrl+k scroll_line_up 19 | map ctrl+j scroll_line_down 20 | map ctrl+] next_window 21 | map ctrl+[ previous_window 22 | map alt+l next_layout 23 | # map alt+s launch --cwd=current --type background bash -c 'random=$RANDOM && gnome-screenshot -f "./screenshot_$random.png" && krita "./screenshot_$random.png"' 24 | 25 | # use script with `cat - | ansi2html > path/to/screenshot.html` 26 | # map alt+s launch --type background --stdin-source=@screen --stdin-add-formatting sh path/to/terminal-screen-shot.sh 27 | -------------------------------------------------------------------------------- /dotfiles/lazygit/.config/lazygit/config.yml: -------------------------------------------------------------------------------- 1 | git: 2 | paging: 3 | colorArg: always 4 | pager: delta --paging=never --side-by-side 5 | 6 | gui: 7 | nerdFontsVersion: "3" 8 | screenMode: half 9 | enlargedSideViewLocation: top 10 | showCommandLog: false 11 | 12 | keybinding: 13 | universal: 14 | scrollUpMain-alt1: 15 | scrollDownMain-alt1: 16 | 17 | promptToReturnFromSubprocess: false 18 | -------------------------------------------------------------------------------- /dotfiles/marksman/.config/marksman/config.toml: -------------------------------------------------------------------------------- 1 | [code_action] 2 | # Enable/disable "Table of Contents" code action 3 | toc.enable = false 4 | -------------------------------------------------------------------------------- /dotfiles/mpv/.config/mpv/input.conf: -------------------------------------------------------------------------------- 1 | l seek +5 2 | h seek -5 3 | ctrl+l playlist-next 4 | ctrl+h playlist-prev 5 | ctrl+p show-text ${playlist} 2000 6 | 7 | GAMEPAD_ACTION_DOWN cycle pause 8 | GAMEPAD_ACTION_RIGHT add chapter 1 9 | GAMEPAD_ACTION_LEFT add chapter -1 10 | GAMEPAD_MENU quit 11 | GAMEPAD_RIGHT_STICK_RIGHT seek +5 12 | GAMEPAD_RIGHT_STICK_LEFT seek -5 13 | GAMEPAD_DPAD_UP add volume 2 14 | GAMEPAD_DPAD_DOWN add volume -2 15 | GAMEPAD_DPAD_LEFT cycle audio 16 | GAMEPAD_DPAD_RIGHT cycle sub 17 | GAMEPAD_START script_binding file_browser/browse-files 18 | GAMEPAD_BACK show-text ${playlist} 3000 19 | -------------------------------------------------------------------------------- /dotfiles/mpv/.config/mpv/mpv.conf: -------------------------------------------------------------------------------- 1 | profile=high-quality 2 | hwdec=auto-safe 3 | fullscreen=yes 4 | input-gamepad=yes 5 | osd-font-size=25 6 | 7 | autocreate-playlist=filter 8 | directory-mode=ignore 9 | directory-filter-types=video,audio 10 | -------------------------------------------------------------------------------- /dotfiles/pandoc/.local/share/pandoc/filters/diagram-generator.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | diagram-generator – create images and figures from code blocks. 3 | 4 | This Lua filter is used to create images with or without captions 5 | from code blocks. Currently PlantUML, GraphViz, Tikz, and Python 6 | can be processed. For further details, see README.md. 7 | 8 | Copyright: © 2018-2021 John MacFarlane , 9 | 2018 Florian Schätzig , 10 | 2019 Thorsten Sommer , 11 | 2019-2021 Albert Krewinkel 12 | License: MIT – see LICENSE file for details 13 | ]] 14 | -- Module pandoc.system is required and was added in version 2.7.3 15 | PANDOC_VERSION:must_be_at_least '2.7.3' 16 | 17 | local system = require 'pandoc.system' 18 | local utils = require 'pandoc.utils' 19 | local stringify = function (s) 20 | return type(s) == 'string' and s or utils.stringify(s) 21 | end 22 | local with_temporary_directory = system.with_temporary_directory 23 | local with_working_directory = system.with_working_directory 24 | 25 | -- The PlantUML path. If set, uses the environment variable PLANTUML or the 26 | -- value "plantuml.jar" (local PlantUML version). In order to define a 27 | -- PlantUML version per pandoc document, use the meta data to define the key 28 | -- "plantuml_path". 29 | local plantuml_path = os.getenv("PLANTUML") or "plantuml.jar" 30 | 31 | -- The Inkscape path. In order to define an Inkscape version per pandoc 32 | -- document, use the meta data to define the key "inkscape_path". 33 | local inkscape_path = os.getenv("INKSCAPE") or "inkscape" 34 | 35 | -- The Python path. In order to define a Python version per pandoc document, 36 | -- use the meta data to define the key "python_path". 37 | local python_path = os.getenv("PYTHON") or "python" 38 | 39 | -- The Python environment's activate script. Can be set on a per document 40 | -- basis by using the meta data key "activatePythonPath". 41 | local python_activate_path = os.getenv("PYTHON_ACTIVATE") 42 | 43 | -- The Java path. In order to define a Java version per pandoc document, 44 | -- use the meta data to define the key "java_path". 45 | local java_path = os.getenv("JAVA_HOME") 46 | if java_path then 47 | java_path = java_path .. package.config:sub(1,1) .. "bin" 48 | .. package.config:sub(1,1) .. "java" 49 | else 50 | java_path = "java" 51 | end 52 | 53 | -- The dot (Graphviz) path. In order to define a dot version per pandoc 54 | -- document, use the meta data to define the key "dot_path". 55 | local dot_path = os.getenv("DOT") or "dot" 56 | 57 | -- The pdflatex path. In order to define a pdflatex version per pandoc 58 | -- document, use the meta data to define the key "pdflatex_path". 59 | local pdflatex_path = os.getenv("PDFLATEX") or "pdflatex" 60 | 61 | -- The asymptote path. There is also the metadata variable 62 | -- "asymptote_path". 63 | local asymptote_path = os.getenv ("ASYMPTOTE") or "asy" 64 | 65 | -- The default format is SVG i.e. vector graphics: 66 | local filetype = "svg" 67 | local mimetype = "image/svg+xml" 68 | 69 | -- Check for output formats that potentially cannot use SVG 70 | -- vector graphics. In these cases, we use a different format 71 | -- such as PNG: 72 | if FORMAT == "docx" then 73 | filetype = "png" 74 | mimetype = "image/png" 75 | elseif FORMAT == "pptx" then 76 | filetype = "png" 77 | mimetype = "image/png" 78 | elseif FORMAT == "rtf" then 79 | filetype = "png" 80 | mimetype = "image/png" 81 | end 82 | 83 | -- Execute the meta data table to determine the paths. This function 84 | -- must be called first to get the desired path. If one of these 85 | -- meta options was set, it gets used instead of the corresponding 86 | -- environment variable: 87 | function Meta(meta) 88 | plantuml_path = stringify( 89 | meta.plantuml_path or meta.plantumlPath or plantuml_path 90 | ) 91 | inkscape_path = stringify( 92 | meta.inkscape_path or meta.inkscapePath or inkscape_path 93 | ) 94 | python_path = stringify( 95 | meta.python_path or meta.pythonPath or python_path 96 | ) 97 | python_activate_path = 98 | meta.activate_python_path or meta.activatePythonPath or python_activate_path 99 | python_activate_path = python_activate_path and stringify(python_activate_path) 100 | java_path = stringify( 101 | meta.java_path or meta.javaPath or java_path 102 | ) 103 | dot_path = stringify( 104 | meta.path_dot or meta.dotPath or dot_path 105 | ) 106 | pdflatex_path = stringify( 107 | meta.pdflatex_path or meta.pdflatexPath or pdflatex_path 108 | ) 109 | asymptote_path = stringify( 110 | meta.asymptote_path or meta.asymptotePath or asymptote_path 111 | ) 112 | end 113 | 114 | -- Call plantuml.jar with some parameters (cf. PlantUML help): 115 | local function plantuml(puml, filetype) 116 | return pandoc.pipe( 117 | java_path, 118 | {"-jar", plantuml_path, "-t" .. filetype, "-pipe", "-charset", "UTF8"}, 119 | puml 120 | ) 121 | end 122 | 123 | -- Call dot (GraphViz) in order to generate the image 124 | -- (thanks @muxueqz for this code): 125 | local function graphviz(code, filetype) 126 | return pandoc.pipe(dot_path, {"-T" .. filetype}, code) 127 | end 128 | 129 | -- 130 | -- TikZ 131 | -- 132 | 133 | --- LaTeX template used to compile TikZ images. Takes additional 134 | --- packages as the first, and the actual TikZ code as the second 135 | --- argument. 136 | local tikz_template = [[ 137 | \documentclass{standalone} 138 | \usepackage{tikz} 139 | %% begin: additional packages 140 | %s 141 | %% end: additional packages 142 | \begin{document} 143 | %s 144 | \end{document} 145 | ]] 146 | 147 | -- Returns a function which takes the filename of a PDF or SVG file 148 | -- and a target filename, and writes the input as the given format. 149 | -- Returns `nil` if conversion into the target format is not possible. 150 | local function convert_with_inkscape(filetype) 151 | -- Build the basic Inkscape command for the conversion 152 | local inkscape_output_args 153 | 154 | -- Check inksape version. 155 | -- TODO: this can be removed if supporting older Inkscape is not important. 156 | local inkscape_v_string = io.popen(inkscape_path .. " --version"):read() 157 | local inkscape_v_major = inkscape_v_string:gmatch("([0-9]*)%.")() 158 | local isv1 = tonumber(inkscape_v_major) >= 1 159 | 160 | local cmd_arg = isv1 and '"%s" "%s" -o "%s" ' or '"%s" --without-gui --file="%s" ' 161 | 162 | if filetype == 'png' then 163 | local png_arg = isv1 and '--export-type=png' or '--export-png="%s"' 164 | output_args = png_arg .. '--export-dpi=300' 165 | elseif filetype == 'svg' then 166 | output_args = isv1 and '--export-type=svg --export-plain-svg' or '--export-plain-svg="%s"' 167 | else 168 | return nil 169 | end 170 | 171 | return function (pdf_file, outfile) 172 | local inkscape_command = string.format( 173 | cmd_arg .. output_args, 174 | inkscape_path, 175 | pdf_file, 176 | outfile 177 | ) 178 | local command_output = io.popen(inkscape_command) 179 | -- TODO: print output when debugging. 180 | command_output:close() 181 | end 182 | end 183 | 184 | --- Compile LaTeX with Tikz code to an image 185 | local function tikz2image(src, filetype, additional_packages) 186 | local convert = convert_with_inkscape(filetype) 187 | -- Bail if there is now known way from PDF to the target format. 188 | if not convert then 189 | error(string.format("Don't know how to convert pdf to %s.", filetype)) 190 | end 191 | return with_temporary_directory("tikz2image", function (tmpdir) 192 | return with_working_directory(tmpdir, function () 193 | -- Define file names: 194 | local file_template = "%s/tikz-image.%s" 195 | local tikz_file = file_template:format(tmpdir, "tex") 196 | local pdf_file = file_template:format(tmpdir, "pdf") 197 | local outfile = file_template:format(tmpdir, filetype) 198 | 199 | -- Build and write the LaTeX document: 200 | local f = io.open(tikz_file, 'w') 201 | f:write(tikz_template:format(additional_packages or '', src)) 202 | f:close() 203 | 204 | -- Execute the LaTeX compiler: 205 | pandoc.pipe(pdflatex_path, {'-output-directory', tmpdir, tikz_file}, '') 206 | 207 | convert(pdf_file, outfile) 208 | 209 | -- Try to open and read the image: 210 | local img_data 211 | local r = io.open(outfile, 'rb') 212 | if r then 213 | img_data = r:read("*all") 214 | r:close() 215 | else 216 | -- TODO: print warning 217 | end 218 | 219 | return img_data 220 | end) 221 | end) 222 | end 223 | 224 | -- Run Python to generate an image: 225 | local function py2image(code, filetype) 226 | 227 | -- Define the temp files: 228 | local outfile = string.format('%s.%s', os.tmpname(), filetype) 229 | local pyfile = os.tmpname() 230 | 231 | -- Replace the desired destination's file type in the Python code: 232 | local extendedCode = string.gsub(code, "%$FORMAT%$", filetype) 233 | 234 | -- Replace the desired destination's path in the Python code: 235 | extendedCode = string.gsub(extendedCode, "%$DESTINATION%$", outfile) 236 | 237 | -- Write the Python code: 238 | local f = io.open(pyfile, 'w') 239 | f:write(extendedCode) 240 | f:close() 241 | 242 | -- Execute Python in the desired environment: 243 | local pycmd = python_path .. ' ' .. pyfile 244 | local command = python_activate_path 245 | and python_activate_path .. ' && ' .. pycmd 246 | or pycmd 247 | os.execute(command) 248 | 249 | -- Try to open the written image: 250 | local r = io.open(outfile, 'rb') 251 | local imgData = nil 252 | 253 | -- When the image exist, read it: 254 | if r then 255 | imgData = r:read("*all") 256 | r:close() 257 | else 258 | io.stderr:write(string.format("File '%s' could not be opened", outfile)) 259 | error 'Could not create image from python code.' 260 | end 261 | 262 | -- Delete the tmp files: 263 | os.remove(pyfile) 264 | os.remove(outfile) 265 | 266 | return imgData 267 | end 268 | 269 | -- 270 | -- Asymptote 271 | -- 272 | 273 | local function asymptote(code, filetype) 274 | local convert 275 | if filetype ~= 'svg' and filetype ~= 'png' then 276 | error(string.format("Conversion to %s not implemented", filetype)) 277 | end 278 | return with_temporary_directory( 279 | "asymptote", 280 | function(tmpdir) 281 | return with_working_directory( 282 | tmpdir, 283 | function () 284 | local asy_file = "pandoc_diagram.asy" 285 | local svg_file = "pandoc_diagram.svg" 286 | local f = io.open(asy_file, 'w') 287 | f:write(code) 288 | f:close() 289 | 290 | pandoc.pipe(asymptote_path, {"-f", "svg", "-o", "pandoc_diagram", asy_file}, "") 291 | 292 | local r 293 | if filetype == 'svg' then 294 | r = io.open(svg_file, 'rb') 295 | else 296 | local png_file = "pandoc_diagram.png" 297 | convert_with_inkscape("png")(svg_file, png_file) 298 | r = io.open(png_file, 'rb') 299 | end 300 | 301 | local img_data 302 | if r then 303 | img_data = r:read("*all") 304 | r:close() 305 | else 306 | error("could not read asymptote result file") 307 | end 308 | return img_data 309 | end) 310 | end) 311 | end 312 | 313 | -- Executes each document's code block to find matching code blocks: 314 | function CodeBlock(block) 315 | -- Using a table with all known generators i.e. converters: 316 | local converters = { 317 | plantuml = plantuml, 318 | graphviz = graphviz, 319 | tikz = tikz2image, 320 | py2image = py2image, 321 | asymptote = asymptote, 322 | } 323 | 324 | -- Check if a converter exists for this block. If not, return the block 325 | -- unchanged. 326 | local img_converter = converters[block.classes[1]] 327 | if not img_converter then 328 | return nil 329 | end 330 | 331 | -- Call the correct converter which belongs to the used class: 332 | local success, img = pcall(img_converter, block.text, 333 | filetype, block.attributes["additionalPackages"] or nil) 334 | 335 | -- Bail if an error occured; img contains the error message when that 336 | -- happens. 337 | if not (success and img) then 338 | io.stderr:write(tostring(img or "no image data has been returned.")) 339 | io.stderr:write('\n') 340 | error 'Image conversion failed. Aborting.' 341 | end 342 | 343 | -- If we got here, then the transformation went ok and `img` contains 344 | -- the image data. 345 | 346 | -- Create figure name by hashing the image content 347 | local fname = pandoc.sha1(img) .. "." .. filetype 348 | 349 | -- Store the data in the media bag: 350 | pandoc.mediabag.insert(fname, mimetype, img) 351 | 352 | local enable_caption = nil 353 | 354 | -- If the user defines a caption, read it as Markdown. 355 | local caption = block.attributes.caption 356 | and pandoc.read(block.attributes.caption).blocks[1].content 357 | or {} 358 | 359 | -- A non-empty caption means that this image is a figure. We have to 360 | -- set the image title to "fig:" for pandoc to treat it as such. 361 | local title = #caption > 0 and "fig:" or "" 362 | 363 | -- Transfer identifier and other relevant attributes from the code 364 | -- block to the image. The `name` is kept as an attribute. 365 | -- This allows a figure block starting with: 366 | -- 367 | -- ```{#fig:example .plantuml caption="Image created by **PlantUML**."} 368 | -- 369 | -- to be referenced as @fig:example outside of the figure when used 370 | -- with `pandoc-crossref`. 371 | local img_attr = { 372 | id = block.identifier, 373 | name = block.attributes.name, 374 | width = block.attributes.width, 375 | height = block.attributes.height 376 | } 377 | 378 | -- Create a new image for the document's structure. Attach the user's 379 | -- caption. Also use a hack (fig:) to enforce pandoc to create a 380 | -- figure i.e. attach a caption to the image. 381 | local img_obj = pandoc.Image(caption, fname, title, img_attr) 382 | 383 | -- Finally, put the image inside an empty paragraph. By returning the 384 | -- resulting paragraph object, the source code block gets replaced by 385 | -- the image: 386 | return pandoc.Para{ img_obj } 387 | end 388 | 389 | -- Normally, pandoc will run the function in the built-in order Inlines -> 390 | -- Blocks -> Meta -> Pandoc. We instead want Meta -> Blocks. Thus, we must 391 | -- define our custom order: 392 | return { 393 | {Meta = Meta}, 394 | {CodeBlock = CodeBlock}, 395 | } 396 | -------------------------------------------------------------------------------- /dotfiles/pandoc/.local/share/pandoc/filters/include-code-files.lua: -------------------------------------------------------------------------------- 1 | --- include-code-files.lua – filter to include code from source files 2 | --- 3 | --- Copyright: © 2020 Bruno BEAUFILS 4 | --- License: MIT – see LICENSE file for details 5 | 6 | --- Dedent a line 7 | local function dedent (line, n) 8 | return line:sub(1,n):gsub(" ","") .. line:sub(n+1) 9 | end 10 | 11 | --- Filter function for code blocks 12 | local function transclude (cb) 13 | if cb.attributes.include then 14 | local content = "" 15 | local fh = io.open(cb.attributes.include) 16 | if not fh then 17 | io.stderr:write("Cannot open file " .. cb.attributes.include .. " | Skipping includes\n") 18 | else 19 | local number = 1 20 | local start = 1 21 | 22 | -- change hyphenated attributes to PascalCase 23 | for i,pascal in pairs({"startLine", "endLine"}) 24 | do 25 | local hyphen = pascal:gsub("%u", "-%0"):lower() 26 | if cb.attributes[hyphen] then 27 | cb.attributes[pascal] = cb.attributes[hyphen] 28 | cb.attributes[hyphen] = nil 29 | end 30 | end 31 | 32 | if cb.attributes.startLine then 33 | cb.attributes.startFrom = cb.attributes.startLine 34 | start = tonumber(cb.attributes.startLine) 35 | end 36 | for line in fh:lines ("L") 37 | do 38 | if cb.attributes.dedent then 39 | line = dedent(line, cb.attributes.dedent) 40 | end 41 | if number >= start then 42 | if not cb.attributes.endLine or number <= tonumber(cb.attributes.endLine) then 43 | content = content .. line 44 | end 45 | end 46 | number = number + 1 47 | end 48 | fh:close() 49 | end 50 | -- remove key-value pair for used keys 51 | cb.attributes.include = nil 52 | cb.attributes.startLine = nil 53 | cb.attributes.endLine = nil 54 | cb.attributes.dedent = nil 55 | -- return final code block 56 | return pandoc.CodeBlock(content, cb.attr) 57 | end 58 | end 59 | 60 | return { 61 | { CodeBlock = transclude } 62 | } 63 | -------------------------------------------------------------------------------- /dotfiles/pandoc/.local/share/pandoc/filters/include-files.lua: -------------------------------------------------------------------------------- 1 | --- include-files.lua – filter to include Markdown files 2 | --- 3 | --- Copyright: © 2019–2021 Albert Krewinkel 4 | --- License: MIT – see LICENSE file for details 5 | 6 | -- Module pandoc.path is required and was added in version 2.12 7 | PANDOC_VERSION:must_be_at_least '2.12' 8 | 9 | local List = require 'pandoc.List' 10 | local path = require 'pandoc.path' 11 | local system = require 'pandoc.system' 12 | 13 | --- Get include auto mode 14 | local include_auto = false 15 | function get_vars (meta) 16 | if meta['include-auto'] then 17 | include_auto = true 18 | end 19 | end 20 | 21 | --- Keep last heading level found 22 | local last_heading_level = 0 23 | function update_last_level(header) 24 | last_heading_level = header.level 25 | end 26 | 27 | --- Update contents of included file 28 | local function update_contents(blocks, shift_by, include_path) 29 | local update_contents_filter = { 30 | -- Shift headings in block list by given number 31 | Header = function (header) 32 | if shift_by then 33 | header.level = header.level + shift_by 34 | end 35 | return header 36 | end, 37 | -- If image paths are relative then prepend include file path 38 | Image = function (image) 39 | if path.is_relative(image.src) then 40 | image.src = path.normalize(path.join({include_path, image.src})) 41 | end 42 | return image 43 | end, 44 | -- Update path for include-code-files.lua filter style CodeBlocks 45 | CodeBlock = function (cb) 46 | if cb.attributes.include and path.is_relative(cb.attributes.include) then 47 | cb.attributes.include = 48 | path.normalize(path.join({include_path, cb.attributes.include})) 49 | end 50 | return cb 51 | end 52 | } 53 | 54 | return pandoc.walk_block(pandoc.Div(blocks), update_contents_filter).content 55 | end 56 | 57 | --- Filter function for code blocks 58 | local transclude 59 | function transclude (cb) 60 | -- ignore code blocks which are not of class "include". 61 | if not cb.classes:includes 'include' then 62 | return 63 | end 64 | 65 | -- Markdown is used if this is nil. 66 | local format = cb.attributes['format'] 67 | 68 | -- Attributes shift headings 69 | local shift_heading_level_by = 0 70 | local shift_input = cb.attributes['shift-heading-level-by'] 71 | if shift_input then 72 | shift_heading_level_by = tonumber(shift_input) 73 | else 74 | if include_auto then 75 | -- Auto shift headings 76 | shift_heading_level_by = last_heading_level 77 | end 78 | end 79 | 80 | --- keep track of level before recusion 81 | local buffer_last_heading_level = last_heading_level 82 | 83 | local blocks = List:new() 84 | for line in cb.text:gmatch('[^\n]+') do 85 | if line:sub(1,2) ~= '//' then 86 | local fh = io.open(line) 87 | if not fh then 88 | io.stderr:write("Cannot open file " .. line .. " | Skipping includes\n") 89 | else 90 | -- read file as the given format with global reader options 91 | local contents = pandoc.read( 92 | fh:read '*a', 93 | format, 94 | PANDOC_READER_OPTIONS 95 | ).blocks 96 | last_heading_level = 0 97 | -- recursive transclusion 98 | contents = system.with_working_directory( 99 | path.directory(line), 100 | function () 101 | return pandoc.walk_block( 102 | pandoc.Div(contents), 103 | { Header = update_last_level, CodeBlock = transclude } 104 | ) 105 | end).content 106 | --- reset to level before recursion 107 | last_heading_level = buffer_last_heading_level 108 | blocks:extend(update_contents(contents, shift_heading_level_by, 109 | path.directory(line))) 110 | fh:close() 111 | end 112 | end 113 | end 114 | return blocks 115 | end 116 | 117 | return { 118 | { Meta = get_vars }, 119 | { Header = update_last_level, CodeBlock = transclude } 120 | } 121 | -------------------------------------------------------------------------------- /dotfiles/pandoc/.local/share/pandoc/filters/pagebreak.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | pagebreak – convert raw LaTeX page breaks to other formats 3 | 4 | Copyright © 2017-2021 Benct Philip Jonsson, Albert Krewinkel 5 | 6 | Permission to use, copy, modify, and/or distribute this software for any 7 | purpose with or without fee is hereby granted, provided that the above 8 | copyright notice and this permission notice appear in all copies. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | ]] 18 | local stringify_orig = (require 'pandoc.utils').stringify 19 | 20 | local function stringify(x) 21 | return type(x) == 'string' and x or stringify_orig(x) 22 | end 23 | 24 | --- configs – these are populated in the Meta filter. 25 | local pagebreak = { 26 | asciidoc = '<<<\n\n', 27 | context = '\\page', 28 | epub = '

', 29 | html = '
', 30 | latex = '\\newpage{}', 31 | ms = '.bp', 32 | ooxml = '', 33 | odt = '' 34 | } 35 | 36 | local function pagebreaks_from_config (meta) 37 | local html_class = 38 | (meta.newpage_html_class and stringify(meta.newpage_html_class)) 39 | or os.getenv 'PANDOC_NEWPAGE_HTML_CLASS' 40 | if html_class and html_class ~= '' then 41 | pagebreak.html = string.format('
', html_class) 42 | end 43 | 44 | local odt_style = 45 | (meta.newpage_odt_style and stringify(meta.newpage_odt_style)) 46 | or os.getenv 'PANDOC_NEWPAGE_ODT_STYLE' 47 | if odt_style and odt_style ~= '' then 48 | pagebreak.odt = string.format('', odt_style) 49 | end 50 | end 51 | 52 | --- Return a block element causing a page break in the given format. 53 | local function newpage(format) 54 | if format:match 'asciidoc' then 55 | return pandoc.RawBlock('asciidoc', pagebreak.asciidoc) 56 | elseif format == 'context' then 57 | return pandoc.RawBlock('context', pagebreak.context) 58 | elseif format == 'docx' then 59 | return pandoc.RawBlock('openxml', pagebreak.ooxml) 60 | elseif format:match 'epub' then 61 | return pandoc.RawBlock('html', pagebreak.epub) 62 | elseif format:match 'html.*' then 63 | return pandoc.RawBlock('html', pagebreak.html) 64 | elseif format:match 'latex' then 65 | return pandoc.RawBlock('tex', pagebreak.latex) 66 | elseif format:match 'ms' then 67 | return pandoc.RawBlock('ms', pagebreak.ms) 68 | elseif format:match 'odt' then 69 | return pandoc.RawBlock('opendocument', pagebreak.odt) 70 | else 71 | -- fall back to insert a form feed character 72 | return pandoc.Para{pandoc.Str '\f'} 73 | end 74 | end 75 | 76 | local function is_newpage_command(command) 77 | return command:match '^\\newpage%{?%}?$' 78 | or command:match '^\\pagebreak%{?%}?$' 79 | end 80 | 81 | -- Filter function called on each RawBlock element. 82 | function RawBlock (el) 83 | -- Don't do anything if the output is TeX 84 | if FORMAT:match 'tex$' then 85 | return nil 86 | end 87 | -- check that the block is TeX or LaTeX and contains only 88 | -- \newpage or \pagebreak. 89 | if el.format:match 'tex' and is_newpage_command(el.text) then 90 | -- use format-specific pagebreak marker. FORMAT is set by pandoc to 91 | -- the targeted output format. 92 | return newpage(FORMAT) 93 | end 94 | -- otherwise, leave the block unchanged 95 | return nil 96 | end 97 | 98 | -- Turning paragraphs which contain nothing but a form feed 99 | -- characters into line breaks. 100 | function Para (el) 101 | if #el.content == 1 and el.content[1].text == '\f' then 102 | return newpage(FORMAT) 103 | end 104 | end 105 | 106 | return { 107 | {Meta = pagebreaks_from_config}, 108 | {RawBlock = RawBlock, Para = Para} 109 | } 110 | -------------------------------------------------------------------------------- /dotfiles/pandoc/.local/share/pandoc/filters/wordcount.lua: -------------------------------------------------------------------------------- 1 | -- counts words in a document 2 | 3 | words = 0 4 | characters = 0 5 | characters_and_spaces = 0 6 | process_anyway = false 7 | 8 | wordcount = { 9 | Str = function(el) 10 | -- we don't count a word if it's entirely punctuation: 11 | if el.text:match("%P") then 12 | words = words + 1 13 | end 14 | characters = characters + utf8.len(el.text) 15 | characters_and_spaces = characters_and_spaces + utf8.len(el.text) 16 | end, 17 | 18 | Space = function(el) 19 | characters_and_spaces = characters_and_spaces + 1 20 | end, 21 | 22 | Code = function(el) 23 | _,n = el.text:gsub("%S+","") 24 | words = words + n 25 | text_nospace = el.text:gsub("%s", "") 26 | characters = characters + utf8.len(text_nospace) 27 | characters_and_spaces = characters_and_spaces + utf8.len(el.text) 28 | end, 29 | 30 | CodeBlock = function(el) 31 | _,n = el.text:gsub("%S+","") 32 | words = words + n 33 | text_nospace = el.text:gsub("%s", "") 34 | characters = characters + utf8.len(text_nospace) 35 | characters_and_spaces = characters_and_spaces + utf8.len(el.text) 36 | end 37 | } 38 | 39 | -- check if the `wordcount` variable is set to `process-anyway` 40 | function Meta(meta) 41 | if meta.wordcount and (meta.wordcount=="process-anyway" 42 | or meta.wordcount=="process" or meta.wordcount=="convert") then 43 | process_anyway = true 44 | end 45 | end 46 | 47 | function Pandoc(el) 48 | -- skip metadata, just count body: 49 | pandoc.walk_block(pandoc.Div(el.blocks), wordcount) 50 | print(words .. " words in body") 51 | print(characters .. " characters in body") 52 | print(characters_and_spaces .. " characters in body (including spaces)") 53 | if not process_anyway then 54 | os.exit(0) 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /dotfiles/shell/.gitconfig: -------------------------------------------------------------------------------- 1 | [core] 2 | pager = delta 3 | 4 | [delta] 5 | syntax-theme = "Visual Studio Dark+" 6 | side-by-side = true 7 | wrap-max-lines = "unlimited" 8 | 9 | [commit] 10 | gpgsign = true 11 | -------------------------------------------------------------------------------- /dotfiles/shell/.zprofile: -------------------------------------------------------------------------------- 1 | . "$HOME/.profile" 2 | -------------------------------------------------------------------------------- /dotfiles/shell/.zshrc: -------------------------------------------------------------------------------- 1 | # History configuration 2 | HISTFILE=~/.histfile 3 | HISTSIZE=10000 4 | SAVEHIST=10000 5 | 6 | # Shell options 7 | unsetopt autocd beep 8 | bindkey -v 9 | setopt PROMPT_SUBST 10 | 11 | # Load and configure VCS (Version Control System) information 12 | autoload -Uz vcs_info 13 | 14 | # Configure VCS info style for Git repositories 15 | zstyle ':vcs_info:git:*' formats '%F{#888888} (%F{#888888}󰘬 %b)%f' 16 | 17 | # Function to set VCS information before each prompt 18 | precmd() { vcs_info } 19 | 20 | # Custom prompt including VCS information 21 | PROMPT='%n@%m:%~${vcs_info_msg_0_}%(!.#.$) ' 22 | 23 | # Completion system initialization 24 | autoload -Uz compinit 25 | compinit 26 | 27 | # Autosuggestions configuration 28 | ZSH_AUTOSUGGEST_STRATEGY=(history completion) 29 | source /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh 30 | 31 | # Key bindings: 32 | bindkey '^ ' autosuggest-accept 33 | bindkey '^P' history-beginning-search-backward 34 | bindkey '^N' history-beginning-search-forward 35 | 36 | # Redo operation in Vi command mode (using Helix redo shortcut) 37 | bindkey -M vicmd 'U' redo 38 | 39 | # Aliases 40 | alias ls="ls -ltha --color --group-directories-first --hyperlink=auto" 41 | alias tree="tree -Catr --noreport --dirsfirst --filelimit 100" 42 | alias ezrc='hx ~/.zshrc && source ~/.zshrc' 43 | alias ai="aichat" 44 | alias n="nnn" 45 | 46 | # Functions 47 | md() { 48 | filename="${1##*/}" 49 | pandoc --self-contained --metadata title="Preview" "$1" -o /tmp/"$filename".html 50 | xdg-open /tmp/"$filename".html 51 | } 52 | 53 | ghpr() { GH_FORCE_TTY=100% gh pr list --limit 300 | 54 | fzf --ansi --preview 'GH_FORCE_TTY=100% gh pr view {1}' --preview-window 'down,70%' --header-lines 3 | 55 | awk '{print $1}' | 56 | xargs gh pr checkout; } 57 | 58 | wordcount() { pandoc --lua-filter wordcount.lua "$@"; } 59 | 60 | # nnn 61 | [ -n "$NNNLVL" ] && PS1="N$NNNLVL $PS1" # prompt you are within a shell that will return you to nnn 62 | 63 | # fzf 64 | source /usr/share/doc/fzf/examples/key-bindings.zsh 65 | 66 | # zoxide 67 | eval "$(zoxide init zsh)" 68 | 69 | # aichat and aider 70 | export OPENAI_API_KEY="xxx" 71 | export TOGETHERAI_API_KEY="xxx" 72 | export TOGETHER_API_KEY="xxx" 73 | 74 | stty -ixon # disable terminal flow control 75 | -------------------------------------------------------------------------------- /dotfiles/sidplayfp/.local/share/sidplayfp/basic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/David-Else/developer-workstation-setup-script-debian/0e160829dfb03526517787e8f84dbbd282a226ae/dotfiles/sidplayfp/.local/share/sidplayfp/basic -------------------------------------------------------------------------------- /dotfiles/sidplayfp/.local/share/sidplayfp/kernal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/David-Else/developer-workstation-setup-script-debian/0e160829dfb03526517787e8f84dbbd282a226ae/dotfiles/sidplayfp/.local/share/sidplayfp/kernal -------------------------------------------------------------------------------- /extras/README.md: -------------------------------------------------------------------------------- 1 | To re-create the `nnn` deb file, follow these steps: 2 | 3 | 1. Download the following files: 4 | - [nnn_4.9.orig.tar.gz](http://deb.debian.org/debian/pool/main/n/nnn/nnn_4.9.orig.tar.gz) 5 | - [nnn_4.9-1.debian.tar.xz](http://deb.debian.org/debian/pool/main/n/nnn/nnn_4.9-1.debian.tar.xz) 6 | 7 | 2. Extract the contents of both files. 8 | 9 | 3. Copy the `debian` folder from the extracted `nnn_4.9-1.debian.tar.xz` file into the `nnn-4.9` folder inside the `nnn_4.9.orig`.folder. 10 | 11 | 4. Add a new rule to the `rules` file inside the `debian` folder: 12 | 13 | ```makefile 14 | #!/usr/bin/make -f 15 | 16 | export DEB_BUILD_MAINT_OPTIONS = hardening=+all 17 | 18 | %: 19 | dh $@ 20 | 21 | override_dh_auto_install: 22 | 23 | override_dh_auto_build: 24 | make -j8 "INSTALL=install --strip-program=true" O_NERD=1 25 | 26 | override_dh_missing: 27 | dh_missing --fail-missing 28 | ``` 29 | 30 | 5. Open the terminal and navigate to the `nnn-4.9` folder. 31 | 32 | 6. Run the command `dpkg-buildpackage -b` to build the `nnn` deb file in the parent folder. 33 | 34 | -------------------------------------------------------------------------------- /extras/_aichat: -------------------------------------------------------------------------------- 1 | #compdef aichat 2 | 3 | autoload -U is-at-least 4 | 5 | _aichat() { 6 | typeset -A opt_args 7 | typeset -a _arguments_options 8 | local ret=1 9 | 10 | if is-at-least 5.2; then 11 | _arguments_options=(-s -S -C) 12 | else 13 | _arguments_options=(-s -C) 14 | fi 15 | 16 | local context curcontext="$curcontext" state line 17 | local common=( 18 | '-m[Select a LLM model]:MODEL:->models' \ 19 | '--model[Select a LLM model]:MODEL:->models' \ 20 | '--prompt[Use the system prompt]:PROMPT: ' \ 21 | '-r[Select a role]:ROLE:->roles' \ 22 | '--role[Select a role]:ROLE:->roles' \ 23 | '-s[Start or join a session]:SESSION:->sessions' \ 24 | '--session[Start or join a session]:SESSION:->sessions' \ 25 | '--empty-session[Ensure the session is empty]' \ 26 | '--save-session[Ensure the new conversation is saved to the session]' \ 27 | '-a[Start a agent]:AGENT:->agents' \ 28 | '--agent[Start a agent]:AGENT:->agents' \ 29 | '--agent-variable[Set agent variables]' \ 30 | '--rag[Start a RAG]:RAG:->rags' \ 31 | '--rebuild-rag[Rebuild the RAG to sync document changes]' \ 32 | '--macro[Execute a macro]:MACRO:->macros' \ 33 | '--serve[Serve the LLM API and WebAPP]' \ 34 | '-e[Execute commands in natural language]' \ 35 | '--execute[Execute commands in natural language]' \ 36 | '-c[Output code only]' \ 37 | '--code[Output code only]' \ 38 | '*-f[Include files, directories, or URLs]:FILE:_files' \ 39 | '*--file[Include files, directories, or URLs]:FILE:_files' \ 40 | '-S[Turn off stream mode]' \ 41 | '--no-stream[Turn off stream mode]' \ 42 | '--dry-run[Display the message without sending it]' \ 43 | '--info[Display information]' \ 44 | '--sync-models[Sync models updates]' \ 45 | '--list-models[List all available chat models]' \ 46 | '--list-roles[List all roles]' \ 47 | '--list-sessions[List all sessions]' \ 48 | '--list-agents[List all agents]' \ 49 | '--list-rags[List all RAGs]' \ 50 | '--list-macros[List all macros]' \ 51 | '-h[Print help]' \ 52 | '--help[Print help]' \ 53 | '-V[Print version]' \ 54 | '--version[Print version]' \ 55 | '*::text -- Input text:' \ 56 | ) 57 | 58 | 59 | _arguments "${_arguments_options[@]}" $common \ 60 | && ret=0 61 | case $state in 62 | models|roles|sessions|agents|rags|macros) 63 | local -a values expl 64 | values=( ${(f)"$(_call_program values aichat --list-$state)"} ) 65 | _wanted values expl $state compadd -a values && ret=0 66 | ;; 67 | esac 68 | return ret 69 | } 70 | 71 | (( $+functions[_aichat_commands] )) || 72 | _aichat_commands() { 73 | local commands; commands=() 74 | _describe -t commands 'aichat commands' commands "$@" 75 | } 76 | 77 | if [ "$funcstack[1]" = "_aichat" ]; then 78 | _aichat "$@" 79 | else 80 | compdef _aichat aichat 81 | fi 82 | -------------------------------------------------------------------------------- /extras/compile-helix-playbook.yml: -------------------------------------------------------------------------------- 1 | - name: Install Helix 2 | hosts: localhost 3 | vars: 4 | helix_src_folder: "{{ ansible_env.HOME }}/src/helix" 5 | helix_config_folder: "{{ ansible_env.HOME }}/.config/helix" 6 | helix_git_version: "e7ac2fcdecfdbf43a4f772e7f7c163b43b3d0b9b" # 25.01.1 7 | tasks: 8 | - name: Clone Helix editor from GitHub 9 | ansible.builtin.git: 10 | repo: https://github.com/helix-editor/helix 11 | dest: "{{ helix_src_folder }}" 12 | version: "{{ helix_git_version }}" 13 | clone: true 14 | update: false 15 | register: helix_cloned 16 | 17 | - name: Install and setup Helix 18 | when: helix_cloned.changed 19 | block: 20 | - name: Install Helix 21 | ansible.builtin.shell: > 22 | cargo install --locked --path "{{ helix_src_folder }}/helix-term" 23 | 24 | - name: Create Helix editor config symlink 25 | ansible.builtin.file: 26 | src: "{{ helix_src_folder }}/runtime" 27 | dest: "{{ helix_config_folder }}/runtime" 28 | state: link 29 | 30 | - name: Ensure the icons directory exists 31 | ansible.builtin.file: 32 | path: "{{ ansible_env.HOME }}/.icons" 33 | state: directory 34 | 35 | - name: Copy Helix editor icons 36 | ansible.builtin.copy: 37 | src: "{{ helix_src_folder }}/contrib/helix.png" 38 | dest: "{{ ansible_env.HOME }}/.icons/helix.png" 39 | 40 | - name: Create Helix .desktop file 41 | ansible.builtin.copy: 42 | dest: "{{ ansible_env.HOME }}/.local/share/applications/helix.desktop" 43 | content: | 44 | [Desktop Entry] 45 | Version=1.0 46 | Type=Application 47 | Terminal=false 48 | Exec={{ ansible_env['HOME'] }}/.local/kitty.app/bin/kitty --single-instance {{ ansible_env['HOME'] }}/.cargo/bin/hx %F 49 | Name=Helix 50 | Comment=Open in Helix using the Kitty terminal 51 | Icon={{ ansible_env.HOME }}/.icons/helix.png 52 | Categories=Utility;TerminalEmulator; 53 | MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;text/html;application/toml;text/x-python;application/json;application/javascript; 54 | 55 | - name: Update the desktop database 56 | ansible.builtin.command: update-desktop-database "{{ ansible_env.HOME }}/.local/share/applications" 57 | changed_when: false 58 | -------------------------------------------------------------------------------- /extras/install-blender-playbook.yml: -------------------------------------------------------------------------------- 1 | - name: Install Blender 2 | hosts: localhost 3 | become: false 4 | vars: 5 | bin_install_dir: /usr/local/bin 6 | blender_version: 4.3.2 7 | blender_url: "https://download.blender.org/release/Blender4.3/blender-{{ blender_version }}-linux-x64.tar.xz" 8 | 9 | tasks: 10 | - name: Create directory for Blender 11 | become: true 12 | ansible.builtin.file: 13 | path: "{{ bin_install_dir }}/blender-bin" 14 | state: directory 15 | 16 | - name: Download and extract Blender 17 | become: true 18 | ansible.builtin.unarchive: 19 | src: "{{ blender_url }}" 20 | dest: "{{ bin_install_dir }}/blender-bin" 21 | remote_src: true 22 | creates: "{{ bin_install_dir }}/blender-bin/blender" 23 | extra_opts: 24 | - "--strip-components=1" 25 | 26 | - name: Create symlink to Blender binary 27 | become: true 28 | ansible.builtin.file: 29 | src: "{{ bin_install_dir }}/blender-bin/blender" 30 | dest: "{{ bin_install_dir }}/blender" 31 | state: link 32 | 33 | - name: Configure Blender desktop file 34 | block: 35 | - name: Copy Blender desktop file 36 | ansible.builtin.copy: 37 | src: "{{ bin_install_dir }}/blender-bin/blender.desktop" 38 | dest: "{{ lookup('ansible.builtin.env', 'HOME') }}/.local/share/applications/blender.desktop" 39 | 40 | - name: Create ~/.icons directory 41 | ansible.builtin.file: 42 | path: "{{ lookup('ansible.builtin.env', 'HOME') }}/.icons" 43 | state: directory 44 | 45 | - name: Copy Blender icon 46 | ansible.builtin.copy: 47 | src: "{{ bin_install_dir }}/blender-bin/blender.svg" 48 | dest: "{{ lookup('ansible.builtin.env', 'HOME') }}/.icons/blender.svg" 49 | -------------------------------------------------------------------------------- /extras/nasa-Q1p7bh3SHj8-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/David-Else/developer-workstation-setup-script-debian/0e160829dfb03526517787e8f84dbbd282a226ae/extras/nasa-Q1p7bh3SHj8-unsplash.jpg -------------------------------------------------------------------------------- /extras/nnn_4.9-1_amd64.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/David-Else/developer-workstation-setup-script-debian/0e160829dfb03526517787e8f84dbbd282a226ae/extras/nnn_4.9-1_amd64.deb -------------------------------------------------------------------------------- /extras/showmethekey-1.12.0-compiled.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/David-Else/developer-workstation-setup-script-debian/0e160829dfb03526517787e8f84dbbd282a226ae/extras/showmethekey-1.12.0-compiled.zip -------------------------------------------------------------------------------- /images/debian_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /images/sources.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/David-Else/developer-workstation-setup-script-debian/0e160829dfb03526517787e8f84dbbd282a226ae/images/sources.png -------------------------------------------------------------------------------- /install-playbook.yml: -------------------------------------------------------------------------------- 1 | - name: Install packages and configure Debian 12/13 2 | hosts: localhost 3 | vars_files: 4 | - packages.yml 5 | tasks: 6 | - name: System configuration 7 | become: true 8 | block: 9 | - name: Install and remove repository packages 10 | ansible.builtin.import_tasks: tasks/install_repo_packages.yml 11 | - name: Install GitHub packages 12 | ansible.builtin.import_tasks: tasks/install_github_packages.yml 13 | - name: Configure system settings and user environment 14 | ansible.builtin.import_tasks: tasks/configure_system_settings.yml 15 | 16 | - name: User configuration 17 | become: false 18 | block: 19 | - name: Install Python packages 20 | ansible.builtin.import_tasks: tasks/install_python_packages.yml 21 | - name: Stow dotfiles 22 | ansible.builtin.import_tasks: tasks/stow_dotfiles.yml 23 | - name: Configure Pipewire 24 | ansible.builtin.import_tasks: tasks/setup_pipewire.yml 25 | - name: Update .bashrc and .profile 26 | ansible.builtin.import_tasks: tasks/update_bashrc.yml 27 | - name: Setup Gnome 28 | ansible.builtin.import_tasks: tasks/setup-gnome.yml 29 | - name: Download and install yabridge 30 | ansible.builtin.unarchive: 31 | src: "https://github.com/robbert-vdh/yabridge/releases/download/{{ yabridge_version }}/yabridge-{{ yabridge_version }}.tar.gz" 32 | dest: "{{ ansible_env.HOME }}/.local/share" 33 | remote_src: true 34 | -------------------------------------------------------------------------------- /packages.yml: -------------------------------------------------------------------------------- 1 | bin_install_dir: /usr/local/bin 2 | pipewire_config_dir: "{{ ansible_env['HOME'] }}/.config/pipewire/" 3 | rclone_version: "1.69.2" 4 | hugo_version: "0.147.2" 5 | helix_version: "25.01.1" 6 | marksman_version: "2024-12-18" 7 | marksman_shasum: "b9cb666c643dfd9b699811fdfc445ed4c56be65c1d878c21d46847f0d7b0e475" 8 | ltex_ls_plus_version: "18.5.1" 9 | yabridge_version: "5.0.5" 10 | delta_version: "0.18.2" 11 | keyd_git_version: "v2.5.0" 12 | 13 | packages_to_remove: 14 | - cheese 15 | - evolution 16 | - gnome-games 17 | - gnome-music 18 | - gnome-software 19 | - gnome-text-editor 20 | - gnome-sound-recorder 21 | - gnome-weather 22 | - rhythmbox 23 | - totem 24 | 25 | debian_packages: 26 | - adb 27 | - android-sdk-platform-tools-common 28 | - ansible-lint 29 | - bat 30 | - borgbackup 31 | - build-essential 32 | - curl 33 | - ffmpeg 34 | - fzf 35 | - gdb 36 | - gh 37 | - gnome-boxes 38 | - gnome-shell-extension-autohidetopbar 39 | - gnome-shell-extension-auto-move-windows 40 | - gnome-tweaks 41 | - golang 42 | - handbrake 43 | - heif-gdk-pixbuf 44 | - heif-thumbnailer 45 | - imagemagick 46 | - jq 47 | - kitty 48 | - krita 49 | # - libvirt-daemon-system # dependency for gnome-boxes at least in Debian 12 50 | - lldb-19 # to supply lldb-dap-19 for Helix debugging 51 | - lshw 52 | - mediainfo 53 | - mpv 54 | - nodejs 55 | - npm 56 | - pandoc 57 | - pipx 58 | - qpwgraph 59 | - ripgrep 60 | - shellcheck 61 | - sidplayfp 62 | - shfmt 63 | - stow 64 | - trash-cli 65 | - wl-clipboard 66 | - xdg-desktop-portal-gnome 67 | - zathura 68 | - zoxide 69 | - zsh 70 | - zsh-autosuggestions 71 | 72 | debian_13_packages: 73 | - alsa-scarlett-gui 74 | - flatseal 75 | - git-delta 76 | - keepassxc-full 77 | - keyd 78 | - lazygit 79 | 80 | flatpak_packages: 81 | - com.github.polymeilex.neothesia 82 | - com.obsproject.Studio # TODO in trixie 83 | - com.obsproject.Studio.Plugin.DroidCam # TODO in trixie 84 | - io.github.flattool.Warehouse 85 | - org.signal.Signal 86 | 87 | npm_packages: 88 | - "@ansible/ansible-language-server@1.2.3" 89 | - "@tailwindcss/language-server@0.14.16" 90 | - bash-language-server@5.4.3 91 | - prettier@3.5.3 92 | - typescript-language-server@4.3.3 93 | - typescript@5.7.3 94 | - vscode-langservers-extracted@4.8.0 95 | - yaml-language-server@1.15.0 96 | 97 | python_packages: 98 | - ansi2html 99 | # - gdbgui doesn't seem to work on trixie 100 | - visidata 101 | - yt-dlp 102 | -------------------------------------------------------------------------------- /profile.sh: -------------------------------------------------------------------------------- 1 | PATH="$HOME/Documents/scripts:$HOME/go/bin:$PATH" 2 | export PATH 3 | export NNN_PLUG='i:-!|mediainfo $nnn;d:dragdrop;f:fzcd;p:preview-tui;m:mtpmount;j:autojump' 4 | export NNN_BMS="d:~/Documents;p:~/Pictures;v:~/Videos;m:~/Music;h:~/;u:/media/$USERNAME;D:~/Downloads;M:${XDG_CONFIG_HOME:-$HOME/.config}/nnn/mounts;a:/run/user/$UID/gvfs" 5 | export NNN_TRASH=1 # use trash-cli: https://pypi.org/project/trash-cli/ 6 | export NNN_FIFO=/tmp/nnn.fifo 7 | export NNN_BATTHEME="Visual Studio Dark+" 8 | export NNN_BATSTYLE="plain" 9 | export NNN_RCLONE='rclone mount --vfs-cache-mode writes' 10 | export BAT_THEME="Visual Studio Dark+" 11 | export FZF_DEFAULT_COMMAND='rg --files --hidden --follow --no-ignore-vcs -g "!{node_modules,.git,.wine}"' 12 | export EDITOR="hx" 13 | export SUDO_EDITOR="/usr/bin/hx" 14 | -------------------------------------------------------------------------------- /tasks/configure_system_settings.yml: -------------------------------------------------------------------------------- 1 | - name: Create symlinks 2 | block: 3 | - name: Gather the package facts 4 | ansible.builtin.package_facts: 5 | manager: auto 6 | 7 | - name: Create symlink for lldb-dap-19 as lldb-dap 8 | ansible.builtin.file: 9 | src: /usr/bin/lldb-dap-19 10 | dest: /usr/bin/lldb-dap 11 | state: link 12 | when: "'lldb-19' in ansible_facts.packages" 13 | 14 | - name: Create symlink for batcat as bat 15 | ansible.builtin.file: 16 | src: /usr/bin/batcat 17 | dest: /usr/local/bin/bat 18 | state: link 19 | when: "'bat' in ansible_facts.packages" 20 | 21 | - name: Create Hugo Zsh completions 22 | block: 23 | - name: Generate Hugo completion for zsh 24 | ansible.builtin.command: hugo completion zsh 25 | register: hugo_completion 26 | changed_when: false 27 | 28 | - name: Write Hugo completion to file 29 | ansible.builtin.copy: 30 | content: "{{ hugo_completion.stdout }}" 31 | dest: /usr/share/zsh/vendor-completions/_hugo 32 | 33 | - name: Switch to Zsh for the default shell 34 | ansible.builtin.user: 35 | name: "{{ lookup('ansible.builtin.env', 'USER') }}" 36 | shell: /usr/bin/zsh 37 | 38 | - name: Create default.conf for keyd 39 | ansible.builtin.copy: 40 | content: | 41 | [ids] 42 | * 43 | 44 | [main] 45 | # Maps capslock to escape when pressed and control when held. 46 | capslock = overload(control, esc) 47 | dest: /etc/keyd/default.conf 48 | 49 | - name: Add user to the pipewire group to get realtime privileges from /etc/security/limits.d/25-pw-rlimits.conf 50 | ansible.builtin.user: 51 | name: "{{ lookup('ansible.builtin.env', 'USER') }}" 52 | groups: pipewire 53 | append: true 54 | -------------------------------------------------------------------------------- /tasks/install_github_packages.yml: -------------------------------------------------------------------------------- 1 | - name: Debian 12 specific tasks 2 | when: ansible_distribution == "Debian" and ansible_distribution_major_version == "12" 3 | block: 4 | - name: Install delta 5 | ansible.builtin.apt: 6 | deb: https://github.com/dandavison/delta/releases/download/{{ delta_version }}/git-delta_{{ delta_version }}_amd64.deb 7 | 8 | - name: Install keyd from source 9 | block: 10 | - name: Clone keyd from GitHub 11 | ansible.builtin.git: 12 | repo: https://github.com/rvaiya/keyd 13 | dest: /tmp/keyd 14 | version: "{{ keyd_git_version }}" 15 | update: false 16 | 17 | - name: Ensure the keyd directory exists 18 | ansible.builtin.file: 19 | path: /etc/keyd/ 20 | state: directory 21 | 22 | - name: Build keyd 23 | community.general.make: 24 | chdir: /tmp/keyd 25 | 26 | - name: Install keyd 27 | community.general.make: 28 | chdir: /tmp/keyd 29 | target: install 30 | 31 | - name: Enable and start keyd service 32 | ansible.builtin.systemd: 33 | name: keyd 34 | enabled: true 35 | state: started 36 | 37 | - name: Clean up temporary directory 38 | ansible.builtin.file: 39 | path: "/tmp/keyd" 40 | state: absent 41 | 42 | - name: Install ltex-ls-plus with JDK 43 | block: 44 | - name: Create versioned installation directory for ltex-ls-plus 45 | ansible.builtin.file: 46 | path: "{{ bin_install_dir }}/ltex-ls-plus-{{ ltex_ls_plus_version }}" 47 | state: directory 48 | 49 | - name: Extract ltex-ls-plus 50 | ansible.builtin.unarchive: 51 | src: "https://github.com/ltex-plus/ltex-ls-plus/releases/download/{{ ltex_ls_plus_version }}/ltex-ls-plus-{{ ltex_ls_plus_version }}-linux-x64.tar.gz" 52 | dest: "{{ bin_install_dir }}/ltex-ls-plus-{{ ltex_ls_plus_version }}" 53 | remote_src: true 54 | extra_opts: 55 | - "--strip-components=2" # removes /./ltex-ls-plus-18.4.0/ 56 | - "--wildcards" 57 | - "*/bin/*" # */ is needed to deal with strange /./ structure 58 | - "*/lib/*" 59 | - "*/jdk-*/*" 60 | creates: "{{ bin_install_dir }}/ltex-ls-plus-{{ ltex_ls_plus_version }}/bin/ltex-ls-plus" 61 | 62 | - name: Create symbolic links to versioned binary 63 | ansible.builtin.file: 64 | src: "{{ bin_install_dir }}/ltex-ls-plus-{{ ltex_ls_plus_version }}/bin/ltex-ls-plus" 65 | dest: "{{ bin_install_dir }}/ltex-ls-plus" 66 | state: link 67 | force: true 68 | 69 | - name: Install executables 70 | block: 71 | - name: Install marksman 72 | ansible.builtin.get_url: 73 | url: "https://github.com/artempyanykh/marksman/releases/download/{{ marksman_version }}/marksman-linux-x64" 74 | dest: "{{ bin_install_dir }}/marksman" 75 | checksum: "sha256:{{ marksman_shasum }}" 76 | 77 | - name: Install .deb packages 78 | ansible.builtin.apt: 79 | deb: "{{ item.url }}" 80 | loop: 81 | - name: rclone 82 | url: "https://github.com/rclone/rclone/releases/download/v{{ rclone_version }}/rclone-v{{ rclone_version }}-linux-amd64.deb" 83 | - name: hugo 84 | url: "https://github.com/gohugoio/hugo/releases/download/v{{ hugo_version }}/hugo_extended_{{ hugo_version }}_linux-amd64.deb" 85 | - name: helix 86 | url: "https://github.com/helix-editor/helix/releases/download/{{ helix_version }}/helix_25.1.1-1_amd64.deb" 87 | -------------------------------------------------------------------------------- /tasks/install_python_packages.yml: -------------------------------------------------------------------------------- 1 | - name: Install packages with pipx 2 | ansible.builtin.command: pipx install {{ item }} 3 | loop: "{{ python_packages }}" 4 | args: 5 | creates: "{{ ansible_env.HOME }}/.local/pipx/venvs/{{ item }}" 6 | 7 | - name: Run pipx ensurepath 8 | ansible.builtin.command: pipx ensurepath 9 | changed_when: false 10 | -------------------------------------------------------------------------------- /tasks/install_repo_packages.yml: -------------------------------------------------------------------------------- 1 | - name: Remove unwanted desktop apps 2 | ansible.builtin.apt: 3 | name: "{{ packages_to_remove }}" 4 | state: absent 5 | autoremove: true 6 | purge: true 7 | 8 | - name: Add Flathub repository 9 | community.general.flatpak_remote: 10 | name: flathub 11 | flatpakrepo_url: https://flathub.org/repo/flathub.flatpakrepo 12 | 13 | - name: Update and upgrade all Debian packages 14 | ansible.builtin.apt: 15 | upgrade: dist 16 | update_cache: true 17 | 18 | - name: Install packages 19 | block: 20 | - name: Install Debian packages (exclude Debian 13 packages on Debian 12) 21 | ansible.builtin.apt: 22 | name: >- 23 | {{ 24 | (ansible_distribution == 'Debian' and ansible_distribution_major_version == '12') 25 | | ternary( 26 | debian_packages, 27 | debian_packages + debian_13_packages 28 | ) 29 | }} 30 | 31 | - name: Install Flatpak packages 32 | community.general.flatpak: 33 | name: "{{ flatpak_packages }}" 34 | 35 | - name: Install NPM global packages 36 | loop: "{{ npm_packages }}" 37 | community.general.npm: 38 | name: "{{ item }}" 39 | global: true 40 | 41 | - name: Install pipewire backport for Debian 12 42 | when: ansible_distribution == "Debian" and ansible_distribution_major_version == "12" 43 | block: 44 | - name: Add bookworm backports apt repository 45 | ansible.builtin.apt_repository: 46 | repo: deb http://deb.debian.org/debian bookworm-backports main 47 | 48 | - name: Install backports pipewire 49 | ansible.builtin.apt: 50 | name: pipewire 51 | state: latest 52 | default_release: bookworm-backports 53 | -------------------------------------------------------------------------------- /tasks/setup-gnome.yml: -------------------------------------------------------------------------------- 1 | - name: Enable GNOME Night Light 2 | community.general.dconf: 3 | key: "/org/gnome/settings-daemon/plugins/color/night-light-enabled" 4 | value: "true" 5 | state: present 6 | 7 | - name: Configure GNOME Auto Move Windows extension workspace rules 8 | community.general.dconf: 9 | key: "/org/gnome/shell/extensions/auto-move-windows/application-list" 10 | value: "['org.gnome.Calendar.desktop:2', 'org.signal.Signal.desktop:2', 'firefox-esr.desktop:3']" 11 | state: present 12 | -------------------------------------------------------------------------------- /tasks/setup_pipewire.yml: -------------------------------------------------------------------------------- 1 | - name: Ensure ~/.config/pipewire/ directory exists 2 | ansible.builtin.file: 3 | path: "{{ pipewire_config_dir }}" 4 | state: directory 5 | 6 | - name: Copy pipewire.conf to user's config directory 7 | ansible.builtin.copy: 8 | src: /usr/share/pipewire/pipewire.conf 9 | dest: "{{ pipewire_config_dir }}pipewire.conf" 10 | force: false 11 | 12 | - name: Update Pipewire allowed sample rates 13 | ansible.builtin.lineinfile: 14 | path: "{{ pipewire_config_dir }}pipewire.conf" 15 | regexp: '^\s*#\s*default.clock.allowed-rates\s*=' 16 | line: "default.clock.allowed-rates = [ 44100 48000 88200 96000 176400 192000 ]" 17 | backrefs: true 18 | register: samplerates_updated 19 | 20 | - name: Create pipewire group 21 | ansible.builtin.group: 22 | name: pipewire 23 | -------------------------------------------------------------------------------- /tasks/stow_dotfiles.yml: -------------------------------------------------------------------------------- 1 | - name: Create ~/.dotfiles directory 2 | ansible.builtin.file: 3 | path: "{{ ansible_env.HOME }}/.dotfiles" 4 | state: directory 5 | 6 | - name: Copy dotfiles to home directory 7 | ansible.builtin.copy: 8 | src: "{{ playbook_dir }}/dotfiles/" 9 | dest: "{{ ansible_env.HOME }}/.dotfiles/" 10 | 11 | - name: Run stow 12 | ansible.builtin.command: 13 | chdir: "{{ ansible_facts['user_dir'] }}/.dotfiles" 14 | cmd: > 15 | stow --target={{ ansible_facts['user_dir'] }} autostart helix mpv shell pandoc kitty lazygit keepassxc aichat sidplayfp marksman config 16 | --verbose=2 17 | register: result 18 | changed_when: 'result.stderr is search("LINK: ")' 19 | failed_when: 'result.rc != 0 and "Conflicting" in result.stderr' 20 | -------------------------------------------------------------------------------- /tasks/update_bashrc.yml: -------------------------------------------------------------------------------- 1 | - name: Update .bashrc by appending extra config 2 | ansible.builtin.blockinfile: 3 | block: "{{ lookup('ansible.builtin.file', 'bashrc.bash') }}" 4 | path: "{{ ansible_env.HOME }}/.bashrc" 5 | backup: true 6 | 7 | - name: Update .profile with shared environment variables for bash and zsh 8 | ansible.builtin.blockinfile: 9 | block: "{{ lookup('ansible.builtin.file', 'profile.sh') }}" 10 | path: "{{ ansible_env.HOME }}/.profile" 11 | backup: true 12 | --------------------------------------------------------------------------------