summaryrefslogtreecommitdiff
path: root/profiles
diff options
context:
space:
mode:
authorMike Vink <mike1994vink@gmail.com>2023-10-06 23:10:55 +0200
committerMike Vink <mike1994vink@gmail.com>2023-10-06 23:10:55 +0200
commitcfaef26e8718916adcc68fbfb63b15f2389b2cd2 (patch)
tree3989af4514d31d0a5cb89e8b96d51210ad7bf152 /profiles
parent654ec06ab6a885ea851c4cbf68d06a00b41b0e14 (diff)
move all the files
Diffstat (limited to 'profiles')
-rw-r--r--profiles/core/configuration.nix154
-rw-r--r--profiles/core/hm.nix24
-rw-r--r--profiles/core/home.nix242
-rw-r--r--profiles/email/gmail.nix118
-rw-r--r--profiles/email/mailsync.nix34
-rw-r--r--profiles/email/neomutt.nix198
-rw-r--r--profiles/email/notmuch.nix22
-rw-r--r--profiles/nix.nix1
-rw-r--r--profiles/station/codeium.nix58
-rw-r--r--profiles/station/kak-lsp.toml428
-rw-r--r--profiles/station/kakoune.nix35
-rw-r--r--profiles/station/meta.nix8
-rw-r--r--profiles/station/mpv.nix47
-rw-r--r--profiles/station/neovim.nix104
-rw-r--r--profiles/station/newsboat.nix83
-rw-r--r--profiles/station/packages.nix90
-rw-r--r--profiles/station/suckless.nix73
-rw-r--r--profiles/station/zathura.nix27
18 files changed, 1746 insertions, 0 deletions
diff --git a/profiles/core/configuration.nix b/profiles/core/configuration.nix
new file mode 100644
index 0000000..e677306
--- /dev/null
+++ b/profiles/core/configuration.nix
@@ -0,0 +1,154 @@
+{
+ config,
+ pkgs,
+ ...
+}: {
+ users.users.mike = {
+ isNormalUser = true;
+ extraGroups = ["wheel" "networkmanager" "docker" "transmission"];
+ };
+
+ virtualisation.docker.enable = true;
+
+ hardware.keyboard.qmk.enable = true;
+ services.udev.extraRules = ''
+ # Atmel DFU
+ ### ATmega16U2
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2fef", TAG+="uaccess"
+ ### ATmega32U2
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff0", TAG+="uaccess"
+ ### ATmega16U4
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff3", TAG+="uaccess"
+ ### ATmega32U4
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff4", TAG+="uaccess"
+ ### AT90USB64
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff9", TAG+="uaccess"
+ ### AT90USB162
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ffa", TAG+="uaccess"
+ ### AT90USB128
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ffb", TAG+="uaccess"
+
+ # Input Club
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="1c11", ATTRS{idProduct}=="b007", TAG+="uaccess"
+
+ # STM32duino
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="1eaf", ATTRS{idProduct}=="0003", TAG+="uaccess"
+ # STM32 DFU
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", TAG+="uaccess"
+
+ # BootloadHID
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05df", TAG+="uaccess"
+
+ # USBAspLoader
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", TAG+="uaccess"
+
+ # USBtinyISP
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="1782", ATTRS{idProduct}=="0c9f", TAG+="uaccess"
+
+ # ModemManager should ignore the following devices
+ # Atmel SAM-BA (Massdrop)
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="6124", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+
+ # Caterina (Pro Micro)
+ ## pid.codes shared PID
+ ### Keyboardio Atreus 2 Bootloader
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="2302", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+ ## Spark Fun Electronics
+ ### Pro Micro 3V3/8MHz
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9203", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+ ### Pro Micro 5V/16MHz
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9205", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+ ### LilyPad 3V3/8MHz (and some Pro Micro clones)
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9207", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+ ## Pololu Electronics
+ ### A-Star 32U4
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="1ffb", ATTRS{idProduct}=="0101", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+ ## Arduino SA
+ ### Leonardo
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0036", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+ ### Micro
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0037", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+ ## Adafruit Industries LLC
+ ### Feather 32U4
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000c", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+ ### ItsyBitsy 32U4 3V3/8MHz
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000d", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+ ### ItsyBitsy 32U4 5V/16MHz
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000e", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+ ## dog hunter AG
+ ### Leonardo
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="0036", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+ ### Micro
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="0037", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
+
+ # hid_listen
+ KERNEL=="hidraw*", MODE="0660", GROUP="plugdev", TAG+="uaccess", TAG+="udev-acl"
+
+ # hid bootloaders
+ ## QMK HID
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2067", TAG+="uaccess"
+ ## PJRC's HalfKay
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="0478", TAG+="uaccess"
+
+ # APM32 DFU
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="314b", ATTRS{idProduct}=="0106", TAG+="uaccess"
+
+ # GD32V DFU
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="28e9", ATTRS{idProduct}=="0189", TAG+="uaccess"
+
+ # WB32 DFU
+ SUBSYSTEMS=="usb", ATTRS{idVendor}=="342d", ATTRS{idProduct}=="dfa0", TAG+="uaccess"
+ '';
+
+ boot.loader.systemd-boot.enable = true;
+ boot.loader.efi.canTouchEfiVariables = true;
+
+ networking.hostName = "lemptop";
+ networking.networkmanager.enable = true;
+ time.timeZone = "Europe/Amsterdam";
+
+ services.xserver.enable = true;
+ services.xserver.displayManager.startx.enable = true;
+ services.xserver.libinput.enable = true;
+
+ services.udev.packages = [ pkgs.yubikey-personalization ];
+ services.pcscd.enable = true;
+ security.pam.services = {
+ login.u2fAuth = true;
+ sudo.u2fAuth = true;
+ };
+
+ sound.enable = true;
+ security.rtkit.enable = true;
+ services.pipewire = {
+ enable = true;
+ alsa.enable = true;
+ alsa.support32Bit = true;
+ pulse.enable = true;
+ };
+
+ services.transmission = {
+ enable = true;
+ };
+
+ hardware.bluetooth.enable = true;
+ services.blueman.enable = true;
+
+ programs.slock.enable = true;
+
+ documentation.dev.enable = true;
+ environment.systemPackages = with pkgs; [
+ man-pages
+ man-pages-posix
+ vim
+ wget
+ git
+ pinentry-curses
+ ];
+
+ system.stateVersion = "23.05";
+ nix.package = pkgs.nixUnstable;
+ nix.extraOptions = ''
+ experimental-features = nix-command flakes
+ '';
+}
diff --git a/profiles/core/hm.nix b/profiles/core/hm.nix
new file mode 100644
index 0000000..e1a29d6
--- /dev/null
+++ b/profiles/core/hm.nix
@@ -0,0 +1,24 @@
+{inputs, config, lib, ...}: {
+ imports = [
+ inputs.home-manager.nixosModules.default
+ (mkAliasOptionModule [ "hm" ] [ "home-manager" "users" my.username ])
+ ];
+
+ system.extraDependencies = collectFlakeInputs inputs.home-manager;
+
+ home-manager = {
+ useGlobalPkgs = true;
+ useUserPackages = true;
+ verbose = true;
+ extraSpecialArgs = { inherit inputs; };
+ };
+
+ hm = {
+ home.stateVersion = config.system.stateVersion;
+ home.enableNixpkgsReleaseCheck = false;
+
+ systemd.user.startServices = "sd-switch";
+
+ manual.html.enable = true;
+ };
+}
diff --git a/profiles/core/home.nix b/profiles/core/home.nix
new file mode 100644
index 0000000..5d57f76
--- /dev/null
+++ b/profiles/core/home.nix
@@ -0,0 +1,242 @@
+{
+ inputs,
+ config,
+ pkgs,
+ ...
+}: {
+ programs.home-manager.enable = true;
+ home.homeDirectory = "/home/${username}";
+ home.username = username;
+ home.stateVersion = "23.05";
+ fonts.fontconfig.enable = true;
+ xdg = {
+ enable = true;
+ configFile = with config.lib.meta; {
+ "emacs/init.el".source = mkMutableSymlink ./emacs/init.el;
+ };
+ mimeApps = {
+ enable = true;
+ defaultApplications = {
+ "text/x-shellscript" = ["text.desktop"];
+ "x-scheme-handler/magnet" = ["torrent.desktop"];
+ "application/x-bittorrent" = ["torrent.desktop"];
+ "x-scheme-handler/mailto" = ["mail.desktop"];
+ "text/plain" = ["text.desktop"];
+ "application/postscript" = ["pdf.desktop"];
+ "application/pdf" = ["pdf.desktop"];
+ "image/png" = ["img.desktop"];
+ "image/jpeg" = ["img.desktop"];
+ "image/gif" = ["img.desktop"];
+ "application/rss+xml" = ["rss.desktop"];
+ "video/x-matroska" = ["video.desktop"];
+ "video/mp4" = ["video.desktop"];
+ "x-scheme-handler/lbry" = ["lbry.desktop"];
+ "inode/directory" = ["file.desktop"];
+ };
+ };
+ mime.enable = true;
+ desktopEntries = {
+ text= { type = "Application"; name = "Text editor"; exec = "${pkgs.st}/bin/st -e kak %u"; };
+ file = { type = "Application"; name = "File Manager"; exec = "${pkgs.st}/bin/st -e lfub %u"; };
+ torrent = { type = "Application"; name = "Torrent"; exec = "${pkgs.coreutils}/bin/env transadd %U"; };
+ img = { type = "Application"; name = "Image Viewer"; exec = "${pkgs.sxiv}/bin/sxiv -a %u"; };
+ video = { type = "Application"; name = "Video Viewer"; exec = "${pkgs.mpv}/bin/mpv -quiet %f"; };
+ mail = { type = "Application"; name = "Mail"; exec = "${pkgs.st}/bin/st -e neomutt %u"; };
+ pdf = { type = "Application"; name = "PDF reader"; exec = "${pkgs.zathura}/bin/zathura %u"; };
+ rss = { type = "Application"; name = "RSS feed addition"; exec = "${pkgs.coreutils}/bin/env rssadd %u"; };
+ };
+ };
+
+ programs.ssh = {
+ enable = true;
+ matchBlocks = {
+ "*" = {
+ identityFile = "${config.home.homeDirectory}/.ssh/id_ed25519";
+ };
+ };
+ };
+
+ home.sessionVariables = {
+ EDITOR = "kak";
+ TERMINAL = "st";
+ };
+
+ home.sessionPath = [
+ "${config.home.homeDirectory}/.krew/bin"
+ "${config.home.homeDirectory}/.cargo/bin"
+ "${pkgs.ncurses}/bin"
+ ];
+
+ programs.starship.enable = true;
+
+ programs.direnv = {
+ enable = true;
+ nix-direnv.enable = true;
+ };
+
+ programs.readline = {
+ enable = true;
+ extraConfig = ''
+ $if mode=vi
+
+ set keymap vi-command
+ # these are for vi-command mode
+ Control-l: clear-screen
+
+ set keymap vi-insert
+ # these are for vi-insert mode
+ Control-l: clear-screen
+ $endif
+ '';
+ };
+
+ programs.emacs = {
+ enable = true;
+ package = pkgs.emacs29;
+ };
+
+ programs.tmux = {
+ enable = true;
+ extraConfig = ''
+ set-option -g default-shell ${pkgs.bashInteractive}/bin/bash
+ set -s set-clipboard on
+ setw -g mouse on
+ set -g default-terminal "st-256color"
+ set -ga terminal-overrides ",xterm-256color:Tc"
+ set-option -g focus-events on
+ set-option -sg escape-time 10
+ # unbind C-b
+ # set -g prefix C-space
+ # bind C-space send-prefix
+
+ bind-key R source ${config.xdg.configHome}/tmux/tmux.conf; display-message "sourced ${config.xdg.configHome}/tmux/tmux.conf!"
+
+ set-window-option -g mode-keys vi
+ bind-key -T copy-mode-vi v send -X begin-selection
+ bind-key -T copy-mode-vi V send -X select-line
+ bind-key -T copy-mode-vi y send -X copy-pipe-and-cancel 'xclip -in -selection clipboard'
+ bind-key -T copy-mode-vi : command-prompt
+
+ bind-key -T window k select-pane -t '{up-of}'
+ bind-key -T window j select-pane -t '{down-of}'
+ bind-key -T window l select-pane -t '{right-of}'
+ bind-key -T window h select-pane -t '{left-of}'
+ bind-key -T window = select-layout even-vertical
+ bind-key -T window o kill-pane -a
+ bind-key -T window _ resize-pane -y 90%
+ bind-key -T window n run-shell '
+ window="$(tmux display -p "#{window_name}")"
+ if [[ "''${window##kakc@}" != "$window" ]]; then
+ tmux splitw "kak -c ''${window##kakc@}"
+ else
+ tmux splitw "kak -c ''${KAK_SERVER##kaks@}"
+ fi
+ '
+ bind -n C-space switch-client -T window
+
+ bind -n C-s run-shell tmux-normal-mode
+ bind -n C-q run-shell 'tmux-normal-mode --quit'
+ '';
+ };
+
+ programs.bash = {
+ enable = true;
+ bashrcExtra = ''
+ export PATH=$PATH:$HOME/.local/bin
+ [[ -f ~/.cache/wal/sequences ]] && (cat ~/.cache/wal/sequences &)
+ unset LD_PRELOAD
+ if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
+ . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
+ fi
+ # include nix.sh if it exists
+ [[ -f ~/.nix-profile/etc/profile.d/nix.sh ]] && . ~/.nix-profile/etc/profile.d/nix.sh
+ # source some workspace specific stuff
+ [[ -f ~/env.sh ]] && . ~/env.sh
+ export COLORTERM=truecolor
+ export GPG_TTY="$(tty)"
+ export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
+ gpgconf --launch gpg-agent
+ '';
+ shellAliases = {
+ e = "kakup ";
+ es = "kakup -f";
+ k9s = "k9s";
+ k = "kubectl ";
+ d = "docker ";
+ ls = "ls --color=auto";
+ s = "sudo nixos-rebuild switch --flake ${config.home.homeDirectory}/flake#";
+ b = "/run/current-system/bin/switch-to-configuration boot";
+ h = "home-manager switch --flake ${config.home.homeDirectory}/flake --impure";
+ fa = "azdo-switch-project";
+ v = "nvim";
+ V = "nvim -S .vimsession.vim";
+ M = "xrandr --output HDMI1 --auto --output eDP1 --off";
+ m = "xrandr --output eDP1 --auto --output HDMI1 --off";
+ mM = "xrandr --output eDP1 --auto --output HDMI1 --off";
+ newflake = "nix flake new -t ~/flake ";
+ ansible-flake = "nix flake new -t ~/flake#ansible ";
+ go-flake = "nix flake new -t ~/flake#go ";
+ lock-pass = "gpgconf --kill gpg-agent";
+ };
+ };
+
+ programs.nushell.enable = true;
+
+ programs.git = {
+ enable = true;
+ userName = "Mike Vink";
+ userEmail = email;
+ extraConfig = {
+ worktree.guessRemote = true;
+ mergetool.fugitive.cmd = "vim -f -c \"Gdiff\" \"$MERGED\"";
+ merge.tool = "fugitive";
+ };
+ ignores = [
+ "/.direnv/"
+ "/.envrc"
+ "/.env"
+ ".vimsession.vim"
+ ];
+ };
+
+ # https://github.com/drduh/config/blob/master/gpg.conf
+ # https://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration-Options.html
+ # https://www.gnupg.org/documentation/manuals/gnupg/GPG-Esoteric-Options.html
+ programs.gpg = {
+ enable = true;
+ scdaemonSettings = {
+ disable-ccid = true;
+ };
+ settings = {
+ personal-cipher-preferences = "AES256 AES192 AES";
+ personal-digest-preferences = "SHA512 SHA384 SHA256";
+ personal-compress-preferences = "ZLIB BZIP2 ZIP Uncompressed";
+ default-preference-list = "SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed";
+ cert-digest-algo = "SHA512";
+ s2k-digest-algo = "SHA512";
+ s2k-cipher-algo = "AES256";
+ charset = "utf-8";
+ fixed-list-mode = true;
+ no-comments = true;
+ no-emit-version = true;
+ no-greeting = true;
+ keyid-format = "0xlong";
+ list-options = "show-uid-validity";
+ verify-options = "show-uid-validity";
+ "with-fingerprint" = true;
+ require-cross-certification = true;
+ no-symkey-cache = true;
+ use-agent = true;
+ throw-keyids = true;
+ };
+ };
+ services.gpg-agent = {
+ enable = true;
+ enableSshSupport = true;
+ defaultCacheTtl = 34550000;
+ maxCacheTtl = 34550000;
+ };
+ programs.password-store = {
+ enable = true;
+ };
+}
diff --git a/profiles/email/gmail.nix b/profiles/email/gmail.nix
new file mode 100644
index 0000000..fa5d44e
--- /dev/null
+++ b/profiles/email/gmail.nix
@@ -0,0 +1,118 @@
+{
+ inputs,
+ config,
+ pkgs,
+ ...
+}: {
+ accounts.email = {
+ maildirBasePath = "${config.xdg.dataHome}/mail";
+ accounts = {
+ gmail = {
+ primary = true;
+ realName = "Mike Vink";
+ userName = "mike1994vink@gmail.com";
+ address = "mike1994vink@gmail.com";
+ passwordCommand = ["${pkgs.pass}/bin/pass" "personal/neomutt"];
+ imap = { host = "imap.gmail.com"; port = 993; tls = { enable = true; }; };
+ smtp = { host = "smtp.gmail.com"; port = 587; tls = { enable = true; useStartTls = true; }; };
+ msmtp = {
+ enable = true;
+ };
+ neomutt = {
+ enable = true;
+ sendMailCommand = "msmtp -a gmail";
+ mailboxName = "=== mike1994vink ===";
+ extraConfig = ''
+ set spoolfile='Inbox'
+ unvirtual-mailboxes *
+ '';
+ };
+ mbsync = {
+ enable = true;
+ create = "both"; remove = "both"; expunge = "both";
+ groups = {
+ gmail = {
+ channels = {
+ Inbox = { farPattern = "INBOX"; nearPattern = "INBOX"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ Archive = { farPattern = "[Gmail]/All Mail"; nearPattern = "Archive"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ Spam = { farPattern = "[Gmail]/Spam"; nearPattern = "Spam"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ Trash = { farPattern = "[Gmail]/Bin"; nearPattern = "Trash"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ Important = { farPattern = "[Gmail]/Important"; nearPattern = "Important"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ Sent = { farPattern = "[Gmail]/Sent Mail"; nearPattern = "Sent"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ FarDrafts = { farPattern = "[Gmail]/Drafts"; nearPattern = "FarDrafts"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ };
+ };
+ };
+ };
+ notmuch = {
+ enable = true;
+ neomutt = {
+ enable = true;
+ virtualMailboxes = [
+ { name = "Inbox"; query = "folder:/gmail/ tag:inbox"; }
+ { name = "Archive"; query = "folder:/gmail/ tag:archive"; }
+ { name = "Sent"; query = "folder:/gmail/ tag:sent"; }
+ { name = "Spam"; query = "folder:/gmail/ tag:spam"; }
+ { name = "Trash"; query = "folder:/gmail/ tag:trash"; }
+ { name = "Jobs"; query = "folder:/gmail/ tag:jobs"; }
+ { name = "Houses"; query = "folder:/gmail/ tag:houses"; }
+ { name = "Development"; query = "folder:/gmail/ tag:dev"; }
+ ];
+ };
+ };
+ };
+ family = {
+ primary = false;
+ realName = "Natalia & Mike Vink";
+ userName = "natalia.mike.vink@gmail.com";
+ address = "natalia.mike.vink@gmail.com";
+ passwordCommand = ["${pkgs.pass}/bin/pass" "personal/neomutt-family"];
+ imap = { host = "imap.gmail.com"; port = 993; tls = { enable = true; }; };
+ smtp = { host = "smtp.gmail.com"; port = 587; tls = { enable = true; useStartTls = true; }; };
+ msmtp = {
+ enable = true;
+ };
+ neomutt = {
+ enable = true;
+ sendMailCommand = "msmtp -a gmail";
+ mailboxName = "=== family ===";
+ extraConfig = ''
+ set spoolfile='Inbox'
+ unvirtual-mailboxes *
+ '';
+ };
+
+ mbsync = {
+ enable = true;
+ create = "both"; remove = "both"; expunge = "both";
+ groups = {
+ family = {
+ channels = {
+ Inbox = { farPattern = "INBOX"; nearPattern = "INBOX"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ Archive = { farPattern = "[Gmail]/All Mail"; nearPattern = "Archive"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ Spam = { farPattern = "[Gmail]/Spam"; nearPattern = "Spam"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ Trash = { farPattern = "[Gmail]/Bin"; nearPattern = "Trash"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ Important = { farPattern = "[Gmail]/Important"; nearPattern = "Important"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ Sent = { farPattern = "[Gmail]/Sent Mail"; nearPattern = "Sent"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ FarDrafts = { farPattern = "[Gmail]/Drafts"; nearPattern = "FarDrafts"; extraConfig = { Create = "Near"; Expunge = "Both"; }; };
+ };
+ };
+ };
+ };
+ notmuch = {
+ enable = true;
+ neomutt = {
+ enable = true;
+ virtualMailboxes = [
+ { name = "Inbox"; query = "folder:/family/ tag:inbox"; }
+ { name = "Archive"; query = "folder:/family/ tag:archive"; }
+ { name = "Sent"; query = "folder:/family/ tag:sent"; }
+ { name = "Spam"; query = "folder:/family/ tag:spam"; }
+ { name = "Trash"; query = "folder:/family/ tag:trash"; }
+ ];
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/profiles/email/mailsync.nix b/profiles/email/mailsync.nix
new file mode 100644
index 0000000..3fcb0c5
--- /dev/null
+++ b/profiles/email/mailsync.nix
@@ -0,0 +1,34 @@
+{
+ inputs,
+ config,
+ pkgs,
+ ...
+}: {
+ programs.mbsync = {
+ enable = true;
+ };
+ systemd.user.timers.mailsync = {
+ Unit = {
+ Description = "daemon that syncs mail";
+ };
+ Timer = {
+ OnBootSec = "5m";
+ OnUnitActiveSec = "5m";
+ Unit = "mailsync.service";
+ };
+ Install = {
+ WantedBy = [ "timers.target" ];
+ };
+ };
+ systemd.user.services.mailsync = {
+ Unit = {
+ Description = "daemon that syncs mail";
+ };
+ Service = {
+ Type = "oneshot";
+ RemainAfterExit = "no";
+ ExecSearchPath = "${config.home.profileDirectory}/bin:/run/current-system/sw/bin";
+ ExecStart = "${pkgs.coreutils}/bin/env mailsync";
+ };
+ };
+}
diff --git a/profiles/email/neomutt.nix b/profiles/email/neomutt.nix
new file mode 100644
index 0000000..384173f
--- /dev/null
+++ b/profiles/email/neomutt.nix
@@ -0,0 +1,198 @@
+{
+ inputs,
+ config,
+ pkgs,
+ ...
+}: {
+ programs.msmtp = {
+ enable = true;
+ };
+
+ xdg.configFile."neomutt/mailcap" = {
+ text = ''
+ text/plain; $EDITOR %s ;
+ text/html; openfile %s ; nametemplate=%s.html
+ text/html; lynx -assume_charset=%{charset} -display_charset=utf-8 -dump -width=1024 %s; nametemplate=%s.html; copiousoutput;
+ image/*; openfile %s ;
+ video/*; setsid mpv --quiet %s &; copiousoutput
+ audio/*; mpv %s ;
+ application/pdf; openfile %s ;
+ application/pgp-encrypted; gpg -d '%s'; copiousoutput;
+ application/pgp-keys; gpg --import '%s'; copiousoutput;
+ application/x-subrip; $EDITOR %s ;
+ '';
+ };
+
+ programs.neomutt = {
+ enable = true;
+ sort = "reverse-date";
+ sidebar = {
+ enable = true;
+ };
+ extraConfig = ''
+ set use_threads=yes
+ set send_charset="us-ascii:utf-8"
+ set mailcap_path = $HOME/.config/neomutt/mailcap
+ set mime_type_query_command = "file --mime-type -b %s"
+ set date_format="%y/%m/%d %I:%M%p"
+ set index_format="%2C %Z %?X?A& ? %D %-15.15F %s (%-4.4c)"
+ set smtp_authenticators = 'gssapi:login'
+ set query_command = "abook --mutt-query '%s'"
+ set rfc2047_parameters = yes
+ set sleep_time = 0 # Pause 0 seconds for informational messages
+ set markers = no # Disables the `+` displayed at line wraps
+ set mark_old = no # Unread mail stay unread until read
+ set mime_forward = no # mail body is forwarded as text
+ set forward_attachments = yes # attachments are forwarded with mail
+ set wait_key = no # mutt won't ask "press key to continue"
+ set fast_reply # skip to compose when replying
+ set fcc_attach # save attachments with the body
+ set forward_format = "Fwd: %s" # format of subject when forwarding
+ set forward_quote # include message in forwards
+ set reverse_name # reply as whomever it was to
+ set include # include message in replies
+ set mail_check=0 # to avoid lags using IMAP with some email providers (yahoo for example)
+ auto_view text/html # automatically show html (mailcap uses lynx)
+ auto_view application/pgp-encrypted
+ #set display_filter = "tac | sed '/\\\[-- Autoview/,+1d' | tac" # Suppress autoview messages.
+ alternative_order text/plain text/enriched text/html
+
+ set sidebar_visible = yes
+ set sidebar_width = 20
+ set sidebar_short_path = yes
+ set sidebar_next_new_wrap = yes
+ set mail_check_stats
+ set sidebar_format = '%D%?F? [%F]?%* %?N?%N/? %?S?%S?'
+ bind index,pager \Ck sidebar-prev
+ bind index,pager \Cj sidebar-next
+ bind index,pager \Co sidebar-open
+ bind index,pager \Cp sidebar-prev-new
+ bind index,pager \Cn sidebar-next-new
+ bind index,pager B sidebar-toggle-visible
+
+ # Default index colors:
+ color index yellow default '.*'
+ color index_author red default '.*'
+ color index_number blue default
+ color index_subject cyan default '.*'
+
+ # New mail is boldened:
+ color index brightyellow black "~N"
+ color index_author brightred black "~N"
+ color index_subject brightcyan black "~N"
+
+ # Tagged mail is highlighted:
+ color index brightyellow blue "~T"
+ color index_author brightred blue "~T"
+ color index_subject brightcyan blue "~T"
+
+ # Flagged mail is highlighted:
+ color index brightgreen default "~F"
+ color index_subject brightgreen default "~F"
+ color index_author brightgreen default "~F"
+
+ # Other colors and aesthetic settings:
+ mono bold bold
+ mono underline underline
+ mono indicator reverse
+ mono error bold
+ color normal default default
+ color indicator brightblack white
+ color sidebar_highlight red default
+ color sidebar_divider brightblack black
+ color sidebar_flagged red black
+ color sidebar_new green black
+ color error red default
+ color tilde black default
+ color message cyan default
+ color markers red white
+ color attachment white default
+ color search brightmagenta default
+ color status brightyellow black
+ color hdrdefault brightgreen default
+ color quoted green default
+ color quoted1 blue default
+ color quoted2 cyan default
+ color quoted3 yellow default
+ color quoted4 red default
+ color quoted5 brightred default
+ color signature brightgreen default
+ color bold black default
+ color underline black default
+
+ # Regex highlighting:
+ color header brightmagenta default "^From"
+ color header brightcyan default "^Subject"
+ color header brightwhite default "^(CC|BCC)"
+ color header blue default ".*"
+ color body brightred default "[\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+" # Email addresses
+ color body brightblue default "(https?|ftp)://[\-\.,/%~_:?&=\#a-zA-Z0-9]+" # URL
+ color body green default "\`[^\`]*\`" # Green text between ` and `
+ color body brightblue default "^# \.*" # Headings as bold blue
+ color body brightcyan default "^## \.*" # Subheadings as bold cyan
+ color body brightgreen default "^### \.*" # Subsubheadings as bold green
+ color body yellow default "^(\t| )*(-|\\*) \.*" # List items as yellow
+ color body brightcyan default "[;:][-o][)/(|]" # emoticons
+ color body brightcyan default "[;:][)(|]" # emoticons
+ color body brightcyan default "[ ][*][^*]*[*][ ]?" # more emoticon?
+ color body brightcyan default "[ ]?[*][^*]*[*][ ]" # more emoticon?
+ color body red default "(BAD signature)"
+ color body cyan default "(Good signature)"
+ color body brightblack default "^gpg: Good signature .*"
+ color body brightyellow default "^gpg: "
+ color body brightyellow red "^gpg: BAD signature from.*"
+ mono body bold "^gpg: Good signature"
+ mono body bold "^gpg: BAD signature from.*"
+ color body red default "([a-z][a-z0-9+-]*://(((([a-z0-9_.!~*'();:&=+$,-]|%[0-9a-f][0-9a-f])*@)?((([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?|[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)(:[0-9]+)?)|([a-z0-9_.!~*'()$,;:@&=+-]|%[0-9a-f][0-9a-f])+)(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?(#([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?|(www|ftp)\\.(([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?(:[0-9]+)?(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?(#([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?)[^].,:;!)? \t\r\n<>\"]"
+ '';
+ binds = [
+ { map = ["index" "pager"]; key = "x"; action = "modify-labels"; }
+ { map = ["index" "pager"]; key = "i"; action = "noop"; }
+ { map = ["index" "pager"]; key = "g"; action = "noop"; }
+ { map = ["index"]; key = "\\Cf"; action = "noop"; }
+ { map = ["index" "pager"]; key = "M"; action = "noop"; }
+ { map = ["index" "pager"]; key = "C"; action = "noop"; }
+ { map = ["index"]; key = "gg"; action = "first-entry"; }
+ { map = ["index"]; key = "j"; action = "next-entry"; }
+ { map = ["index"]; key = "k"; action = "previous-entry"; }
+ { map = ["attach"]; key = "<return>"; action = "view-mailcap"; }
+ { map = ["attach"]; key = "l"; action = "view-mailcap"; }
+ { map = ["editor"]; key = "<space>"; action = "noop"; }
+ { map = ["index"]; key = "G"; action = "last-entry"; }
+ { map = ["pager" "attach"]; key = "h"; action = "exit"; }
+ { map = ["pager"]; key = "j"; action = "next-line"; }
+ { map = ["pager"]; key = "k"; action = "previous-line"; }
+ { map = ["pager"]; key = "l"; action = "view-attachments"; }
+ { map = ["index"]; key = "U"; action = "undelete-message"; }
+ { map = ["index"]; key = "L"; action = "limit"; }
+ { map = ["index"]; key = "h"; action = "noop"; }
+ { map = ["index"]; key = "l"; action = "display-message"; }
+ { map = ["index" "query"]; key = "<space>"; action = "tag-entry"; }
+ { map = ["index" "pager"]; key = "H"; action = "view-raw-message"; }
+ { map = ["browser"]; key = "l"; action = "select-entry"; }
+ { map = ["browser"]; key = "gg"; action = "top-page"; }
+ { map = ["browser"]; key = "G"; action = "bottom-page"; }
+ { map = ["pager"]; key = "gg"; action = "top"; }
+ { map = ["pager"]; key = "G"; action = "bottom"; }
+ { map = ["index" "pager" "browser"]; key = "d"; action = "half-down"; }
+ { map = ["index" "pager" "browser"]; key = "u"; action = "half-up"; }
+ { map = ["index" "pager"]; key = "\\Cr"; action = "group-reply"; }
+ { map = ["index" "pager"]; key = "R"; action = "group-chat-reply"; }
+ { map = ["index"]; key = "\031"; action = "previous-undeleted"; }
+ { map = ["index"]; key = "\005"; action = "next-undeleted"; }
+ { map = ["pager"]; key = "\031"; action = "previous-line"; }
+ { map = ["pager"]; key = "\005"; action = "next-line"; }
+ { map = ["editor"]; key = "<Tab>"; action = "complete-query"; }
+ ];
+ macros = [
+ { map = ["index"]; key = "X"; action = "<save-message>=Spam<enter>y"; }
+ { map = ["index"]; key = "A"; action = "<modify-labels-then-hide>+archive -unread -inbox<enter><mark-message>z<enter><change-folder>^<enter>'z"; }
+ { map = ["index"]; key = "h"; action = "<mark-message>z<enter><change-folder>^<enter>'z"; }
+ { map = ["index"]; key = "D"; action = "<delete-message>"; }
+ { map = ["index" "pager"]; key = "S"; action = "<sync-mailbox>!notmuch-hook &<enter>"; }
+ { map = ["index"]; key = "c"; action = "<change-vfolder>?"; }
+ { map = ["index"]; key = "\\\\"; action = "<vfolder-from-query>"; }
+ { map = ["browser"]; key = "h"; action = "<change-dir><kill-line>..<enter>"; }
+ ];
+ };
+}
diff --git a/profiles/email/notmuch.nix b/profiles/email/notmuch.nix
new file mode 100644
index 0000000..3b182c7
--- /dev/null
+++ b/profiles/email/notmuch.nix
@@ -0,0 +1,22 @@
+{
+ inputs,
+ config,
+ pkgs,
+ ...
+}: {
+ programs.notmuch = {
+ enable = true;
+ new = {
+ tags = ["new"];
+ ignore = [".mbsyncstate" ".uidvalidity"];
+ };
+ search.excludeTags = ["deleted" "spam"];
+ maildir.synchronizeFlags = true;
+ extraConfig = {
+ database.path = "${config.xdg.dataHome}/mail";
+ user.name = "Mike Vink";
+ user.primary_email = "mike1994vink@gmail.com";
+ crypto.gpg_path="gpg";
+ };
+ };
+}
diff --git a/profiles/nix.nix b/profiles/nix.nix
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/profiles/nix.nix
@@ -0,0 +1 @@
+{}
diff --git a/profiles/station/codeium.nix b/profiles/station/codeium.nix
new file mode 100644
index 0000000..f3841b3
--- /dev/null
+++ b/profiles/station/codeium.nix
@@ -0,0 +1,58 @@
+{
+ inputs,
+ config,
+ pkgs,
+ ...
+}: let
+ codeium = with pkgs; stdenv.mkDerivation rec {
+ pname = "codeium";
+ version = "1.1.39";
+
+ ls-sha = "c8fda9657259bb7f3d432c1b558db921db4257aa";
+
+ src = fetchurl {
+ url = "https://github.com/Exafunction/codeium/releases/download/language-server-v${version}/language_server_linux_x64.gz";
+ sha256 = "sha256-LA1VVW4X30a8UD9aDUCTmBKVXM7G0WE7dSsZ73TaaVo=";
+ };
+
+ nativeBuildInputs = [
+ autoPatchelfHook
+ ];
+
+ sourceRoot = ".";
+
+ unpackPhase = ''
+ cp $src language_server_linux_x64.gz
+ gzip -d language_server_linux_x64.gz
+ '';
+
+ installPhase = ''
+ install -m755 -D language_server_linux_x64 $out
+ '';
+
+ preFixup = ''
+ patchelf \
+ --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
+ $out
+ '';
+
+ meta = with lib; {
+ homepage = "https://www.codeium.com/";
+ description = "Codeium language server";
+ platforms = platforms.linux;
+ };
+ };
+in {
+ home.activation = {
+ # links codeium into place
+ codium-symlink = inputs.home-manager.lib.hm.dag.entryAfter ["writeBoundary"] ''
+ CODEIUM_TARGET="${config.home.homeDirectory}/.codeium/bin/c8fda9657259bb7f3d432c1b558db921db4257aa"
+ if [ -L $CODEIUM_TARGET ] && [ -e $CODEIUM_TARGET ]; then
+ $DRY_RUN_CMD echo "codeium linked"
+ else
+ mkdir -p $CODEIUM_TARGET
+ $DRY_RUN_CMD ln -sf ${codeium} "$CODEIUM_TARGET/language_server_linux_x64"
+ fi
+ '';
+ };
+}
diff --git a/profiles/station/kak-lsp.toml b/profiles/station/kak-lsp.toml
new file mode 100644
index 0000000..b0592cf
--- /dev/null
+++ b/profiles/station/kak-lsp.toml
@@ -0,0 +1,428 @@
+snippet_support = true
+verbosity = 2
+
+[server]
+# exit session if no requests were received during given period in seconds
+# set to 0 to disable
+timeout = 1800 # seconds = 30 minutes
+
+[language.bash]
+filetypes = ["sh"]
+roots = [".git", ".hg"]
+command = "bash-language-server"
+args = ["start"]
+
+[language.c_cpp]
+filetypes = ["c", "cpp"]
+roots = ["compile_commands.json", ".clangd", ".git", ".hg"]
+command = "clangd"
+
+[language.clojure]
+filetypes = ["clojure"]
+roots = ["project.clj", ".git", ".hg"]
+command = "clojure-lsp"
+settings_section = "_"
+[language.clojure.settings._]
+# See https://clojure-lsp.io/settings/#all-settings
+# source-paths-ignore-regex = ["resources.*", "target.*"]
+
+[language.cmake]
+filetypes = ["cmake"]
+roots = ["CMakeLists.txt", ".git", ".hg"]
+command = "cmake-language-server"
+
+[language.crystal]
+filetypes = ["crystal"]
+roots = ["shard.yml"]
+command = "crystalline"
+
+[language.css]
+filetypes = ["css"]
+roots = ["package.json", ".git", ".hg"]
+command = "vscode-css-languageserver"
+args = ["--stdio"]
+
+[language.less]
+filetypes = ["less"]
+roots = ["package.json", ".git", ".hg"]
+command = "vscode-css-languageserver"
+args = ["--stdio"]
+
+[language.scss]
+filetypes = ["scss"]
+roots = ["package.json", ".git", ".hg"]
+command = "vscode-css-languageserver"
+args = ["--stdio"]
+
+[language.d]
+filetypes = ["d", "di"]
+roots = [".git", "dub.sdl", "dub.json"]
+command = "dls"
+
+[language.dart]
+# start shell to find path to dart analysis server source
+filetypes = ["dart"]
+roots = ["pubspec.yaml", ".git", ".hg"]
+command = "sh"
+args = ["-c", "dart $(dirname $(command -v dart))/snapshots/analysis_server.dart.snapshot --lsp"]
+
+[language.elixir]
+filetypes = ["elixir"]
+roots = ["mix.exs"]
+command = "elixir-ls"
+settings_section = "elixirLS"
+[language.elixir.settings.elixirLS]
+# See https://github.com/elixir-lsp/elixir-ls/blob/master/apps/language_server/lib/language_server/server.ex
+# dialyzerEnable = true
+
+[language.elm]
+filetypes = ["elm"]
+roots = ["elm.json"]
+command = "elm-language-server"
+args = ["--stdio"]
+settings_section = "elmLS"
+[language.elm.settings.elmLS]
+# See https://github.com/elm-tooling/elm-language-server#server-settings
+runtime = "node"
+elmPath = "elm"
+elmFormatPath = "elm-format"
+elmTestPath = "elm-test"
+
+[language.elvish]
+filetypes = ["elvish"]
+roots = [".git", ".hg"]
+command = "elvish"
+args = ["-lsp"]
+
+[language.erlang]
+filetypes = ["erlang"]
+# See https://github.com/erlang-ls/erlang_ls.git for more information and
+# how to configure. This default config should work in most cases though.
+roots = ["rebar.config", "erlang.mk", ".git", ".hg"]
+command = "erlang_ls"
+
+[language.go]
+filetypes = ["go"]
+roots = ["Gopkg.toml", "go.mod", ".git", ".hg"]
+command = "gopls"
+settings_section = "gopls"
+[language.go.settings.gopls]
+# See https://github.com/golang/tools/blob/master/gopls/doc/settings.md
+# "build.buildFlags" = []
+
+[language.haskell]
+filetypes = ["haskell"]
+roots = ["hie.yaml", "cabal.project", "Setup.hs", "stack.yaml", "*.cabal"]
+command = "haskell-language-server-wrapper"
+args = ["--lsp"]
+settings_section = "_"
+[language.haskell.settings._]
+# See https://haskell-language-server.readthedocs.io/en/latest/configuration.html
+# haskell.formattingProvider = "ormolu"
+
+[language.html]
+filetypes = ["html"]
+roots = ["package.json"]
+command = "vscode-html-languageserver"
+args = ["--stdio"]
+
+# # Commented out by default because you still need to set the paths in the JDT
+# # Language Server arguments below before this can become a valid configuration.
+# [language.java]
+# filetypes = ["java"]
+# roots = [".git", "mvnw", "gradlew"]
+# command = "java"
+# args = [
+# "-Declipse.application=org.eclipse.jdt.ls.core.id1",
+# "-Dosgi.bundles.defaultStartLevel=4",
+# "-Declipse.product=org.eclipse.jdt.ls.core.product",
+# "-Dlog.level=ALL",
+# "-Dfile.encoding=utf-8",
+# "--add-modules=ALL-SYSTEM",
+# "--add-opens",
+# "java.base/java.util=ALL-UNNAMED",
+# "--add-opens",
+# "java.base/java.lang=ALL-UNNAMED",
+# "-noverify",
+# "-Xmx1G",
+# "-jar",
+# "/path/to/eclipse.jdt.ls/repository/plugins/org.eclipse.equinox.launcher_1.6.100.v20201223-0822.jar",
+# "-configuration",
+# "/path/to/eclipse.jdt.ls/repository/config_linux",
+# "-data",
+# "/path/to/eclipse-workspace",
+# ]
+# [language.java.settings]
+# # See https://github.dev/eclipse/eclipse.jdt.ls
+# # "java.format.insertSpaces" = true
+
+[language.jsx] # works for javascript as well
+filetypes = ["javascript"]
+roots = ["package.json", "tsconfig.json", ".git", ".hg"]
+command = "typescript-language-server"
+args = ["--stdio"]
+
+[language.json]
+filetypes = ["json"]
+roots = ["package.json"]
+command = "vscode-json-languageserver"
+args = ["--stdio"]
+
+# Requires Julia package "LanguageServer"
+# Run: `julia --project=@kak-lsp -e 'import Pkg; Pkg.add("LanguageServer")'` to install it
+# Configuration adapted from https://github.com/neovim/nvim-lspconfig/blob/bcebfac7429cd8234960197dca8de1767f3ef5d3/lua/lspconfig/julials.lua
+[language.julia]
+filetypes = ["julia"]
+roots = ["Project.toml", ".git", ".hg"]
+command = "julia"
+args = [
+ "--startup-file=no",
+ "--history-file=no",
+ "-e",
+ """
+ ls_install_path = joinpath(get(DEPOT_PATH, 1, joinpath(homedir(), ".julia")), "environments", "kak-lsp");
+ pushfirst!(LOAD_PATH, ls_install_path);
+ using LanguageServer;
+ popfirst!(LOAD_PATH);
+ depot_path = get(ENV, "JULIA_DEPOT_PATH", "");
+ buffer_file = ENV["kak_buffile"];
+ project_path = let
+ dirname(something(
+ # 1. Check if there is an explicitly set project
+ Base.load_path_expand((
+ p = get(ENV, "JULIA_PROJECT", nothing);
+ p === nothing ? nothing : isempty(p) ? nothing : p
+ )),
+ # 2. Check for Project.toml in current working directory
+ Base.current_project(pwd()),
+ # 3. Check for Project.toml from buffer's full file path excluding the file name
+ Base.current_project(dirname(buffer_file)),
+ # 4. Fallback to global environment
+ Base.active_project()
+ ))
+ end
+ server = LanguageServer.LanguageServerInstance(stdin, stdout, project_path, depot_path);
+ server.runlinter = true;
+ run(server);
+ """,
+]
+[language.julia.settings]
+# See https://github.com/julia-vscode/LanguageServer.jl/blob/master/src/requests/workspace.jl
+# Format options. See https://github.com/julia-vscode/DocumentFormat.jl/blob/master/src/DocumentFormat.jl
+# "julia.format.indent" = 4
+# Lint options. See https://github.com/julia-vscode/StaticLint.jl/blob/master/src/linting/checks.jl
+# "julia.lint.call" = true
+# Other options, see https://github.com/julia-vscode/LanguageServer.jl/blob/master/src/requests/workspace.jl
+# "julia.lint.run" = "true"
+
+[language.latex]
+filetypes = ["latex"]
+roots = [".git", ".hg"]
+command = "texlab"
+settings_section = "texlab"
+[language.latex.settings.texlab]
+# See https://github.com/latex-lsp/texlab/wiki/Configuration
+#
+# Preview configuration for zathura with SyncTeX search.
+# For other PDF viewers see https://github.com/latex-lsp/texlab/wiki/Previewing
+forwardSearch.executable = "zathura"
+forwardSearch.args = [
+ "%p",
+ "--synctex-forward", # Support texlab-forward-search
+ "%l:1:%f",
+ "--synctex-editor-command", # Inverse search: use Control+Left-Mouse-Button to jump to source.
+ """
+ sh -c '
+ echo "
+ evaluate-commands -client %opt{texlab_client} %{
+ evaluate-commands -try-client %opt{jumpclient} %{
+ edit -- %{input} %{line}
+ }
+ }
+ " | kak -p $kak_session
+ '
+ """,
+]
+
+[language.lua]
+filetypes = ["lua"]
+roots = [".git", ".hg"]
+command = "lua-language-server"
+[language.lua.settings.Lua]
+# See https://github.com/sumneko/vscode-lua/blob/master/setting/schema.json
+# diagnostics.enable = true
+
+[language.nim]
+filetypes = ["nim"]
+roots = ["*.nimble", ".git", ".hg"]
+command = "nimlsp"
+
+[language.nix]
+filetypes = ["nix"]
+roots = ["flake.nix", "shell.nix", ".git", ".hg"]
+command = "rnix-lsp"
+
+[language.ocaml]
+filetypes = ["ocaml"]
+# Often useful to simply do a `touch dune-workspace` in your project root folder if you have problems with root detection
+roots = ["dune-workspace", "dune-project", "Makefile", "opam", "*.opam", "esy.json", ".git", ".hg", "dune"]
+command = "ocamllsp"
+
+[language.php]
+filetypes = ["php"]
+roots = [".htaccess", "composer.json"]
+command = "intelephense"
+args = ["--stdio"]
+settings_section = "intelephense"
+[language.php.settings]
+intelephense.storagePath = "/tmp/intelephense"
+
+[language.proto]
+filetypes = ["protobuf"]
+roots = [".git", ".hg"]
+command = "pls" # https://github.com/lasorda/protobuf-language-server
+
+[language.python]
+filetypes = ["python"]
+roots = ["requirements.txt", "setup.py", ".git", ".hg"]
+command = "pyright-langserver"
+args = ["--stdio"]
+settings_section = "_"
+[language.python.settings.python.analysis]
+autoSearchPaths = true
+diagnosticMode = "workspace"
+useLibraryCodeForTypes = true
+
+
+[language.r]
+filetypes = ["r"]
+roots = ["DESCRIPTION", ".git", ".hg"]
+command = "R"
+args = ["--slave", "-e", "languageserver::run()"]
+
+[language.racket]
+filetypes = ["racket"]
+roots = ["info.rkt"]
+command = "racket"
+args = ["-l", "racket-langserver"]
+
+[language.reason]
+filetypes = ["reason"]
+roots = ["package.json", "Makefile", ".git", ".hg"]
+command = "ocamllsp"
+
+[language.ruby]
+filetypes = ["ruby"]
+roots = ["Gemfile"]
+command = "solargraph"
+args = ["stdio"]
+settings_section = "_"
+[language.ruby.settings._]
+# See https://github.com/castwide/solargraph/blob/master/lib/solargraph/language_server/host.rb
+# diagnostics = false
+
+# [language.rust]
+# filetypes = ["rust"]
+# roots = ["Cargo.toml"]
+# command = "sh"
+# args = [
+# "-c",
+# """
+# if path=$(rustup which rls 2>/dev/null); then
+# "$path"
+# else
+# rls
+# fi
+# """,
+# ]
+# [language.rust.settings.rust]
+# # See https://github.com/rust-lang/rls#configuration
+# # features = []
+
+[language.rust]
+filetypes = ["rust"]
+roots = ["Cargo.toml"]
+command = "sh"
+args = [
+ "-c",
+ """
+ if path=$(rustup which rust-analyzer 2>/dev/null); then
+ "$path"
+ else
+ rust-analyzer
+ fi
+ """,
+]
+settings_section = "rust-analyzer"
+[language.rust.settings.rust-analyzer]
+# See https://rust-analyzer.github.io/manual.html#configuration
+hoverActions.enable = false # kak-lsp doesn't support this at the moment
+# cargo.features = []
+
+[language.terraform]
+filetypes = ["terraform"]
+roots = ["*.tf"]
+command = "terraform-ls"
+args = ["serve"]
+[language.terraform.settings.terraform-ls]
+# See https://github.com/hashicorp/terraform-ls/blob/main/docs/SETTINGS.md
+# rootModulePaths = []
+
+[language.tsx] # works for typescript as well
+filetypes = ["typescript"]
+roots = ["package.json", "tsconfig.json", ".git", ".hg"]
+command = "typescript-language-server"
+args = ["--stdio"]
+
+# [language.typescript]
+# filetypes = ["typescript"]
+# roots = ["package.json", "tsconfig.json", ".git", ".hg"]
+# command = "deno"
+# args = ["lsp"]
+# [language.typescript.settings.deno]
+# enable = true
+# lint = true
+
+[language.yaml]
+filetypes = ["yaml"]
+roots = [".git", ".hg"]
+command = "yaml-language-server"
+args = ["--stdio"]
+[language.yaml.settings]
+# See https://github.com/redhat-developer/yaml-language-server#language-server-settings
+# Defaults are at https://github.com/redhat-developer/yaml-language-server/blob/master/src/yamlSettings.ts
+# yaml.format.enable = true
+
+[language.zig]
+filetypes = ["zig"]
+roots = ["build.zig"]
+command = "zls"
+
+[language.cs]
+filetypes = ["cs"]
+roots = [".git"]
+command = "OmniSharp"
+args = ["--encoding", "utf-8", "-z", "--languageserver", "DotNet:enablePackageRestore=false", "FormattingOptions:EnableEditorConfigSupport=true", "Sdk:IncludePrereleases=true"]
+
+# Semantic tokens support
+# See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_semanticTokens
+# for the default list of tokens and modifiers.
+# However, many language servers implement their own values.
+# Make sure to check the output of `lsp-capabilities` and each server's documentation and source code as well.
+# Examples:
+# - TypeScript: https://github.com/microsoft/vscode-languageserver-node/blob/main/client/src/common/semanticTokens.ts
+# - Rust Analyzer: https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ide/src/syntax_highlighting.rs
+[semantic_tokens]
+faces = [
+ {face="documentation", token="comment", modifiers=["documentation"]},
+ {face="comment", token="comment"},
+ {face="function", token="function"},
+ {face="keyword", token="keyword"},
+ {face="module", token="namespace"},
+ {face="operator", token="operator"},
+ {face="string", token="string"},
+ {face="type", token="type"},
+ {face="default+d", token="variable", modifiers=["readonly"]},
+ {face="default+d", token="variable", modifiers=["constant"]},
+ {face="variable", token="variable"},
+]
diff --git a/profiles/station/kakoune.nix b/profiles/station/kakoune.nix
new file mode 100644
index 0000000..41caf9f
--- /dev/null
+++ b/profiles/station/kakoune.nix
@@ -0,0 +1,35 @@
+{
+ inputs,
+ flake,
+ config,
+ pkgs,
+ ...
+}:
+ let
+ kakouneWithPlugins = pkgs.wrapKakoune pkgs.kakoune-unwrapped { configure = { plugins = with pkgs.kakounePlugins; [kak-lsp parinfer-rust]; }; };
+ in {
+ home.packages = [kakouneWithPlugins];
+ home.activation = {
+ kakoune-symlink = inputs.home-manager.lib.hm.dag.entryAfter ["writeBoundary"] ''
+ KAK_CONFIG="${config.home.homeDirectory}/kakoune"
+ XDG_CONFIG_HOME_KAK="${config.xdg.configHome}/kak"
+ if [ -L $XDG_CONFIG_HOME_KAK ] && [ -e $XDG_CONFIG_HOME_KAK ]; then
+ $DRY_RUN_CMD echo "kakoune linked"
+ else
+ $DRY_RUN_CMD ln -s $KAK_CONFIG $XDG_CONFIG_HOME_KAK
+ fi
+ rm -rf $XDG_CONFIG_HOME_KAK/autoload/default
+ ln -sf ${kakouneWithPlugins}/share/kak/autoload $XDG_CONFIG_HOME_KAK/autoload/default
+ '';
+ };
+ home.file."${config.xdg.configHome}/kak-lsp/kak-lsp.toml" = {
+ source = ./kak-lsp.toml;
+ };
+
+ #set global windowing_modules ""
+ #require-module tmux
+ #require-module tmux-repl
+ #alias global terminal tmux-terminal-vertical
+ #alias global sp new
+
+}
diff --git a/profiles/station/meta.nix b/profiles/station/meta.nix
new file mode 100644
index 0000000..e6f3a78
--- /dev/null
+++ b/profiles/station/meta.nix
@@ -0,0 +1,8 @@
+{inputs,lib,config, ...}: with lib; {
+ lib.meta = {
+ configPath = "${config.home.homeDirectory}/flake";
+ mkMutableSymlink = path:
+ config.lib.file.mkOutOfStoreSymlink
+ (config.lib.meta.configPath + removePrefix (toString inputs.self) (toString path));
+ };
+}
diff --git a/profiles/station/mpv.nix b/profiles/station/mpv.nix
new file mode 100644
index 0000000..1b673ab
--- /dev/null
+++ b/profiles/station/mpv.nix
@@ -0,0 +1,47 @@
+
+{
+ flake,
+ config,
+ pkgs,
+ ...
+}: {
+ programs.mpv = {
+ enable = true;
+ scripts = [
+ (with pkgs; stdenv.mkDerivation rec {
+ pname = "mpv-sockets";
+ version = "1.0";
+
+ src = fetchFromGitHub {
+ owner = "wis";
+ repo = "mpvSockets";
+ rev = "be9b7ca84456466e54331bab59441ac207659c1c";
+ sha256 = "sha256-tcY+cHvkQpVNohZ9yHpVlq0bU7iiKMxeUsO/BRwGzAs=";
+ };
+
+ # installFlags = [ "SCRIPTS_DIR=$(out)/share/mpv/scripts" ];
+ passthru.scriptName = "mpvSockets.lua";
+ installPhase = ''
+ install -m755 -D mpvSockets.lua $out/share/mpv/scripts/mpvSockets.lua
+ '';
+
+ meta = with lib; {
+ description = "mpvSockets lua module for mpv";
+ homepage = "https://github.com/wis/mpvSockets";
+ license = licenses.mit;
+ platforms = platforms.linux;
+ };
+ })
+ ];
+ config = {
+ gpu-context = "drm";
+ };
+ bindings = {
+ l="seek 5";
+ h="seek -5";
+ j="seek -60";
+ k="seek 60";
+ S="cycle sub";
+ };
+ };
+}
diff --git a/profiles/station/neovim.nix b/profiles/station/neovim.nix
new file mode 100644
index 0000000..8957c89
--- /dev/null
+++ b/profiles/station/neovim.nix
@@ -0,0 +1,104 @@
+{
+ inputs,
+ config,
+ pkgs,
+ ...
+}: {
+ home.activation = {
+ # fixes hotpot cannot be found error after updates
+ clearHotpotCache = inputs.home-manager.lib.hm.dag.entryAfter ["writeBoundary"] ''
+ HOTPOT_CACHE="${config.xdg.cacheHome}/nvim/hotpot"
+ if [[ -d "$HOTPOT_CACHE" ]]; then
+ $DRY_RUN_CMD rm -rf "$VERBOSE_ARG" "$HOTPOT_CACHE"
+ fi
+ '';
+ };
+
+ xdg = {
+ configFile = with config.lib.meta; {
+ "nvim".source = mkMutableSymlink ../neovim;
+ };
+ };
+
+ editorconfig = {
+ enable = true;
+ settings = {
+ "*" = {
+ trim_trailing_whitespace = true;
+ insert_final_newline = true;
+ };
+ "*.yaml" = {
+ indent_style = "space";
+ indent_size = 2;
+ };
+ };
+ };
+
+ programs.neovim = {
+ enable = true;
+ package = pkgs.neovim-unwrapped;
+ viAlias = true;
+ vimAlias = true;
+ extraPackages = with pkgs; [
+ bashInteractive
+ sumneko-lua-language-server
+ pyright
+ gopls
+ fennel
+ fnlfmt
+ alejandra
+ statix
+ ];
+ plugins = with pkgs.vimPlugins; [
+ # highlighting
+ nvim-treesitter.withAllGrammars
+ nvim-treesitter-context
+ playground
+ gruvbox-material
+ kanagawa-nvim
+ lsp_lines-nvim
+ heirline-nvim
+ gitsigns-nvim
+ noice-nvim
+ nui-nvim
+ vim-helm
+
+ # external
+ git-worktree-nvim
+ vim-dirvish
+ vim-fugitive
+ vim-dispatch
+ vim-oscyank
+ venn-nvim
+ gv-vim
+
+ # Coding
+ plenary-nvim
+ telescope-nvim
+ nvim-lspconfig
+ null-ls-nvim
+ lsp_signature-nvim
+ omnisharp-extended-lsp-nvim
+ nvim-dap
+ nvim-dap-ui
+ luasnip
+ vim-test
+ vim-rest-console
+ harpoon
+
+ # cmp
+ nvim-cmp
+ cmp-cmdline
+ cmp-nvim-lsp
+ cmp-buffer
+ cmp-path
+ cmp_luasnip
+
+ # trying out lisp
+ conjure
+ vim-racket
+ nvim-parinfer
+ hotpot-nvim
+ ];
+ };
+}
diff --git a/profiles/station/newsboat.nix b/profiles/station/newsboat.nix
new file mode 100644
index 0000000..fc47060
--- /dev/null
+++ b/profiles/station/newsboat.nix
@@ -0,0 +1,83 @@
+{...}: {
+ programs.newsboat = {
+ enable = true;
+ autoReload = true;
+ urls = [
+ {url = "https://github.com/neovim/neovim/releases.atom";}
+ {url = "https://github.com/rancher/rancher/releases.atom";}
+ {url = "https://github.com/istio/istio/releases.atom";}
+ {url = "https://github.com/argoproj/argo-cd/releases.atom";}
+ {url = "https://github.com/argoproj/argo-cd/releases.atom";}
+ {url = "https://github.com/kyverno/kyverno/releases.atom";}
+ {url = "https://github.com/hashicorp/terraform/releases.atom";}
+ {url = "https://github.com/ansible/ansible/releases.atom";}
+ {url = "https://github.com/ansible/awx/releases.atom";}
+ {url = "https://kubeshark.co/rss.xml";}
+ {url = "https://azurecomcdn.azureedge.net/en-us/updates/feed/?product=azure-devops";}
+ {url = "https://www.hashicorp.com/blog/categories/products-technology/feed.xml";}
+ {url = "https://kubernetes.io/feed.xml";}
+ {url = "https://www.cncf.io/rss";}
+ {url = "https://blog.alexellis.io/rss/";}
+ {url = "https://www.openfaas.com/feed";}
+ {url = "https://istio.io/latest/blog/feed.xml";}
+ {url = "https://www.youtube.com/feeds/videos.xml?channel_id=UCUyeluBRhGPCW4rPe_UvBZQ";}
+ ];
+ extraConfig = ''
+ #show-read-feeds no
+ auto-reload yes
+
+ external-url-viewer "urlscan -dc -r 'linkhandler {}'"
+
+ bind-key j down
+ bind-key k up
+ bind-key j next articlelist
+ bind-key k prev articlelist
+ bind-key J next-feed articlelist
+ bind-key K prev-feed articlelist
+ bind-key G end
+ bind-key g home
+ bind-key d pagedown
+ bind-key u pageup
+ bind-key l open
+ bind-key h quit
+ bind-key a toggle-article-read
+ bind-key n next-unread
+ bind-key N prev-unread
+ bind-key D pb-download
+ bind-key U show-urls
+ bind-key x pb-delete
+
+ color listnormal cyan default
+ color listfocus black yellow standout bold
+ color listnormal_unread blue default
+ color listfocus_unread yellow default bold
+ color info red black bold
+ color article white default bold
+
+ browser linkhandler
+ macro , open-in-browser
+ macro t set browser "qndl" ; open-in-browser ; set browser linkhandler
+ macro a set browser "tsp yt-dlp --embed-metadata -xic -f bestaudio/best --restrict-filenames" ; open-in-browser ; set browser linkhandler
+ macro v set browser "setsid -f mpv" ; open-in-browser ; set browser linkhandler
+ macro w set browser "lynx" ; open-in-browser ; set browser linkhandler
+ macro d set browser "dmenuhandler" ; open-in-browser ; set browser linkhandler
+ macro c set browser "echo %u | xclip -r -sel c" ; open-in-browser ; set browser linkhandler
+ macro C set browser "youtube-viewer --comments=%u" ; open-in-browser ; set browser linkhandler
+ macro p set browser "peertubetorrent %u 480" ; open-in-browser ; set browser linkhandler
+ macro P set browser "peertubetorrent %u 1080" ; open-in-browser ; set browser linkhandler
+
+ highlight all "---.*---" yellow
+ highlight feedlist ".*(0/0))" black
+ highlight article "(^Feed:.*|^Title:.*|^Author:.*)" cyan default bold
+ highlight article "(^Link:.*|^Date:.*)" default default
+ highlight article "https?://[^ ]+" green default
+ highlight article "^(Title):.*$" blue default
+ highlight article "\\[[0-9][0-9]*\\]" magenta default bold
+ highlight article "\\[image\\ [0-9]+\\]" green default bold
+ highlight article "\\[embedded flash: [0-9][0-9]*\\]" green default bold
+ highlight article ":.*\\(link\\)$" cyan default
+ highlight article ":.*\\(image\\)$" blue default
+ highlight article ":.*\\(embedded flash\\)$" magenta default
+ '';
+ };
+}
diff --git a/profiles/station/packages.nix b/profiles/station/packages.nix
new file mode 100644
index 0000000..02c5b8e
--- /dev/null
+++ b/profiles/station/packages.nix
@@ -0,0 +1,90 @@
+{
+ flake,
+ config,
+ pkgs,
+ username,
+ ...
+}: let
+ core-packages = with pkgs;
+ [
+ # nixopsnixops
+ age
+ sops
+ # k8s and friends
+ kubernetes-helm
+ kubectl
+ kind
+ krew
+ jq
+ yq-go
+ dasel
+ initool
+ python311Packages.editorconfig
+ gnutls
+ # other stuff
+ coreutils
+ dnsutils
+ iputils
+ inetutils
+ usbutils
+ gcc
+ pkgsi686Linux.glibc
+ gnumake
+ raylib
+ gdb
+ maim
+ calcurse
+ profanity
+ file
+ lf
+ ueberzug
+ mypaint
+ lynx
+ pstree
+ pywal
+ bashInteractive
+ k9s
+ powershell
+ azure-cli
+ htop
+ subversion
+ ripgrep
+ gnused
+ gnugrep
+ curl
+ inotify-tools
+ alejandra
+ statix
+ fzf
+ github-cli
+ lazygit
+ fd
+ argocd
+ parallel
+ bc
+ sxiv
+ nushell
+ sent
+ ]
+ ++ (import ../shell-scripts.nix {inherit pkgs config;});
+ mike-extra-packages = with pkgs; [
+ (nerdfonts.override {fonts = ["FiraCode"];})
+ noto-fonts
+ noto-fonts-emoji
+ docker
+ k9s
+ dmenu
+ librewolf
+ firefox-wayland
+ xclip
+ libreoffice
+ ];
+in {
+ home.packages =
+ core-packages
+ ++ (
+ if (username == "mike")
+ then mike-extra-packages
+ else []
+ );
+}
diff --git a/profiles/station/suckless.nix b/profiles/station/suckless.nix
new file mode 100644
index 0000000..d10414d
--- /dev/null
+++ b/profiles/station/suckless.nix
@@ -0,0 +1,73 @@
+{
+ flake,
+ config,
+ pkgs,
+ suckless,
+ ...
+}: let
+in {
+ xsession = {
+ enable = true;
+ initExtra = ''
+ ${pkgs.xorg.xmodmap}/bin/xmodmap -e "remove mod1 = Alt_R"
+ ${pkgs.xorg.xmodmap}/bin/xmodmap -e "add mod3 = Alt_R"
+ wal -R
+ dwm
+ dwmblocks &
+ '';
+ };
+ services.picom = {
+ enable = true;
+ activeOpacity = 0.99;
+ inactiveOpacity = 0.7;
+ opacityRules = [
+ "100:class_g = 'dwm'"
+ "100:name *= 'Firefox'"
+ "100:name *= 'mpv'"
+ "100:name *= 'LibreWolf'"
+ ];
+ settings = {
+ inactive-opacity-override = false;
+ frame-opacity = 1;
+ };
+ };
+ services.dunst = {
+ enable = true;
+ settings = {
+ global = {
+ monitor = 0;
+ follow = "keyboard";
+ width = 370;
+ height = 350;
+ offset = "0x19";
+ padding = 2;
+ horizontal_padding = 2;
+ transparency = 25;
+ font = "Monospace 12";
+ format = "<b>%s</b>\\n%b";
+ };
+ urgency_low = {
+ background = "#1d2021";
+ foreground = "#928374";
+ timeout = 3;
+ };
+ urgency_normal = {
+ foreground = "#ebdbb2";
+ background = "#458588";
+ timeout = 5;
+ };
+ urgency_critical = {
+ background = "#1cc24d";
+ foreground = "#ebdbb2";
+ frame_color = "#fabd2f";
+ timeout = 10;
+ };
+ };
+ };
+ home.packages = with pkgs; [
+ st
+ dwm
+ dwmblocks
+ libnotify
+ ];
+}
diff --git a/profiles/station/zathura.nix b/profiles/station/zathura.nix
new file mode 100644
index 0000000..198f039
--- /dev/null
+++ b/profiles/station/zathura.nix
@@ -0,0 +1,27 @@
+{
+ flake,
+ config,
+ pkgs,
+ ...
+}: {
+ programs.zathura = {
+ enable = true;
+ extraConfig = ''
+ set sandbox none
+ set statusbar-h-padding 0
+ set statusbar-v-padding 0
+ set page-padding 1
+ set selection-clipboard clipboard
+ map u scroll half-up
+ map d scroll half-down
+ map D toggle_page_mode
+ map r reload
+ map R rotate
+ map K zoom in
+ map J zoom out
+ map i recolor
+ map p print
+ map g goto top
+ '';
+ };
+}