From 4a3d2a8ddaf4e546df360656bc54b2947bdb890b Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Sun, 3 Jan 2021 00:55:29 +0100 Subject: gkleen@sif: import --- accounts/gkleen@sif.nix | 1 - accounts/gkleen@sif/autorandr-profiles/bstr.nix | 21 + accounts/gkleen@sif/autorandr-profiles/default.nix | 13 + accounts/gkleen@sif/backup-patterns | 24 + accounts/gkleen@sif/default.nix | 181 +++ accounts/gkleen@sif/dunst-settings.nix | 64 + accounts/gkleen@sif/emacs.el | 99 ++ accounts/gkleen@sif/firefox-chrome.css | 25 + accounts/gkleen@sif/firefox-content.css | 12 + accounts/gkleen@sif/ssh-hosts.nix | 190 +++ accounts/gkleen@sif/xmonad/.gitignore | 4 + accounts/gkleen@sif/xmonad/default.nix | 7 + accounts/gkleen@sif/xmonad/lib/XMonad/Mpv.hs | 127 ++ .../gkleen@sif/xmonad/lib/XMonad/Prompt/MyPass.hs | 94 ++ .../gkleen@sif/xmonad/lib/XMonad/Prompt/MyShell.hs | 105 ++ .../gkleen@sif/xmonad/lib/XMonad/Prompt/MySsh.hs | 243 +++ accounts/gkleen@sif/xmonad/package.yaml | 30 + accounts/gkleen@sif/xmonad/stack.nix | 17 + accounts/gkleen@sif/xmonad/stack.yaml | 10 + accounts/gkleen@sif/xmonad/xmonad-yggdrasil.nix | 21 + accounts/gkleen@sif/xmonad/xmonad.hs | 898 ++++++++++++ accounts/gkleen@sif/xresources.nix | 46 + overlays/nerdfonts.nix | 5 + overlays/pidgin.nix | 20 + overlays/urxvt/52-osc.pl | 41 + overlays/urxvt/default.nix | 21 + user-profiles/mpv/default.nix | 83 ++ user-profiles/tmux/default.nix | 26 + user-profiles/tmux/tmux.conf | 25 + user-profiles/utils.nix | 22 + user-profiles/zsh/default.nix | 30 + user-profiles/zsh/p10k.zsh | 1548 ++++++++++++++++++++ users/gkleen/default.nix | 34 +- users/root.nix | 29 +- 34 files changed, 4111 insertions(+), 5 deletions(-) delete mode 100644 accounts/gkleen@sif.nix create mode 100644 accounts/gkleen@sif/autorandr-profiles/bstr.nix create mode 100644 accounts/gkleen@sif/autorandr-profiles/default.nix create mode 100644 accounts/gkleen@sif/backup-patterns create mode 100644 accounts/gkleen@sif/default.nix create mode 100644 accounts/gkleen@sif/dunst-settings.nix create mode 100644 accounts/gkleen@sif/emacs.el create mode 100644 accounts/gkleen@sif/firefox-chrome.css create mode 100644 accounts/gkleen@sif/firefox-content.css create mode 100644 accounts/gkleen@sif/ssh-hosts.nix create mode 100644 accounts/gkleen@sif/xmonad/.gitignore create mode 100644 accounts/gkleen@sif/xmonad/default.nix create mode 100644 accounts/gkleen@sif/xmonad/lib/XMonad/Mpv.hs create mode 100644 accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyPass.hs create mode 100644 accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyShell.hs create mode 100644 accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MySsh.hs create mode 100644 accounts/gkleen@sif/xmonad/package.yaml create mode 100644 accounts/gkleen@sif/xmonad/stack.nix create mode 100644 accounts/gkleen@sif/xmonad/stack.yaml create mode 100644 accounts/gkleen@sif/xmonad/xmonad-yggdrasil.nix create mode 100644 accounts/gkleen@sif/xmonad/xmonad.hs create mode 100644 accounts/gkleen@sif/xresources.nix create mode 100644 overlays/nerdfonts.nix create mode 100644 overlays/pidgin.nix create mode 100644 overlays/urxvt/52-osc.pl create mode 100644 overlays/urxvt/default.nix create mode 100644 user-profiles/mpv/default.nix create mode 100644 user-profiles/tmux/default.nix create mode 100644 user-profiles/tmux/tmux.conf create mode 100644 user-profiles/utils.nix create mode 100644 user-profiles/zsh/default.nix create mode 100644 user-profiles/zsh/p10k.zsh diff --git a/accounts/gkleen@sif.nix b/accounts/gkleen@sif.nix deleted file mode 100644 index c157af78..00000000 --- a/accounts/gkleen@sif.nix +++ /dev/null @@ -1 +0,0 @@ -{ ... }: {} diff --git a/accounts/gkleen@sif/autorandr-profiles/bstr.nix b/accounts/gkleen@sif/autorandr-profiles/bstr.nix new file mode 100644 index 00000000..527f8321 --- /dev/null +++ b/accounts/gkleen@sif/autorandr-profiles/bstr.nix @@ -0,0 +1,21 @@ +{ + fingerprint = { + "eDP-1-1" = "00ffffffffffff004c83414100000000131d0104b5221378029491ae513eb7240b505400000001010101010101010101010101010101f0d40040f17018803020440058c21000001bf0d40040f17018803020440058c21000001b0000000f00ff093cff093c2c800000000000000000fe0041544e413536575230382d3020011502030f00e3058000e6060501736d0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab"; + "DP-1.3" = "00ffffffffffff000469a3289bdd00000b190104a53e22783a1cb5a3574fa0270d5054bfef00d1c0814081809500b300714f81c0010122cc0050f0703e80181035006d552100001a04740030f2705a80b0588a006d552100001a000000fd001e5018a03c041100f0f838f03c000000fc0041535553205042323837510a2001a8020327714f0102031112130414051f900e0f1d1e23091707830100006a030c0010000078200000565e00a0a0a02950302035006d552100001ee26800a0a0402e60302036006d552100001a011d00bc52d01e20b82855406d552100001e8c0ad090204031200c4055006d55210000180000000000000000000000000000000064"; + }; + config = { + "DP-1.3" = { + enable = true; + primary = true; + position = "3840x0"; + rate = "60"; + mode = "3840x2160"; + }; + eDP-1-1 = { + enable = true; + primary = false; + position = "0x0"; + mode = "3840x2160"; + }; + }; +} diff --git a/accounts/gkleen@sif/autorandr-profiles/default.nix b/accounts/gkleen@sif/autorandr-profiles/default.nix new file mode 100644 index 00000000..304b4afe --- /dev/null +++ b/accounts/gkleen@sif/autorandr-profiles/default.nix @@ -0,0 +1,13 @@ +{ + fingerprint = { + eDP-1-1 = "00ffffffffffff004c83414100000000131d0104b5221378029491ae513eb7240b505400000001010101010101010101010101010101f0d40040f17018803020440058c21000001bf0d40040f17018803020440058c21000001b0000000f00ff093cff093c2c800000000000000000fe0041544e413536575230382d3020011502030f00e3058000e6060501736d0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab"; + }; + config = { + eDP-1-1 = { + enable = true; + primary = true; + position = "0x0"; + mode = "3840x2160"; + }; + }; +} diff --git a/accounts/gkleen@sif/backup-patterns b/accounts/gkleen@sif/backup-patterns new file mode 100644 index 00000000..d9d12f5b --- /dev/null +++ b/accounts/gkleen@sif/backup-patterns @@ -0,0 +1,24 @@ +R . + +- pp:.cache +- pp:.antigen ++ pf:.cabal/config +- pp:.cabal ++ pf:.stack/config.yaml +- pp:.stack +- pp:.nox +- pp:.local/share/Steam +- sh:**/.stack-work +- sh:**/.~lock.* +- sh:**/.gup ++ pf:.config/pulse/default.pa +- pp:.config/pulse +- pp:.zplug/log +- pp:.zplug/cache +- pp:.compose-cache +- pp:.undo-tree +- pp:.saves +- pp:.mozilla +- pp:Downloads/tmp +- pp:secret +- pp:mail \ No newline at end of file diff --git a/accounts/gkleen@sif/default.nix b/accounts/gkleen@sif/default.nix new file mode 100644 index 00000000..9f2df668 --- /dev/null +++ b/accounts/gkleen@sif/default.nix @@ -0,0 +1,181 @@ +{ flake, userName, pkgs, customUtils, lib, config, ... }: +let + cfg = config.home-manager.users.${userName}; + xmonad = import ./xmonad pkgs.haskellPackages; +in { + imports = with flake.nixosModules.userProfiles.${userName}; [ + mpv + ]; + + home-manager.users.${userName} = { + programs = { + ssh = { + matchBlocks = import ./ssh-hosts.nix; # customUtils.recImport { dir = ./ssh-hosts; }; + extraConfig = '' + Match host uniworx3.ifi.lmu.de,uniworx4.ifi.lmu.de,uni2workgw.ifi.lmu.de,blackbeard.tcs.ifi.lmu.de,gitlab2.rz.ifi.lmu.de,oregon.tcs.ifi.lmu.de !exec "nc -z -w 1 %h %p &>/dev/null" + ProxyJump gate + ''; + }; + + emacs = { + enable = true; + extraPackages = epkgs: with epkgs; [ + evil evil-dvorak evil-magit undo-tree magit haskell-mode + nix-mode yaml-mode json-mode shakespeare-mode + smart-mode-line highlight-parentheses highlight-symbol + notmuch ag sass-mode lua-mode + ]; + }; + firefox = { + enable = true; + profiles.default = { + settings = { + "layout.css.devPixelsPerPx" = "1.75"; + "browser.tabs.drawInTitlebar" = false; + "toolkit.legacyUserProfileCustomizations.stylesheets" = true; + }; + }; + }; + + urxvt = { + enable = true; + package = pkgs.rxvt_unicode-with-plugins; + fonts = [ "xft:Fira Mono for Powerline:style=Medium:pixelsize=20" ]; + scroll = { + lines = 0; + bar.enable = false; + }; + extraConfig = { + urgentOnBell = false; + print-pipe = "cat >/dev/null"; + perl-ext-common = "52-osc,url-select"; + "url-select.launcher" = "firefox"; + "url-select.underline" = true; + }; + keybindings = { + "M-u" = "perl:url-select:select_next"; + }; + }; + + zathura = { + enable = true; + package = pkgs.zathura.override { useMupdf = false; }; + }; + + mpv.config = { + demuxer-max-bytes = 1073741824; + demuxer-max-back-bytes = 268435456; + }; + + autorandr = { + enable = true; + hooks.postswitch = { + # "restart-compton" = "${pkgs.systemd}/bin/systemctl --user try-restart picom"; + "restart-trays" = '' + ${pkgs.coreutils}/bin/sleep 5 + ${pkgs.systemd}/bin/systemctl --user try-restart trayer xmobar + ''; + }; + profiles = customUtils.recImport { dir = ./autorandr-profiles; }; + }; + }; + + services = { + dunst = { + settings = import ./dunst-settings.nix; + iconTheme = cfg.gtk.iconTheme; + enable = true; + }; + emacs.enable = true; + gpg-agent = { + enable = true; + enableSshSupport = true; + extraConfig = '' + pinentry-program ${pkgs.pinentry-gtk2}/bin/pinentry + grab + ''; + }; + pasystray.enable = true; + udiskie = { + enable = true; + automount = false; + }; + unclutter = { + enable = true; + timeout = 5; + }; + network-manager-applet.enable = true; + blueman-applet.enable = true; + + sxhkd = { + enable = true; + keybindings = { + "button8" = "pacmd set-source-mute @DEFAULT_SOURCE@ 0"; + "@button8" = "pacmd set-source-mute @DEFAULT_SOURCE@ 1"; + "button9" = "pacmd set-sink-mute @DEFAULT_SINK@ 1"; + "@button9" = "pacmd set-sink-mute @DEFAULT_SINK@ 0"; + }; + }; + }; + + gtk = { + enable = true; + font.name = "DejaVu Sans 6"; + theme = { + package = pkgs.equilux-theme; + name = "Equilux-compact"; + }; + iconTheme = { + package = pkgs.paper-icon-theme; + name = "Paper"; + }; + }; + + xsession = { + enable = true; + + windowManager.command = "${xmonad}/bin/xmonad"; + + initExtra = let + lockScript = pkgs.writeScript "lock" '' + #!${pkgs.stdenv.shell} + ${pkgs.playerctl}/bin/playerctl -a pause + exec ${pkgs.xsecurelock}/bin/xsecurelock + ''; + in '' + ${pkgs.coreutils}/bin/env XSECURELOCK_WANT_FIRST_KEYPRESS=1 XSECURELOCK_DIM_ALPHA=1 ${pkgs.xss-lock}/bin/xss-lock -l -n ${pkgs.xsecurelock}/libexec/xsecurelock/dimmer -- ${lockScript} & + ${pkgs.xorg.xinput}/bin/xinput disable 'SynPS/2 Synaptics TouchPad' # Synaptics TM3512-010 + ${pkgs.xorg.xset}/bin/xset s 590 10 + ''; + }; + + xresources.properties = import ./xresources.nix; + + home = { + packages = with pkgs; [ + fira-code powerline-fonts nerdfonts pavucontrol keepassxc + youtube-dl sxiv xclip mumble pulseaudio-ctl libnotify synergy + xorg.xbacklight screen-message pidgin-with-plugins + google-play-music-desktop-player qt5ct playerctl evince + thunderbird zulip zoom-us steam steam-run wireshark skype + virt-manager rclone cached-nix-shell xournal discord xmonad + ]; + + file = { + ".emacs".source = ./emacs.el; + ".backup-munin".source = ./backup-patterns; + ".mozilla/firefox/default/chrome/userChrome.css".source = ./firefox-chrome.css; + ".mozilla/firefox/default/chrome/userContent.css".source = ./firefox-content.css; + }; + + sessionVariables = { + GDK_SCALE = 96.0 / 282.0; + XDG_DATA_DIRS = "${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}:${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}:$XDG_DATA_DIRS"; + QT_AUTO_SCREEN_SCALE_FACTOR = 1; + QT_QPA_PLATFORMTHEME = "qt5ct"; + }; + + stateVersion = "20.03"; + }; + }; +} diff --git a/accounts/gkleen@sif/dunst-settings.nix b/accounts/gkleen@sif/dunst-settings.nix new file mode 100644 index 00000000..8319da03 --- /dev/null +++ b/accounts/gkleen@sif/dunst-settings.nix @@ -0,0 +1,64 @@ +{ + global = { + font = "Monospace 6"; + markup = "full"; + format = "%s %p\\n%b"; + alignment = "left"; + geometry = "1216x10-32+64"; + shrink = true; + monitor = 0; + follow = "none"; + padding = 6; + horizontal_padding = 6; + separator_height = 1; + separator_color = "frame"; + idle_threshold = 0; + + transparency = 10; + + frame_width = 1; + frame_color = "#999999"; + + word_wrap = true; + show_age_threshold = 15; + show_indicators = false; + icon_position = "right"; + sort = false; + sticky_history = false; + }; + shortcuts = { + close = "ctrl+space"; + close_all = "ctrl+shift+space"; + history = "ctrl+comma"; + context = "ctrl+period"; + }; + urgency_low = { + background = "#000000"; + foreground = "#999999"; + timeout = 5; + }; + urgency_normal = { + background = "#000000"; + foreground = "#ffffff"; + timeout = 15; + }; + urgency_critical = { + background = "#900000"; + foreground = "#ffffff"; + timeout = 0; + }; + pulseaudio-ctl = { + summary = "Volume *"; + body = "Current is *"; + set_stack_tag = "volume"; + history_ignore = true; + }; + mail = { + appname = "notmuch"; + timeout = 0; + }; + zulip = { + appname = "Zulip"; + timeout = 0; + }; +} diff --git a/accounts/gkleen@sif/emacs.el b/accounts/gkleen@sif/emacs.el new file mode 100644 index 00000000..7bfd5c18 --- /dev/null +++ b/accounts/gkleen@sif/emacs.el @@ -0,0 +1,99 @@ +(menu-bar-mode -1) +(scroll-bar-mode -1) +(tool-bar-mode -1) + +(set-face-attribute 'default nil :height 50) + +(require 'evil) +(evil-mode 1) + +(global-subword-mode) +(global-undo-tree-mode) + +(global-set-key (kbd "RET") 'newline-and-indent) +(global-set-key (kbd "M-g") 'magit-status) +(global-set-key (kbd "M-?") 'vc-git-grep) + +(setq backup-directory-alist `(("." . "~/.saves"))) +(setq delete-old-versions t + kept-new-versions 6 + kept-old-versions 2 + version-control t) + +(add-hook 'haskell-mode-hook 'haskell-indentation-mode) +(add-hook 'haskell-mode-hook 'subword-mode) +(add-hook 'haskell-mode-hook 'highlight-symbol-mode) +(add-hook 'haskell-mode-hook 'highlight-paretheses-mode) + +(add-hook 'js-mode-hook 'highlight-symbol-mode) +(add-hook 'js-mode-hook 'highlight-parentheses-mode) +(defun my-js-mode-hook () + "Custom `js-mode' behaviours." + (setq js-indent-level 2) + ) +(add-hook 'js-mode-hook 'my-js-mode-hook) + +(setq notmuch-address-internal-completion '(received nil)) +(setq notmuch-always-prompt-for-sender t) +(setq notmuch-command "notmuch-ssh") +(setq notmuch-crypto-process-mime t) +(setq notmuch-draft-tags '("+draft" "-inbox")) +(setq notmuch-fcc-dirs nil) +(setq notmuch-hello-sections '(notmuch-hello-insert-header notmuch-hello-insert-saved-searches)) +(setq notmuch-hello-thousands-separator " ") +(setq notmuch-identities '("gkleen@yggdrasil.li" "g@141.li" "kleen@cip.ifi.lmu.de" "Gregor.Kleen@stud.ifi.lmu.de" "G.Kleen@campus.lmu.de" "G.Kleen@lmu.de" "gregor.kleen@ifi.lmu.de" "uni2work@ifi.lmu.de" "gregor@kleen.li")) +(setq notmuch-message-headers '("Subject" "To" "Cc" "Date")) +(setq notmuch-message-replied-tags '("+replied" "-unread" "-inbox")) +(setq notmuch-saved-searches + (quote + ((:name "inbox" :query "tag:inbox" :key "i") + (:name "unread" :query "tag:unread AND tag:inbox" :key "u") + (:name "drafts" :query "tag:draft" :key "d") + (:name "all mail" :query "date:month.." :key "a" :count-query "*") + (:name "sent" :query "is:sent" :key "s" :count-query "is:sent") + ))) +(setq notmuch-search-oldest-first nil) +(setq notmuch-show-all-tags-list t) +(setq notmuch-show-logo nil) + +(setq send-mail-function 'sendmail-send-it) +(setq mail-envelope-from 'header) +(setq mail-specify-envelope-from 't) +(setq mail-default-headers nil) +(setq message-default-headers "") +(setq message-default-mail-headers "") +(setq message-sendmail-envelope-from 'header) + +(setq highlight-symbol-idle-delay 0) + +(setq indent-tabs-mode nil) + +(setq ido-enable-flex-matching t) +(setq ido-everywhere t) +(ido-mode 1) + +(setq mail-host-address "sif.midgard.yggdrasil") +(setq user-full-name "Gregor Kleen") + +(defun tell-emacsclients-for-buffer-to-die () + "Sends error exit command to every client for the current buffer." + (interactive) + (dolist (proc server-buffer-clients) + (server-send-string proc "-error die"))) + +(defun kill-buffer-with-special-emacsclient-handling () + "Wrapper around kill-buffer that ensures tell-emacsclients-for-buffer-to-die is on the hooks" + (interactive) + (add-hook 'kill-buffer-hook 'tell-emacsclients-for-buffer-to-die nil t) + (kill-buffer)) + +;; (global-set-key (kbd "C-x k") 'kill-buffer) + +(defun install-emacsclient-wrapped-kill-buffer () + "Installs wrapped kill-buffer with special emacsclient handling. +Best not to install it unconditionally because the server is not +necessarily running." + (interactive) + (global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling)) + +(add-hook 'server-switch-hook 'install-emacsclient-wrapped-kill-buffer) diff --git a/accounts/gkleen@sif/firefox-chrome.css b/accounts/gkleen@sif/firefox-chrome.css new file mode 100644 index 00000000..2d359771 --- /dev/null +++ b/accounts/gkleen@sif/firefox-chrome.css @@ -0,0 +1,25 @@ +@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); + +* { + font-size:12px; +} + +#sidebar { + min-width:20em !important; + max-width:20em !important; + border-right:1px solid rgba(30,30,30) !important; +} + +#sidebar-header:nth-last-child(2) > *:last-child { + visibility: collapse; +} + +#sidebar-splitter { + visibility: collapse; +} + +#toolbar-menubar[inactive="true"] + #TabsToolbar { + visibility: collapse !important; +} + +#sidebar-box[sidebarcommand="tabcenter-reborn_ariasuni-sidebar-action"] #sidebar-header { visibility: collapse !important; } diff --git a/accounts/gkleen@sif/firefox-content.css b/accounts/gkleen@sif/firefox-content.css new file mode 100644 index 00000000..3ac53a9d --- /dev/null +++ b/accounts/gkleen@sif/firefox-content.css @@ -0,0 +1,12 @@ +@-moz-document url("about:blank") { + html { + background-color: rgb(40,40,40); + } +} + +@-moz-document url(about:newtab) { + body, #newtab-customize-overlay { + background-color: rgb(40,40,40) !important; + color: rgb(166,166,166) !important; + } +} diff --git a/accounts/gkleen@sif/ssh-hosts.nix b/accounts/gkleen@sif/ssh-hosts.nix new file mode 100644 index 00000000..ffbd8c00 --- /dev/null +++ b/accounts/gkleen@sif/ssh-hosts.nix @@ -0,0 +1,190 @@ +{ + "git.ymir" = + { hostname = "ymir.yggdrasil.li"; + user = "gitolite"; + identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil"; + }; + "git.yggdrasil.li" = + { user = "gitolite"; + identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil"; + }; + "git.rheperire.org" = + { user = "gitolite"; + identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil"; + }; + "borg.munin" = + { hostname = "u120515.your-storagebox.de"; + user = "u120515"; + identityFile = "~/.ssh/borg.munin"; + port = 23; + }; + "munin" = + { hostname = "u120515.your-storagebox.de"; + user = "u120515"; + identityFile = "~/.ssh/munin"; + }; + "ymir" = + { hostname = "ymir.yggdrasil.li"; + identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil"; + }; + "odin" = + { hostname = "odin.asgard.yggdrasil"; + identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil"; + }; + "init.odin" = + { hostname = "odin.asgard.yggdrasil"; + user = "root"; + identityFile = "~/.ssh/rsa.gkleen@hel.midgard.yggdrasil"; + extraOptions = { + StrictHostKeyChecking = "off"; + }; + }; + "heimdallr" = + { hostname = "heimdallr.asgard.yggdrasil"; + user = "root"; + identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil"; + }; + "gitlab2.rz.ifi.lmu.de" = + { user = "git"; + identityFile = "~/.ssh/gkleen@gitlab2.rz.ifi.lmu.de"; + }; + "gitlab2.cip.ifi.lmu.de" = + { user = "git"; + identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil"; + }; + "hel".hostname = "hel.midgard.yggdrasil"; + "blackbeard" = + { hostname = "blackbeard.tcs.ifi.lmu.de"; + user = "pi"; + identityFile = "~/.ssh/blackbeard"; + }; + "github.com" = + { user = "git"; + identityFile = "~/.ssh/gkleen@github.com"; + }; + "ullr.playat.ch" = + { hostname = "ullr.playat.ch"; + user = "minecraft"; + identityFile = "~/.ssh/minecraft@ullr.playat.ch"; + }; + "ullr" = + { hostname = "185.170.112.70"; + identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil"; + }; + "testworx" = + { hostname = "testworx.tcs.ifi.lmu.de"; + user = "root"; + port = 30363; + identityFile = "~/.ssh/testworx"; + }; + "remote.cip.ifi.lmu.de".user = "kleen"; + "uniworx3" = + { hostname = "uniworx3.ifi.lmu.de"; + user = "root"; + identityFile = "~/.ssh/uni2work"; + }; + "uniworx4" = + { hostname = "uniworx4.ifi.lmu.de"; + user = "root"; + identityFile = "~/.ssh/uni2work"; + }; + "uni2workgw" = + { hostname = "uni2workgw.ifi.lmu.de"; + user = "root"; + identityFile = "~/.ssh/uni2work"; + }; + "uniworxdb" = + { hostname = "uniworxdb"; + proxyJump = "uniworx4"; + user = "root"; + identityFile = "~/.ssh/uni2work"; + }; + "uniworxdb2" = + { hostname = "uniworxdb2"; + proxyJump = "uniworx4"; + user = "root"; + identityFile = "~/.ssh/uni2work"; + }; + "gate2" = + { hostname = "gate2.tcs.ifi.lmu.de"; + user = "gkleen"; + identityFile = "~/.ssh/tcs"; + }; + "proxy.gate2" = + { hostname = "gate2.tcs.ifi.lmu.de"; + user = "gkleen"; + identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de"; + dynamicForwards = [ { port = 8118; } ]; + extraOptions = { + ExitOnForwardFailure = "yes"; + }; + }; + "jump.gate2" = + { hostname = "gate2.tcs.ifi.lmu.de"; + user = "gkleen"; + identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de"; + extraOptions = { + ExitOnForwardFailure = "yes"; + }; + }; + "gate" = + { hostname = "gate.tcs.ifi.lmu.de"; + user = "gkleen"; + identityFile = "~/.ssh/tcs"; + }; + "proxy.gate" = + { hostname = "gate.tcs.ifi.lmu.de"; + user = "gkleen"; + identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de"; + dynamicForwards = [ { port = 8118; } ]; + extraOptions = { + ExitOnForwardFailure = "yes"; + }; + }; + "jump.gate" = + { hostname = "gate.tcs.ifi.lmu.de"; + user = "gkleen"; + identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de"; + extraOptions = { + ExitOnForwardFailure = "yes"; + }; + }; + "oregon" = + { hostname = "oregon.tcs.ifi.lmu.de"; + user = "root"; + identityFile = "~/.ssh/tcs"; + }; + "witbank" = + { hostname = "witbank.tcs.ifi.lmu.de"; + user = "uni2work"; + identityFile = "~/.ssh/letz"; + }; + "git.odin" = + { hostname = "odin.asgard.yggdrasil"; + user = "gitolite"; + }; + "notmuch.odin" = + { hostname = "odin.asgard.yggdrasil"; + identityFile = "~/.ssh/notmuch.odin.asgard.yggdrasil"; + }; + "status.odin" = + { hostname = "odin.asgard.yggdrasil"; + identityFile = "~/.ssh/status.odin.asgard.yggdrasil"; + extraOptions.ControlPath = "~/.ssh/status-%r@%n:%p"; + }; + "moden" = + { hostname = "oristano.tcs.ifi.lmu.de"; + user = "gkleen"; + port = 30363; + identityFile = "~/.ssh/gkleen@oristano.tcs.ifi.lmu.de"; + }; + "ubuntu1804" = + { hostname = "192.168.122.30"; + identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil"; + forwardAgent = true; + }; + "gitlab.haskell.org" = + { hostname = "gitlab.haskell.org"; + identityFile = "~/.ssh/gkleen@gitlab.haskell.org"; + }; +} diff --git a/accounts/gkleen@sif/xmonad/.gitignore b/accounts/gkleen@sif/xmonad/.gitignore new file mode 100644 index 00000000..c11891cd --- /dev/null +++ b/accounts/gkleen@sif/xmonad/.gitignore @@ -0,0 +1,4 @@ +**/#*# +**/.stack-work/ +/stack.yaml.lock +/*.cabal diff --git a/accounts/gkleen@sif/xmonad/default.nix b/accounts/gkleen@sif/xmonad/default.nix new file mode 100644 index 00000000..8790c12f --- /dev/null +++ b/accounts/gkleen@sif/xmonad/default.nix @@ -0,0 +1,7 @@ +argumentPackages@{ ... }: + +let + # defaultPackages = (import ./stackage.nix {}); + # haskellPackages = defaultPackages // argumentPackages; + haskellPackages = argumentPackages; +in haskellPackages.callPackage ./xmonad-yggdrasil.nix {} diff --git a/accounts/gkleen@sif/xmonad/lib/XMonad/Mpv.hs b/accounts/gkleen@sif/xmonad/lib/XMonad/Mpv.hs new file mode 100644 index 00000000..e6accdcc --- /dev/null +++ b/accounts/gkleen@sif/xmonad/lib/XMonad/Mpv.hs @@ -0,0 +1,127 @@ +{-# LANGUAGE DeriveGeneric, OverloadedLists, OverloadedStrings, ViewPatterns, ExistentialQuantification, MultiWayIf #-} + +module XMonad.Mpv + ( MpvCommand(..), MpvResponse(..), MpvException(..) + , mpv + , mpvDir + , mpvAll, mpvOne + , mpvResponse + ) where + +import Data.Aeson + +import Data.Monoid + +import Network.Socket hiding (recv) +import Network.Socket.ByteString + +import qualified Data.ByteString as BS +import qualified Data.ByteString.Char8 as CBS +import qualified Data.ByteString.Lazy as LBS + +import GHC.Generics (Generic) +import Data.Typeable (Typeable) +import Data.String (IsString(..)) + +import Control.Exception + +import System.IO.Temp (getCanonicalTemporaryDirectory) + +import Control.Monad +import Control.Exception (bracket) +import Control.Monad.IO.Class (MonadIO(..)) + +import System.FilePath +import System.Directory (getDirectoryContents) + +import Data.List +import Data.Either +import Data.Maybe + +import Debug.Trace + + +data MpvCommand + = forall a. ToJSON a => MpvSetProperty String a + | MpvGetProperty String +data MpvResponse + = MpvError String + | MpvSuccess (Maybe Value) + deriving (Read, Show, Generic, Eq) +data MpvException = MpvException String + | MpvNoValue + | MpvNoParse String + deriving (Generic, Typeable, Read, Show) +instance Exception MpvException + + +instance ToJSON MpvCommand where + toJSON (MpvSetProperty name val) = Array ["set_property", fromString name, toJSON val] + toJSON (MpvGetProperty name) = Array ["get_property", fromString name] + +instance FromJSON MpvResponse where + parseJSON = withObject "response object" $ \obj -> do + mval <- obj .:? "data" + err <- obj .: "error" + + let ret + | err == "success" = MpvSuccess mval + | otherwise = MpvError err + + return ret + +mpvSocket :: FilePath -> (Socket -> IO a) -> IO a +mpvSocket sockPath = withSocketsDo . bracket mkSock close + where + mkSock = do + sock <- socket AF_UNIX Stream defaultProtocol + connect sock $ SockAddrUnix (traceId sockPath) + return sock + +mpvResponse :: FromJSON v => MpvResponse -> IO v +mpvResponse (MpvError str) = throwIO $ MpvException str +mpvResponse (MpvSuccess Nothing) = throwIO MpvNoValue +mpvResponse (MpvSuccess (Just v)) = case fromJSON v of + Success v' -> return v' + Error str -> throwIO $ MpvNoParse str + +mpv :: FilePath -> MpvCommand -> IO MpvResponse +mpv sockPath cmd = mpvSocket sockPath $ \sock -> do + let message = (`BS.append` "\n") . LBS.toStrict . encode $ Object [("command", toJSON cmd)] + traceIO $ show message + sendAll sock message + let recvAll = do + prefix <- recv sock 4096 + if + | (prefix', rest) <- CBS.break (== '\n') prefix + , not (BS.null rest) -> return prefix' + | BS.null prefix -> return prefix + | otherwise -> BS.append prefix <$> recvAll + response <- recvAll + traceIO $ show response + either (ioError . userError) return . traceShowId $ eitherDecodeStrict' response + +mpvDir :: Exception e => FilePath -> (FilePath -> [(FilePath, Either e MpvResponse)] -> Maybe MpvCommand) -> IO [(FilePath, Either e MpvResponse)] +mpvDir dir step = do + socks <- filter (".sock" `isSuffixOf`) <$> getDirectoryContents dir + go [] socks + where + go acc [] = return acc + go acc (sock:socks) + | Just cmd <- step sock acc = do + res <- try $ mpv (dir sock) cmd + go ((sock, res) : acc) socks + | otherwise = + go acc socks + +mpvAll :: FilePath -> MpvCommand -> IO [MpvResponse] +mpvAll dir cmd = do + results <- map snd <$> (mpvDir dir (\_ _ -> Just cmd) :: IO [(FilePath, Either SomeException MpvResponse)]) + mapM (either throwIO return) results + +mpvOne :: FilePath -> MpvCommand -> IO (Maybe MpvResponse) +mpvOne dir cmd = listToMaybe . snd . partitionEithers . map snd <$> (mpvDir dir step :: IO [(FilePath, Either SomeException MpvResponse)]) + where + step _ results + | any (isRight . snd) results = Nothing + | otherwise = Just cmd diff --git a/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyPass.hs b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyPass.hs new file mode 100644 index 00000000..1caefae5 --- /dev/null +++ b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyPass.hs @@ -0,0 +1,94 @@ +module XMonad.Prompt.MyPass + ( + -- * Usages + -- $usages + mkPassPrompt + ) where + +import Control.Monad (liftM) +import XMonad.Core +import XMonad.Prompt ( XPrompt + , showXPrompt + , commandToComplete + , nextCompletion + , getNextCompletion + , XPConfig + , mkXPrompt + , searchPredicate) +import System.Directory (getHomeDirectory) +import System.FilePath (takeExtension, dropExtension, combine) +import System.Posix.Env (getEnv) +import XMonad.Util.Run (runProcessWithInput) + +-- $usages +-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@: +-- +-- > import XMonad.Prompt.Pass +-- +-- Then add a keybinding for 'passPrompt', 'passGeneratePrompt' or 'passRemovePrompt': +-- +-- > , ((modMask x , xK_p) , passPrompt xpconfig) +-- > , ((modMask x .|. controlMask, xK_p) , passGeneratePrompt xpconfig) +-- > , ((modMask x .|. controlMask .|. shiftMask, xK_p), passRemovePrompt xpconfig) +-- +-- For detailed instructions on: +-- +-- - editing your key bindings, see "XMonad.Doc.Extending#Editing_key_bindings". +-- +-- - how to setup the password storage, see +-- + +type Predicate = String -> String -> Bool + +getPassCompl :: [String] -> Predicate -> String -> IO [String] +getPassCompl compls p s + | length s <= minL + , all ((> minL) . length) compls = return [] + | otherwise = do return $ filter (p s) compls + where + minL = 3 + +type PromptLabel = String + +data Pass = Pass PromptLabel + +instance XPrompt Pass where + showXPrompt (Pass prompt) = prompt ++ ": " + commandToComplete _ c = c + nextCompletion _ = getNextCompletion + +-- | Default password store folder in $HOME/.password-store +-- +passwordStoreFolderDefault :: String -> String +passwordStoreFolderDefault home = combine home ".password-store" + +-- | Compute the password store's location. +-- Use the PASSWORD_STORE_DIR environment variable to set the password store. +-- If empty, return the password store located in user's home. +-- +passwordStoreFolder :: IO String +passwordStoreFolder = + getEnv "PASSWORD_STORE_DIR" >>= computePasswordStoreDir + where computePasswordStoreDir Nothing = liftM passwordStoreFolderDefault getHomeDirectory + computePasswordStoreDir (Just storeDir) = return storeDir + +-- | A pass prompt factory +-- +mkPassPrompt :: PromptLabel -> (String -> X ()) -> XPConfig -> X () +mkPassPrompt promptLabel passwordFunction xpconfig = do + passwords <- io (passwordStoreFolder >>= getPasswords) + mkXPrompt (Pass promptLabel) xpconfig (getPassCompl passwords $ searchPredicate xpconfig) passwordFunction + +-- | Retrieve the list of passwords from the password storage 'passwordStoreDir +getPasswords :: FilePath -> IO [String] +getPasswords passwordStoreDir = do + files <- runProcessWithInput "find" [ + passwordStoreDir, + "-type", "f", + "-name", "*.gpg", + "-printf", "%P\n"] [] + return $ map removeGpgExtension $ lines files + +removeGpgExtension :: String -> String +removeGpgExtension file | takeExtension file == ".gpg" = dropExtension file + | otherwise = file diff --git a/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyShell.hs b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyShell.hs new file mode 100644 index 00000000..c268f87d --- /dev/null +++ b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyShell.hs @@ -0,0 +1,105 @@ +module XMonad.Prompt.MyShell + ( Shell (..) + , shellPrompt + , prompt + , safePrompt + , unsafePrompt + , getCommands + , getShellCompl + , split + ) where + +import Codec.Binary.UTF8.String (encodeString) +import Control.Exception as E +import Control.Monad (forM) +import Data.List (isPrefixOf) +import System.Directory (doesDirectoryExist, getDirectoryContents) +import System.Environment (getEnv) +import System.Posix.Files (getFileStatus, isDirectory) + +import XMonad hiding (config) +import XMonad.Prompt +import XMonad.Util.Run + +econst :: Monad m => a -> IOException -> m a +econst = const . return + +data Shell = Shell String + +instance XPrompt Shell where + showXPrompt (Shell q) = q + completionToCommand _ = escape + +shellPrompt :: String -> XPConfig -> X () +shellPrompt q c = do + cmds <- io getCommands + mkXPrompt (Shell q) c (getShellCompl cmds) spawn + +{- $spawns + See safe and unsafeSpawn in "XMonad.Util.Run". + prompt is an alias for safePrompt; + safePrompt and unsafePrompt work on the same principles, but will use + XPrompt to interactively query the user for input; the appearance is + set by passing an XPConfig as the second argument. The first argument + is the program to be run with the interactive input. + You would use these like this: + + > , ((modm, xK_b), safePrompt "firefox" greenXPConfig) + > , ((modm .|. shiftMask, xK_c), prompt ("xterm" ++ " -e") greenXPConfig) + + Note that you want to use safePrompt for Firefox input, as Firefox + wants URLs, and unsafePrompt for the XTerm example because this allows + you to easily start a terminal executing an arbitrary command, like + 'top'. -} + +prompt, unsafePrompt, safePrompt :: String -> FilePath -> XPConfig -> X () +prompt = unsafePrompt +safePrompt q c config = mkXPrompt (Shell q) config (getShellCompl [c]) run + where run = safeSpawn c . return +unsafePrompt q c config = mkXPrompt (Shell q) config (getShellCompl [c]) run + where run a = unsafeSpawn $ c ++ " " ++ a + +getShellCompl :: [String] -> String -> IO [String] +getShellCompl cmds s | s == "" || last s == ' ' = return [] + | otherwise = do + f <- fmap lines $ runProcessWithInput "bash" [] ("compgen -A file -- " + ++ s ++ "\n") + files <- case f of + [x] -> do fs <- getFileStatus (encodeString x) + if isDirectory fs then return [x ++ "/"] + else return [x] + _ -> return f + return . uniqSort $ files ++ commandCompletionFunction cmds s + +commandCompletionFunction :: [String] -> String -> [String] +commandCompletionFunction cmds str | '/' `elem` str = [] + | otherwise = filter (isPrefixOf str) cmds + +getCommands :: IO [String] +getCommands = do + p <- getEnv "PATH" `E.catch` econst [] + let ds = filter (/= "") $ split ':' p + es <- forM ds $ \d -> do + exists <- doesDirectoryExist d + if exists + then getDirectoryContents d + else return [] + return . uniqSort . filter ((/= '.') . head) . concat $ es + +split :: Eq a => a -> [a] -> [[a]] +split _ [] = [] +split e l = + f : split e (rest ls) + where + (f,ls) = span (/=e) l + rest s | s == [] = [] + | otherwise = tail s + +escape :: String -> String +escape [] = "" +escape (x:xs) + | isSpecialChar x = '\\' : x : escape xs + | otherwise = x : escape xs + +isSpecialChar :: Char -> Bool +isSpecialChar = flip elem " &\\@\"'#?$*()[]{};" diff --git a/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MySsh.hs b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MySsh.hs new file mode 100644 index 00000000..c85d0f92 --- /dev/null +++ b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MySsh.hs @@ -0,0 +1,243 @@ +module XMonad.Prompt.MySsh + ( -- * Usage + -- $usage + sshPrompt, + Ssh, + Override (..), + mkOverride, + Conn (..), + moshCmd, + moshCmd', + sshCmd, + inTmux, + withEnv + ) where + +import XMonad +import XMonad.Util.Run +import XMonad.Prompt + +import System.Directory +import System.Environment +import qualified Control.Exception as E + +import Control.Monad +import Data.Maybe + +import Text.Parsec.String +import Text.Parsec +import Data.Char (isSpace) + +econst :: Monad m => a -> E.IOException -> m a +econst = const . return + +-- $usage +-- 1. In your @~\/.xmonad\/xmonad.hs@: +-- +-- > import XMonad.Prompt +-- > import XMonad.Prompt.Ssh +-- +-- 2. In your keybindings add something like: +-- +-- > , ((modm .|. controlMask, xK_s), sshPrompt defaultXPConfig) +-- +-- Keep in mind, that if you want to use the completion you have to +-- disable the "HashKnownHosts" option in your ssh_config +-- +-- For detailed instruction on editing the key binding see +-- "XMonad.Doc.Extending#Editing_key_bindings". + +data Override = Override + { oUser :: Maybe String + , oHost :: String + , oPort :: Maybe Int + , oCommand :: Conn -> String + } + +mkOverride = Override { oUser = Nothing, oHost = "", oPort = Nothing, oCommand = sshCmd } +sshCmd c = concat + [ "ssh -t " + , if isJust $ cUser c then (fromJust $ cUser c) ++ "@" else "" + , cHost c + , if isJust $ cPort c then " -p " ++ (show $ fromJust $ cPort c) else "" + , " -- " + , cCommand c + ] +moshCmd c = concat + [ "mosh " + , if isJust $ cUser c then (fromJust $ cUser c) ++ "@" else "" + , cHost c + , if isJust $ cPort c then " --ssh=\"ssh -p " ++ (show $ fromJust $ cPort c) ++ "\"" else "" + , " -- " + , cCommand c + ] +moshCmd' p c = concat + [ "mosh " + , "--server=" ++ p ++ " " + , if isJust $ cUser c then (fromJust $ cUser c) ++ "@" else "" + , cHost c + , if isJust $ cPort c then " --ssh=\"ssh -p " ++ (show $ fromJust $ cPort c) ++ "\"" else "" + , " -- " + , cCommand c + ] +inTmux c + | null $ cCommand c = c { cCommand = "tmux new-session" } + | otherwise = c { cCommand = "tmux new-session \"" ++ (cCommand c) ++ "\"" } +withEnv :: [(String, String)] -> Conn -> Conn +withEnv envs c = c { cCommand = "env" ++ (concat $ map (\(n, v) -> ' ' : (n ++ "=" ++ v)) envs) ++ " " ++ (cCommand c) } + +data Conn = Conn + { cUser :: Maybe String + , cHost :: String + , cPort :: Maybe Int + , cCommand :: String + } deriving (Eq, Show, Read) + +data Ssh = Ssh + +instance XPrompt Ssh where + showXPrompt Ssh = "SSH to: " + commandToComplete _ c = c + nextCompletion _ = getNextCompletion + +toConn :: String -> Maybe Conn +toConn = toConn' . parse connParser "(unknown)" +toConn' :: Either ParseError Conn -> Maybe Conn +toConn' (Left _) = Nothing +toConn' (Right a) = Just a + +connParser :: Parser Conn +connParser = do + spaces + user' <- optionMaybe $ try $ do + str <- many1 $ satisfy (\c -> (not $ isSpace c) && (c /= '@')) + char '@' + return str + host' <- many1 $ satisfy (not . isSpace) + port' <- optionMaybe $ try $ do + space + string "-p" + spaces + int <- many1 digit + (space >> return ()) <|> eof + return $ (read int :: Int) + spaces + command' <- many anyChar + eof + return $ Conn + { cHost = host' + , cUser = user' + , cPort = port' + , cCommand = command' + } + +sshPrompt :: [Override] -> XPConfig -> X () +sshPrompt o c = do + sc <- io sshComplList + mkXPrompt Ssh c (mkComplFunFromList sc) $ ssh o + +ssh :: [Override] -> String -> X () +ssh overrides str = do + let cmd = applyOverrides overrides str + liftIO $ putStr "SSH Command: " + liftIO $ putStrLn cmd + runInTerm "" cmd + +applyOverrides :: [Override] -> String -> String +applyOverrides [] str = "ssh " ++ str +applyOverrides (o:os) str = case (applyOverride o str) of + Just str -> str + Nothing -> applyOverrides os str + +applyOverride :: Override -> String -> Maybe String +applyOverride o str = let + conn = toConn str + in + if isNothing conn then Nothing else + case (fromJust conn) `matches` o of + True -> Just $ (oCommand o) (fromJust conn) + False -> Nothing + +matches :: Conn -> Override -> Bool +a `matches` b = and + [ justBool (cUser a) (oUser b) (==) + , (cHost a) == (oHost b) + , justBool (cPort a) (oPort b) (==) + ] + +justBool :: Eq a => Maybe a -> Maybe a -> (a -> a -> Bool) -> Bool +justBool Nothing _ _ = True +justBool _ Nothing _ = True +justBool (Just a) (Just b) match = a `match` b + +sshComplList :: IO [String] +sshComplList = uniqSort `fmap` liftM2 (++) sshComplListLocal sshComplListGlobal + +sshComplListLocal :: IO [String] +sshComplListLocal = do + h <- getEnv "HOME" + s1 <- sshComplListFile $ h ++ "/.ssh/known_hosts" + s2 <- sshComplListConf $ h ++ "/.ssh/config" + return $ s1 ++ s2 + +sshComplListGlobal :: IO [String] +sshComplListGlobal = do + env <- getEnv "SSH_KNOWN_HOSTS" `E.catch` econst "/nonexistent" + fs <- mapM fileExists [ env + , "/usr/local/etc/ssh/ssh_known_hosts" + , "/usr/local/etc/ssh_known_hosts" + , "/etc/ssh/ssh_known_hosts" + , "/etc/ssh_known_hosts" + ] + case catMaybes fs of + [] -> return [] + (f:_) -> sshComplListFile' f + +sshComplListFile :: String -> IO [String] +sshComplListFile kh = do + f <- doesFileExist kh + if f then sshComplListFile' kh + else return [] + +sshComplListFile' :: String -> IO [String] +sshComplListFile' kh = do + l <- readFile kh + return $ map (getWithPort . takeWhile (/= ',') . concat . take 1 . words) + $ filter nonComment + $ lines l + +sshComplListConf :: String -> IO [String] +sshComplListConf kh = do + f <- doesFileExist kh + if f then sshComplListConf' kh + else return [] + +sshComplListConf' :: String -> IO [String] +sshComplListConf' kh = do + l <- readFile kh + return $ map (!!1) + $ filter isHost + $ map words + $ lines l + where + isHost ws = take 1 ws == ["Host"] && length ws > 1 + +fileExists :: String -> IO (Maybe String) +fileExists kh = do + f <- doesFileExist kh + if f then return $ Just kh + else return Nothing + +nonComment :: String -> Bool +nonComment [] = False +nonComment ('#':_) = False +nonComment ('|':_) = False -- hashed, undecodeable +nonComment _ = True + +getWithPort :: String -> String +getWithPort ('[':str) = host ++ " -p " ++ port + where (host,p) = break (==']') str + port = case p of + ']':':':x -> x + _ -> "22" +getWithPort str = str diff --git a/accounts/gkleen@sif/xmonad/package.yaml b/accounts/gkleen@sif/xmonad/package.yaml new file mode 100644 index 00000000..48de1a53 --- /dev/null +++ b/accounts/gkleen@sif/xmonad/package.yaml @@ -0,0 +1,30 @@ +name: xmonad-yggdrasil + +executables: + xmonad: + dependencies: + - base + - xmonad + - xmonad-contrib + - aeson + - bytestring + - text + - temporary + - filepath + - directory + - network + - unix + - utf8-string + - parsec + - process + - mtl + - X11 + - transformers + - containers + - hostname + - libnotify + + main: xmonad.hs + source-dirs: + - . + - lib diff --git a/accounts/gkleen@sif/xmonad/stack.nix b/accounts/gkleen@sif/xmonad/stack.nix new file mode 100644 index 00000000..17a49e04 --- /dev/null +++ b/accounts/gkleen@sif/xmonad/stack.nix @@ -0,0 +1,17 @@ +{ ghc, nixpkgs ? import ./nixpkgs.nix {} }: + +let + haskellPackages = import ./stackage.nix { inherit nixpkgs; }; + inherit (nixpkgs {}) pkgs; +in pkgs.haskell.lib.buildStackProject { + inherit ghc; + inherit (haskellPackages) stack; + name = "stackenv"; + buildInputs = (with pkgs; + [ xorg.libX11 xorg.libXrandr xorg.libXinerama xorg.libXScrnSaver xorg.libXext xorg.libXft + cairo + glib + ]) ++ (with haskellPackages; + [ + ]); +} diff --git a/accounts/gkleen@sif/xmonad/stack.yaml b/accounts/gkleen@sif/xmonad/stack.yaml new file mode 100644 index 00000000..b8ed1147 --- /dev/null +++ b/accounts/gkleen@sif/xmonad/stack.yaml @@ -0,0 +1,10 @@ +nix: + enable: true + shell-file: stack.nix + +resolver: lts-13.21 + +packages: + - . + +extra-deps: [] diff --git a/accounts/gkleen@sif/xmonad/xmonad-yggdrasil.nix b/accounts/gkleen@sif/xmonad/xmonad-yggdrasil.nix new file mode 100644 index 00000000..e8786d35 --- /dev/null +++ b/accounts/gkleen@sif/xmonad/xmonad-yggdrasil.nix @@ -0,0 +1,21 @@ +{ mkDerivation, aeson, base, bytestring, containers, directory +, filepath, hostname, hpack, mtl, network, parsec, process, stdenv +, temporary, transformers, unix, utf8-string, X11, xmonad +, xmonad-contrib, libnotify +}: +mkDerivation { + pname = "xmonad-yggdrasil"; + version = "0.0.0"; + src = ./.; + isLibrary = false; + isExecutable = true; + libraryToolDepends = [ hpack ]; + executableHaskellDepends = [ + aeson base bytestring containers directory filepath hostname mtl + network parsec process temporary transformers unix utf8-string X11 + xmonad xmonad-contrib libnotify + ]; + preConfigure = "hpack"; + license = "unknown"; + hydraPlatforms = stdenv.lib.platforms.none; +} diff --git a/accounts/gkleen@sif/xmonad/xmonad.hs b/accounts/gkleen@sif/xmonad/xmonad.hs new file mode 100644 index 00000000..f3a59f34 --- /dev/null +++ b/accounts/gkleen@sif/xmonad/xmonad.hs @@ -0,0 +1,898 @@ +{-# LANGUAGE TupleSections, ViewPatterns, OverloadedStrings, FlexibleInstances, UndecidableInstances, MultiWayIf #-} + +import XMonad +import XMonad.Hooks.DynamicLog +import XMonad.Hooks.ManageDocks +import XMonad.Util.Run +import XMonad.Util.Loggers +import XMonad.Util.EZConfig(additionalKeys) +import System.IO +import System.IO.Error +import System.Environment +import Data.Map (Map) +import qualified Data.Map as Map +import qualified XMonad.StackSet as W +import System.Exit +import Control.Monad.State (get) +-- import XMonad.Layout.Spiral +import Data.Ratio +import Data.List +import Data.Char +import Data.Maybe (fromMaybe, listToMaybe, maybeToList, catMaybes, isJust) +import XMonad.Layout.Tabbed +import XMonad.Prompt +import XMonad.Prompt.Input +import XMonad.Util.Scratchpad +import XMonad.Util.NamedScratchpad +import Control.Monad (sequence, liftM, liftM2, join, void) +import XMonad.Util.WorkspaceCompare +import XMonad.Layout.NoBorders +import XMonad.Layout.PerWorkspace +import XMonad.Layout.SimplestFloat +import XMonad.Layout.Renamed +import XMonad.Layout.Reflect +import XMonad.Layout.OnHost +import XMonad.Layout.Combo +import XMonad.Layout.ComboP +import XMonad.Layout.Column +import XMonad.Layout.TwoPane +import XMonad.Layout.IfMax +import XMonad.Layout.LayoutBuilder +import XMonad.Layout.WindowNavigation +import XMonad.Layout.Dwindle +import XMonad.Layout.TrackFloating +import System.Process +import System.Directory (removeFile) +import System.Posix.Files +import System.FilePath (()) +import Control.Concurrent +import System.Posix.Process (getProcessID) +import System.IO.Error +import System.IO +import XMonad.Hooks.ManageHelpers hiding (CW) +import XMonad.Hooks.UrgencyHook as U +import XMonad.Hooks.EwmhDesktops +import XMonad.StackSet (RationalRect (..)) +import Control.Monad (when, filterM, (<=<)) +import Graphics.X11.ExtraTypes.XF86 +import XMonad.Util.Cursor +import XMonad.Actions.Warp +import XMonad.Actions.FloatKeys +import XMonad.Util.SpawnOnce +import System.Directory +import System.FilePath +import XMonad.Actions.CopyWindow +import XMonad.Hooks.ServerMode +import XMonad.Actions.Commands +import XMonad.Actions.CycleWS +import XMonad.Actions.RotSlaves +import XMonad.Actions.UpdatePointer +import XMonad.Prompt.Window +import Data.IORef +import Data.Monoid +import Data.String +import qualified XMonad.Actions.PhysicalScreens as P + +import XMonad.Layout.IM + +import XMonad.Prompt.MyShell +import XMonad.Prompt.MyPass +import XMonad.Prompt.MySsh + +import XMonad.Mpv + +import Network.HostName + +import Control.Applicative ((<$>)) + +import Libnotify as Notify hiding (appName) +import qualified Libnotify as Notify (appName) +import Libnotify (Notification) +-- import System.Information.Battery + +import Data.Int (Int32) + +import System.Posix.Process +import System.Posix.Signals +import System.Posix.IO as Posix +import Control.Exception + +import System.IO.Unsafe + +import Control.Monad.Trans.Class +import Control.Monad.Trans.Maybe + +import Data.Fixed (Micro) + +import qualified Data.Text as Text +import Data.Ord (comparing) +import Debug.Trace + +instance MonadIO m => IsString (m ()) where + fromString = spawn + +type KeyMap = Map (ButtonMask, KeySym) (X ()) + +data Host = Host + { hName :: HostName + , hManageHook :: ManageHook + , hWsp :: Integer -> WorkspaceId + , hCoWsp :: String -> Maybe WorkspaceId + , hKeysMod :: XConfig Layout -> (KeyMap -> KeyMap) + , hScreens :: [P.PhysicalScreen] + , hKbLayouts :: [(String, Maybe String)] + , hCmds :: X [(String, X ())] + , hKeyUpKeys :: XConfig Layout -> KeyMap + } + +defaultHost = Host { hName = "unkown" + , hManageHook = composeOne [manageScratchTerm] + , hWsp = show + , hCoWsp = const Nothing + , hKeysMod = const id + , hScreens = [0,1..] + , hKbLayouts = [ ("us", Just "dvp") + , ("us", Nothing) + , ("de", Nothing) + ] + , hCmds = return [] + , hKeyUpKeys = const Map.empty + } + +browser :: String +browser = "env MOZ_USE_XINPUT2=1 firefox" + +hostFromName :: HostName -> Host +hostFromName h@("vali") = defaultHost { hName = h + , hManageHook = composeOne $ catMaybes [ Just manageScratchTerm + , assign "web" $ className =? ".dwb-wrapped" + , assign "web" $ className =? "Chromium" + , assign "work" $ className =? "Emacs" + , assign "media" $ className =? "mpv" + ] + , hWsp = hWsp + , hCoWsp = hCoWsp + , hKeysMod = \conf -> Map.union $ (Map.fromList $ join $ map (spawnBindings conf) [ (xK_d, ["chromium", "chromium $(xclip -o)"]) + , (xK_e, ["emacsclient -c"]) + ]) + `Map.union` + ( Map.fromList [ ((XMonad.modMask conf .|. controlMask, xK_Return), scratchpadSpawnActionCustom $ (XMonad.terminal conf) ++ " -name scratchpad -title scratchpad -e tmux new-session -D -s scratch") + ] ) + , hScreens = hScreens defaultHost + } + where + workspaceNames = Map.fromList [ (2, "web") + , (3, "work") + , (10, "media") + ] + hWsp = wspFromMap workspaceNames + hCoWsp = coWspFromMap workspaceNames + assign wsp test = (\wsp -> test -?> doShift wsp) <$> hCoWsp wsp +hostFromName h + | h `elem` ["hel", "sif"] = defaultHost { hName = h + , hManageHook = namedScratchpadManageHook scratchpads <+> composeOne (catMaybes + [ assign "mpv" $ className =? "mpv" + , assign "mpv" $ (className =? "URxvt" <&&> title =? "irssi") + , assign "mpv" $ (className =? "URxvt" <&&> resource =? "presentation") + , assign "mpv" $ stringProperty "WM_WINDOW_ROLE" =? "presentation" + , assign "read" $ stringProperty "WM_WINDOW_ROLE" =? "presenter" + , assign "mpv" $ className =? "factorio" + , assign "web" $ className =? "chromium-browser" + , assign "web" $ className =? "Google-chrome" + , assign "work" $ (appName =? "Devtools" <&&> className =? "Firefox") + , assign "work" $ className =? "Postman" + , assign "web" $ className =? "Firefox" + , assign "comm" $ (className =? "URxvt" <&&> resource =? "comm") + , assign "comm" $ (className =? "Emacs" <&&> title =? "Mail") + , assign "comm" $ className =? "Zulip" + , assign "comm" $ className =? "Discord" + , assign "media" $ (className =? "URxvt" <&&> resource =? "media") + , assign "media" $ (className =? "URxvt" <&&> title =? "streamlink") + , assign "media" $ (className =? "URxvt" <&&> title =? "mpv") + , assign "monitor" $ (className =? "URxvt" <&&> fmap ("monitor" `isInfixOf`) title) + , assign "monitor" $ className =? "Grafana" + , Just $ (className =? "URxvt" <&&> resource =? "htop") -?> centerFloat + , Just $ (className =? "Scp-dbus-service.py") -?> centerFloat + , Just $ (className =? "URxvt" <&&> resource =? "log") -?> centerFloat + , assign "work" $ className =? "URxvt" + , assign' ["work", "uni"] $ (className =? "Emacs" <&&> appName /=? "Edit_with_Emacs_FRAME") + , assign' ["work", "uni"] $ className =? "jetbrains-idea-ce" + , assign "read" $ className =? "llpp" + , assign "read" $ className =? "Evince" + , assign "read" $ fmap ("zathura" `isInfixOf`) title + , assign "read" $ className =? "MuPDF" + , assign "read" $ className =? "Xournal" + , assign "read" $ appName =? "com-trollworks-gcs-app-GCS" + , assign "read" $ appName =? "Tux.py" + , assign "read" $ className =? "Gnucash" + , assign "comm" $ className =? "Skype" + , assign "comm" $ className =? "Daily" + , assign "comm" $ className =? "Pidgin" + , assign "comm" $ className =? "Slack" + , Just $ (resource =? "xvkbd") -?> doRectFloat $ RationalRect (1 % 8) (3 % 8) (6 % 8) (4 % 8) + , Just $ (stringProperty "_NET_WM_WINDOW_TYPE" =? "_NET_WM_WINDOW_TYPE_DIALOG") -?> doFloat + , Just $ (className =? "Dunst") -?> doFloat + , Just $ (className =? "Xmessage") -?> doCenterFloat + , Just $ (className =? "Nm-openconnect-auth-dialog") -?> centerFloat + , Just $ (className =? "Pinentry") -?> doCenterFloat + , Just $ (className =? "pinentry") -?> doCenterFloat + , Just $ (appName =? "Edit_with_Emacs_FRAME") -?> centerFloat + , Just $ (stringProperty "WM_WINDOW_ROLE" =? "GtkFileChooseDialog") -?> centerFloatSmall + , Just $ (className =? "Nvidia-settings") -?> doCenterFloat + , Just $ fmap ("Minetest" `isInfixOf`) title -?> doIgnore + , Just $ fmap ("Automachef" `isInfixOf`) title -?> doIgnore + ]) + , hWsp = hWsp + , hCoWsp = hCoWsp + , hKeysMod = \conf -> Map.union $ (Map.fromList $ join $ map (spawnBindings conf) [ (xK_e, ["emacsclient -c"]) + , (xK_d, [fromString browser, fromString $ browser ++ " $(xclip -o)", fromString $ "notmuch-links"]) + , (xK_f, ["urxvtc -name comm -title Feeds -e mosh odin -- tmux new-session -ADs comm"]) + , (xK_c, [ inputPrompt xPConfig "dc" ?+ dc ]) + , (xK_g, ["pidgin"]) + , (xK_s, ["skype"]) + -- , (xK_p, [mkPassPrompt "Type password" pwType xPConfig, mkPassPrompt "Show password" pwShow xPConfig, mkPassPrompt "Copy password" pwClip xPConfig]) + , (xK_w, ["sudo rewacom"]) + , (xK_y, [ "tmux new-window -dt media /var/media/link.hs $(xclip -o)" + , "urxvtc -name media -e tmuxp load /var/media" + ]) + , (xK_l, [ "tmux new-window -dt media mpv $(xclip -o)" + , "tmux new-window -dt media streamlink --retry-open 10 $(xclip -o)" + ]) + , (xK_m, [ "emacsclient -c -F \"'(title . \\\"Mail\\\")\" -e '(notmuch)'" + , "emacsclient -c -F \"'(title . \\\"Mail\\\")\" -e '(notmuch-mua-new-mail)'" + , "emacsclient -c -F \"'(title . \\\"Mail\\\")\" -e \"(browse-url-mail \"$(xclip -o)\")\"" + ]) + , (xK_Return, ["keynav start,windowzoom", "keynav start"]) + , (xK_t, [inputPrompt xPConfig "fuzzytime timer" ?+ fuzzytime, fuzzytime "unset", work_fuzzytime]) + , (xK_a, [inputPrompt xPConfig "adjmix" ?+ adjmix]) + , (xK_s, [ inputPromptWithCompl xPConfig "start synergy" synergyCompl ?+ synergyStart + , inputPromptWithCompl xPConfig "stop synergy" synergyCompl ?+ synergyStop + ]) + , (xK_h, [ "urxvtc -name htop -e htop" + , "urxvtc -name log -e journalctl -xef" + ]) + , (xK_x, [ "autorandr -c" + , "autorandr -fl default" + ]) + , (xK_z, [ "zulip -- --force-device-scale-factor=2" + ]) + ]) + `Map.union` + ( Map.fromList [ ((XMonad.modMask conf .|. controlMask, xK_Return), namedScratchpadAction scratchpads "term") + , ((XMonad.modMask conf .|. controlMask, xK_a), namedScratchpadAction scratchpads "pavucontrol") + , ((XMonad.modMask conf .|. controlMask, xK_w), namedScratchpadAction scratchpads "alarms") + , ((XMonad.modMask conf .|. controlMask, xK_b), namedScratchpadAction scratchpads "blueman") + , ((XMonad.modMask conf .|. controlMask, xK_p), namedScratchpadAction scratchpads "keepassxc") + , ((XMonad.modMask conf .|. controlMask, xK_t), namedScratchpadAction scratchpads "toggl") + , ((XMonad.modMask conf .|. controlMask, xK_e), namedScratchpadAction scratchpads "emacs") + , ((XMonad.modMask conf .|. controlMask, xK_m), namedScratchpadAction scratchpads "calendar") + , ((XMonad.modMask conf .|. controlMask, xK_f), namedScratchpadAction scratchpads "music") + , ((XMonad.modMask conf .|. mod1Mask, xK_Up), rotate U) + , ((XMonad.modMask conf .|. mod1Mask, xK_Down), rotate D) + , ((XMonad.modMask conf .|. mod1Mask, xK_Left), rotate L) + , ((XMonad.modMask conf .|. mod1Mask, xK_Right), rotate R) + -- , ((XMonad.modMask conf .|. shiftMask, xK_a), startMute "hel") + ] ) + , hKeyUpKeys = \conf -> Map.fromList [ -- ((XMonad.modMask conf .|. shiftMask, xK_a), stopMute "hel") + ] + , hScreens = hScreens defaultHost + , hCmds = return [ ("prev-workspace", prevWS) + , ("next-workspace", nextWS) + , ("prev-window", rotAllDown) + , ("next-window", rotAllUp) + , ("banish", banishScreen LowerRight) + , ("update-gpg-tty", safeSpawn "gpg-connect-agent" ["UPDATESTARTUPTTY", "/bye"]) + , ("rescreen", rescreen) + , ("repanel", do + spawn "nm-applet" + spawn "blueman-applet" + spawn "pasystray" + spawn "kdeconnect-indicator" + spawn "dunst -print" + spawn "udiskie" + spawn "autocutsel -s PRIMARY" + spawn "autocutsel -s CLIPBOARD" + ) + , ("pause", mediaMpv $ MpvSetProperty "pause" True) + , ("unpause", mediaMpv $ MpvSetProperty "pause" False) + , ("exit", io $ exitWith ExitSuccess) + ] + } + where + withGdkScale act = void . xfork $ setEnv "GDK_SCALE" "2" >> act + workspaceNames = Map.fromList [ (1, "comm") + , (2, "web") + , (3, "work") + , (4, "read") + , (5, "monitor") + , (6, "uni") + , (9, "media") + , (10, "mpv") + ] + scratchpads = [ NS "term" "urxvtc -name scratchpad -title scratchpad -e tmux new-session -AD -s scratch" (resource =? "scratchpad") centerFloat + , NS "pavucontrol" "pavucontrol" (resource =? "pavucontrol") centerFloat + , NS "alarms" "alarm-clock-applet" (className =? "Alarm-clock-applet" <&&> title =? "Alarms") centerFloat + , NS "blueman" "blueman-manager" (className =? ".blueman-manager-wrapped") centerFloat + , NS "keepassxc" "keepassxc" (className =? "KeePassXC") centerFloat + , NS "toggl" "toggldesktop" (className =? "Toggl Desktop") centerFloat + , NS "calendar" "minetime -- --force-device-scale-factor=1.6" (className =? "MineTime") centerFloat + , NS "emacs" "emacsclient -c -F \"'(title . \\\"Scratchpad\\\")\"" (className =? "Emacs" <&&> title =? "Scratchpad") centerFloat + , NS "music" "google-play-music-desktop-player --force-device-scale-factor=1.6" (className =? "Google Play Music Desktop Player") centerFloat + ] + centerFloat = customFloating $ RationalRect (1 % 16) (1 % 16) (7 % 8) (7 % 8) + centerFloatSmall = customFloating $ RationalRect (1 % 4) (1 % 4) (1 % 2) (1 % 2) + hWsp = wspFromMap workspaceNames + hCoWsp = coWspFromMap workspaceNames + assign wsp test = (\wsp -> test -?> doShift wsp) <$> hCoWsp wsp + assign' :: [String] -> Query Bool -> Maybe MaybeManageHook + assign' wsps test = do + wsIds <- mapM hCoWsp wsps + return $ test -?> go wsIds + where + go :: [WorkspaceId] -> ManageHook + go wsps = do + visWsps <- liftX $ (\wset -> W.tag . W.workspace <$> W.current wset : W.visible wset) <$> gets windowset + case (filter (`elem` visWsps) wsps, wsps) of + (wsp : _, _) -> doShift wsp + (_, wsp : _) -> doShift wsp + ([], []) -> return mempty + rotate rot = do + safeSpawn "xrandr" ["--output", "eDP-1", "--rotate", xrandrDir] + mapM_ rotTouch touchscreens + where + xrandrDir = case rot of + U -> "normal" + L -> "left" + R -> "right" + D -> "inverted" + matrix = case rot of + U -> [ [ 1, 0, 0] + , [ 0, 1, 0] + , [ 0, 0, 1] + ] + L -> [ [ 0, -1, 1] + , [ 1, 0, 0] + , [ 0, 0, 1] + ] + R -> [ [ 0, 1, 0] + , [-1, 0, 1] + , [ 0, 0, 1] + ] + D -> [ [-1, 0, 1] + , [ 0, -1, 1] + , [ 0, 0, 1] + ] + touchscreens = [ "Wacom Co.,Ltd. Pen and multitouch sensor Finger touch" + , "Wacom Co.,Ltd. Pen and multitouch sensor Pen stylus" + , "Wacom Co.,Ltd. Pen and multitouch sensor Pen eraser" + ] + rotTouch screen = do + safeSpawn "xinput" $ ["set-prop", screen, "Coordinate Transformation Matrix"] ++ map (\n -> show n ++ ",") (concat matrix) + safeSpawn "xinput" ["map-to-output", screen, "eDP-1"] + withPw f label = io . void . forkProcess $ do + uninstallSignalHandlers + void $ createSession + (dropWhileEnd isSpace -> pw) <- readCreateProcess (proc "pass" ["show", label]) "" + void $ f pw + pwType :: String -> X () + pwType = withPw $ readCreateProcess (proc "xdotool" ["type", "--clearmodifiers", "--file", "-"]) + pwClip label = safeSpawn "pass" ["show", "--clip", label] + pwShow :: String -> X () + pwShow = withPw $ \pw -> do + xmessage <- fromMaybe "xmessage" <$> liftIO (lookupEnv "XMONAD_XMESSAGE") + readCreateProcess (proc xmessage ["-file", "-"]) pw + fuzzytime str = safeSpawn "fuzzytime" $ "timer" : words str + work_fuzzytime = io . void . forkProcess $ do + readCreateProcess (proc "worktime" []) "" >>= safeSpawn "fuzzytime" . ("timer" : ) . pure + adjmix str = safeSpawn "adjmix" $ words str + dc expr = void . xfork $ do + result <- readProcess "dc" [] $ expr ++ "f" + let + (first : rest) = filter (not . null) $ lines result + notification = Notify.summary first <> Notify.body (unlines rest) <> Notify.timeout Infinite <> Notify.urgency Normal <> Notify.appName "dc" + void $ Notify.display notification + synergyCompl = mkComplFunFromList' ["mathw86"] + synergyStart host = safeSpawn "systemctl" ["--user", "start", "synergy-rtunnel@" ++ host ++ ".service"] + synergyStop host = safeSpawn "systemctl" ["--user", "stop", "synergy-rtunnel@" ++ host ++ ".service"] + +hostFromName _ = defaultHost + +-- muteRef :: IORef (Maybe (String, Notification)) +-- {-# NOINLINE muteRef #-} +-- muteRef = unsafePerformIO $ newIORef Nothing + +-- startMute, stopMute :: String -> X () +-- startMute sink = liftIO $ do +-- muted <- isJust <$> readIORef muteRef +-- when (not muted) $ do +-- let +-- notification = Notify.summary "Muted" <> Notify.timeout Infinite <> Notify.urgency Normal +-- level = "0.0dB" +-- -- level <- runProcessWithInput "ssh" ["bragi", "cat", "/dev/shm/mix/" ++ sink ++ "/level"] "" +-- -- callProcess "ssh" ["bragi", "adjmix", "-t", sink, "-o", "0"] +-- hPutStrLn stderr "Mute" +-- writeIORef muteRef . Just . (level, ) =<< Notify.display notification +-- stopMute sink = liftIO $ do +-- let +-- unmute (Just (level, notification)) = do +-- hPutStrLn stderr "Unmute" +-- -- callProcess "ssh" ["bragi", "adjmix", "-t", sink, "-o", level] +-- Notify.close notification +-- unmute Nothing = return () +-- muted <- isJust <$> readIORef muteRef +-- when muted . join . atomicModifyIORef muteRef $ (Nothing, ) . unmute + +wspFromMap workspaceNames = \i -> case Map.lookup i workspaceNames of + Just str -> show i ++ " " ++ str + Nothing -> show i + +coWspFromMap workspaceNames = \str -> case filter ((== str) . snd) $ Map.toList workspaceNames of + [] -> Nothing + [(i, _)] -> Just $ wspFromMap workspaceNames i + _ -> Nothing + +spawnModifiers = [0, controlMask, shiftMask .|. controlMask] +spawnBindings :: XConfig layout -> (KeySym, [X ()]) -> [((KeyMask, KeySym), X ())] +spawnBindings conf (k, cmds) = zipWith (\m cmd -> ((modm .|. mod1Mask .|. m, k), cmd)) spawnModifiers cmds + where + modm = XMonad.modMask conf + +manageScratchTerm = (resource =? "scratchpad" <||> resource =? "keysetup") -?> doRectFloat $ RationalRect (1 % 16) (1 % 16) (7 % 8) (7 % 8) + +tabbedLayout t = renamed [Replace "Tabbed"] $ reflectHoriz $ t CustomShrink $ tabbedTheme +tabbedLayoutHoriz t = renamed [Replace "Tabbed Horiz"] $ reflectVert $ t CustomShrink $ tabbedTheme +tabbedTheme = def + { activeColor = "black" + , inactiveColor = "black" + , urgentColor = "black" + , activeBorderColor = "grey" + , inactiveBorderColor = "#202020" + , urgentBorderColor = "#bb0000" + , activeTextColor = "grey" + , inactiveTextColor = "grey" + , urgentTextColor = "grey" + , decoHeight = 32 + , fontName = "xft:Fira Mono for Powerline:style=Medium:pixelsize=22.5" + } + +main :: IO () +main = do + arguments <- either (const []) id <$> tryIOError getArgs + case arguments of + ["--command", s] -> do + d <- openDisplay "" + rw <- rootWindow d $ defaultScreen d + a <- internAtom d "XMONAD_COMMAND" False + m <- internAtom d s False + allocaXEvent $ \e -> do + setEventType e clientMessage + setClientMessageEvent e rw a 32 m currentTime + sendEvent d rw False structureNotifyMask e + sync d False + _ -> do + -- batteryMon <- xfork $ monitorBattery Nothing Nothing + hostname <- getHostName + let + host = hostFromName hostname + setEnv "HOST" hostname + let myConfig = withHostUrgency . ewmh $ docks def + { manageHook = hManageHook host + , terminal = "urxvtc" + , layoutHook = smartBorders . avoidStruts $ windowNavigation layout' + , logHook = do + dynamicLogString xmobarPP' >>= writeProps + updatePointer (99 % 100, 98 % 100) (0, 0) + , modMask = mod4Mask + , keys = \conf -> hKeysMod host conf $ myKeys' conf host + , workspaces = take (length numKeys) $ map wsp [1..] + , startupHook = setDefaultCursor xC_left_ptr + , normalBorderColor = "#202020" + , focusedBorderColor = "grey" + , handleEventHook = fullscreenEventHook <+> (serverModeEventHookCmd' $ hCmds host) <+> keyUpEventHook + } + writeProps str = do + let encodeCChar = map $ fromIntegral . fromEnum + atoms = [ "_XMONAD_WORKSPACES" + , "_XMONAD_LAYOUT" + , "_XMONAD_TITLE" + ] + (flip mapM_) (zip atoms (lines str)) $ \(atom', content) -> do + ustring <- getAtom "UTF8_STRING" + atom <- getAtom atom' + withDisplay $ \dpy -> io $ do + root <- rootWindow dpy $ defaultScreen dpy + changeProperty8 dpy root atom ustring propModeReplace $ encodeCChar content + sync dpy True + wsp = hWsp host + -- We can´t define per-host layout modifiers because we lack dependent types + layout' = onHost "skadhi" ( onWorkspace (wsp 1) (Full ||| withIM (1%5) (Title "Buddy List") tabbedLayout') $ + onWorkspace (wsp 10) Full $ + onWorkspace (wsp 2) (Full ||| tabbedLayout') $ + onWorkspace (wsp 5) tabbedLayout' $ + onWorkspace (wsp 8) (withIM (1%5) (Title "Friends") tabbedLayout') $ + defaultLayouts + ) $ + onHost "vali" ( onWorkspace (wsp 2) (Full ||| tabbedLayout' ||| combineTwo (TwoPane 0.01 0.57) Full tabbedLayout') $ + onWorkspace (wsp 3) workLayouts $ + defaultLayouts + ) $ + onHost "hel" ( onWorkspace (wsp 1) (withIM (1 % 8) (Title "Buddy List") $ trackFloating tabbedLayout') $ + onWorkspace (wsp 2) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $ + onWorkspace (wsp 3) workLayouts $ + onWorkspace (wsp 6) workLayouts $ + onWorkspace (wsp 4) (tabbedLayout' ||| tabbedLayoutHoriz' ||| Dwindle R CW 1 (5 % 100)) $ + onWorkspace (wsp 5) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $ + onWorkspace (wsp 10) (tabbedLayout''' ||| combineTwoP (TwoPane (1 % 100) (3 % 4)) tabbedLayout''' tabbedLayout''' (ClassName "mpv") ||| Dwindle R CW 1 (5 % 100)) $ + defaultLayouts + ) $ + onHost "sif" ( onWorkspace (wsp 1) (withIM (1 % 8) (Title "Buddy List") $ trackFloating tabbedLayout') $ + onWorkspace (wsp 2) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $ + onWorkspace (wsp 3) workLayouts $ + onWorkspace (wsp 6) workLayouts $ + onWorkspace (wsp 4) (tabbedLayout' ||| tabbedLayoutHoriz' ||| Dwindle R CW 1 (5 % 100)) $ + onWorkspace (wsp 5) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $ + onWorkspace (wsp 10) (tabbedLayout''' ||| combineTwoP (TwoPane (1 % 100) (3 % 4)) tabbedLayout''' tabbedLayout''' (ClassName "mpv") ||| Dwindle R CW 1 (5 % 100)) $ + defaultLayouts + ) $ + defaultLayouts + -- tabbedLayout''' = renamed [Replace "Tabbed'"] $ IfMax 1 (noBorders Full) (tabbedLayout tabbedBottomAlways) + tabbedLayout''' = tabbedLayout tabbedBottom + tabbedLayout' = tabbedLayout tabbedBottomAlways + tabbedLayoutHoriz' = tabbedLayoutHoriz tabbedLeftAlways + defaultLayouts = {- spiralWithDir East CW (1 % 2) -} Dwindle R CW 1 (5 % 100) ||| tabbedLayout' ||| Full + -- workLayouts = {- spiralWithDir East CW (1 % 2) -} Dwindle R CW (2 % 1) (5 % 100) ||| tabbedLayout' ||| Full + workLayouts = tabbedLayout' ||| (renamed [Replace "Combined"] $ combineTwoP (TwoPane (1 % 100) (1891 % 2560)) tabbedLayout''' (Column 1.6) (ClassName "Postman" `Or` ClassName "Emacs" `Or` ClassName "jetbrains-idea-ce" `Or` (Resource "Devtools" `And` ClassName "Firefox"))) ||| Full ||| Dwindle R CW 1 (5 % 100) + sqrtTwo = approxRational (sqrt 2) (1 / 2560) + xmobarPP' = xmobarPP { ppTitle = shorten 80 + , ppSort = (liftM2 (.)) getSortByIndex $ return scratchpadFilterOutWorkspace + , ppUrgent = wrap "(" ")" . xmobarColor "red" "" + , ppHiddenNoWindows = xmobarColor "#202020" "" . wrap "(" ")" + , ppVisible = wrap "(" ")" . xmobarColor "yellow" "" + , ppCurrent = wrap "(" ")" . xmobarColor "green" "" + , ppHidden = wrap "(" ")" + , ppWsSep = " " + , ppSep = "\n" + } + withHostUrgency = case hostname of + "hel" -> withUrgencyHookC urgencyHook' $ urgencyConfig { suppressWhen = U.Never, remindWhen = Dont } + "sif" -> withUrgencyHookC urgencyHook' $ urgencyConfig { suppressWhen = U.Never, remindWhen = Dont } + _ -> id + urgencyHook' window = do + runQuery ((resource =? "comm" <||> resource =? "Pidgin" <||> className =? "Gajim" <||> className =? "Skype") --> safeSpawn "thinklight" ["Blink", "100"]) window + urgencyHook (BorderUrgencyHook { urgencyBorderColor = "#bb0000" }) window + shutdown :: SomeException -> IO a + shutdown e = do + let pids = [ -- batteryMon + ] + mapM_ (signalProcess sigTERM) pids + mapM_ (getProcessStatus False False) pids + throw e + keyUpEventHook :: Event -> X All + keyUpEventHook event = handle event >> return (All True) + where + handle (KeyEvent { ev_event_type = t, ev_state = m, ev_keycode = code }) + | t == keyRelease = withDisplay $ \dpy -> do + s <- io $ keycodeToKeysym dpy code 0 + mClean <- cleanMask m + ks <- asks $ hKeyUpKeys host . config + userCodeDef () $ whenJust (Map.lookup (mClean, s) ks) id + | otherwise = return () + handle _ = return () + handle shutdown $ launch myConfig + +secs :: Int -> Int +secs = (* 1000000) + +-- monitorBattery :: Maybe BatteryContext -> Maybe Notification -> IO () +-- monitorBattery Nothing n = do +-- ctx <- batteryContextNew +-- case ctx of +-- Nothing -> threadDelay (secs 10) >> monitorBattery Nothing n +-- Just _ -> monitorBattery ctx n +-- monitorBattery ctx@(Just ctx') n = do +-- batInfo <- getBatteryInfo ctx' +-- case batInfo of +-- Nothing -> threadDelay (secs 1) >> monitorBattery ctx n +-- Just batInfo -> do +-- let n' +-- | batteryState batInfo == BatteryStateDischarging +-- , timeLeft <= 1200 +-- , timeLeft > 0 = Just $ summary "Discharging" <> hint "value" percentage <> urgency u <> body (duz timeLeft ++ "left") +-- | otherwise = Nothing +-- u +-- | timeLeft <= 600 = Critical +-- | timeLeft <= 1800 = Normal +-- | otherwise = Low +-- timeLeft = batteryTimeToEmpty batInfo +-- percentage :: Int32 +-- percentage = round $ batteryPercentage batInfo +-- ts = [("s", 60), ("m", 60), ("h", 24), ("d", 365), ("y", 1)] +-- duz ms = ss +-- where (ss, _) = foldl (\(ss, x) (s, y) -> ((if rem x y > 0 then show (rem x y) ++ s ++ " " else "") ++ ss , quot x y)) ("", ms) ts +-- case n' of +-- Just n' -> Notify.display (maybe mempty reuse n <> Notify.appName "monitorBattery" <> n') >>= (\n -> threadDelay (secs 2) >> monitorBattery ctx (Just n)) +-- Nothing -> threadDelay (secs 30) >> monitorBattery ctx n + +disableTouchpad, disableTrackpoint, enableTrackpoint, enableTouchpad :: X () +enableTouchpad = safeSpawn "xinput" ["enable", "SynPS/2 Synaptics TouchPad"] +disableTouchpad = safeSpawn "xinput" ["disable", "SynPS/2 Synaptics TouchPad"] +enableTrackpoint = safeSpawn "xinput" ["enable", "TPPS/2 IBM TrackPoint"] +disableTrackpoint = safeSpawn "xinput" ["disable", "TPPS/2 IBM TrackPoint"] + +isDisabled :: String -> X Bool +isDisabled str = do + out <- runProcessWithInput "xinput" ["list", str] "" + return $ "disabled" `isInfixOf` out + + +spawnKeychain :: X () +spawnKeychain = do + home <- liftIO getHomeDirectory + let keys = (map ((home ) . (".ssh/" ++)) ["id", "id-rsa"]) ++ ["6B13AA67"] + liftIO (maybe (return ()) (setEnv "SSH_ASKPASS") =<< findAskpass) + safeSpawn "keychain" . (["--agents", "gpg,ssh"] ++)=<< liftIO (filterM doesFileExist keys) + where + findAskpass = filter `liftM` readFile "/etc/zshrc" + filter = listToMaybe . catMaybes . map (stripPrefix "export SSH_ASKPASS=") . lines + +assimilateKeychain :: X () +assimilateKeychain = liftIO $ assimilateKeychain' >> return () +assimilateKeychain' = tryIOError $ do + -- pid <- getProcessID + -- tmpDir <- lookupEnv "TMPDIR" + -- let tmpDir' = fromMaybe "/tmp" tmpDir + -- tmpFile = tmpDir' "xmonad-keychain" ++ (show pid) ++ ".env" + env <- runProcessWithInput "sh" ["-c", "eval $(keychain --eval --noask --agents gpg,ssh); env"] "" -- > " ++ tmpFile] "" + -- env <- readFile tmpFile + let envVars = Map.fromList $ map (\(k, v) -> (k, tail' v)) $ map (span (/= '=')) $ envLines + envVars' = Map.filterWithKey (\k _ -> k `elem` transfer) envVars + transfer = ["SSH_AUTH_SOCK", "SSH_AGENT_PID", "GPG_AGENT_INFO"] + envLines = filter (elem '=') $ lines env :: [String] + sequence $ map (\(k, c) -> setEnv k c) $ Map.toList envVars' + -- removeFile tmpFile + where + tail' [] = [] + tail' (x:xs) = xs + + +numKeys = [xK_parenleft, xK_parenright, xK_braceright, xK_plus, xK_braceleft, xK_bracketright, xK_bracketleft, xK_exclam, xK_equal, xK_asterisk] + +instance Shrinker CustomShrink where + shrinkIt _ "" = [""] + shrinkIt s cs + | length cs >= 4 = cs : shrinkIt s ((reverse . drop 4 . reverse $ cs) ++ "...") + | otherwise = cs : shrinkIt s (init cs) + +xPConfig :: XPConfig +xPConfig = def + { font = "xft:Fira Mono for Powerline:style=Medium:pixelsize=22.5" + , height = 32 + , bgColor = "black" + , fgColor = "grey" + , fgHLight = "green" + , bgHLight = "black" + , borderColor = "grey" + , searchPredicate = (\needle haystack -> all (`isInfixOf` map toLower haystack) . map (map toLower) $ words needle) + , position = Top + } + +sshOverrides = map (\h -> mkOverride { oHost = h, oCommand = moshCmd . inTmux } ) + [ + "odin", "odin.asgard.yggdrasil" + , "ymir", "ymir.yggdrasil.li", "ymir.niflheim.yggdrasil" + , "surtr", "yggdrasil.li", "surtr.yggdrasil.li", "praseodym.org", "surtr.praseodym.org", "surtr.141.li", "141.li" + , "vindler", "vindler.alfheim.yggdrasil" + , "ullr" + , "heimdallr", "heimdallr.asgard.yggdrasil" + , "testworx" + ] + ++ + map (\h -> mkOverride { oHost = h, oCommand = moshCmd' "/run/current-system/sw/bin/mosh-server" . withEnv [("TERM", "xterm")] . inTmux} ) + [ "bragi", "bragi.asgard.yggdrasil" + ] + ++ + map (\h -> mkOverride { oHost = h, oCommand = sshCmd . withEnv [("TERM", "xterm")] . inTmux } ) + [ "remote.cip.ifi.lmu.de" + , "uniworx3", "uniworx4", "uniworxdb" + ] + +backlight :: (Rational -> Rational) -> X () +backlight f = void . xfork . liftIO $ do + [ _device + , _class + , read . Text.unpack -> currentBright + , _currentPercentage + , read . Text.unpack -> maximumBright + ] <- Text.splitOn "," . Text.pack <$> readProcess "brightnessctl" ["-m"] "" + let current = currentBright % maximumBright + new' = f current * fromIntegral maximumBright + new :: Integer + new | floor new' < 0 = 0 + | ceiling new' > maximumBright = maximumBright + | new' >= maximumBright % 2 = ceiling new' + | otherwise = floor new' + callProcess "brightnessctl" ["-m", "s", show new] + +cycleThrough :: [Rational] -> (Rational -> Rational) +cycleThrough opts current = fromMaybe currentOpt $ listToMaybe next' + where currentOpt = minimumBy (comparing $ abs . subtract current) opts + (_, _ : next') = break (== currentOpt) opts + +cycleKbLayout :: [(String, Maybe String)] -> X () +cycleKbLayout [] = return () +cycleKbLayout layouts = liftIO $ do + next <- (getNext . extract) `liftM` runProcessWithInput "setxkbmap" ["-query"] "" + let + args = case next of + (l, Just v) -> [l, v] + (l, Nothing) -> [l] + safeSpawn "setxkbmap" args + where + extract :: String -> Maybe (String, Maybe String) + extract str = listToMaybe $ do + ["layout:", l] <- str' + [(l, Just v) | ["variant:", v] <- str'] ++ pure (l, Nothing) + where + str' = map words $ lines str + getNext :: Maybe (String, Maybe String) -> (String, Maybe String) + getNext = maybe (head layouts) getNext' + getNext' x = case elemIndex x layouts of + Nothing -> getNext Nothing + Just i -> layouts !! ((i + 1) `mod` length layouts) + +mpvAll' :: MpvCommand -> IO [MpvResponse] +mpvAll' = mpvAll "/var/media/.mpv-ipc" + +mpvOne' :: MpvCommand -> IO (Maybe MpvResponse) +mpvOne' = mpvOne "/var/media/.mpv-ipc" + +mediaMpv :: MpvCommand -> X () +mediaMpv cmd = void . xfork $ print =<< mpvAll' cmd + +mediaMpvTogglePause :: X () +mediaMpvTogglePause = void . xfork $ do + paused <- mapM mpvResponse <=< mpvAll' $ MpvGetProperty "pause" + if + | and paused -> print <=< mpvAll' $ MpvSetProperty "pause" False + | otherwise -> print <=< mpvOne' $ MpvSetProperty "pause" True + +myKeys' conf host = Map.fromList $ + -- launch a terminal + [ ((modm, xK_Return), spawn $ (XMonad.terminal conf) ++ " -e tmux") + , ((modm .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf) + + -- launch dmenu + --, ((modm, xK_d ), spawn "exe=`dmenu_path | dmenu` && eval \"exec $exe\"") + , ((modm, xK_d ), shellPrompt "Run: " xPConfig) + , ((modm .|. shiftMask, xK_d ), prompt "Run in Terminal: " ("urxvtc" ++ " -e") xPConfig) + , ((modm, xK_at ), sshPrompt sshOverrides xPConfig) + + -- close focused window + , ((modm .|. shiftMask, xK_q ), kill) + , ((modm .|. controlMask .|. shiftMask, xK_q ), spawn "xkill") + + -- Rotate through the available layout algorithms + , ((modm, xK_space ), sendMessage NextLayout) + + -- Reset the layouts on the current workspace to default + , ((modm .|. controlMask, xK_r ), (setLayout $ XMonad.layoutHook conf) >> refresh) + + -- Resize viewed windows to the correct size + , ((modm, xK_r ), refresh) + + -- Move focus to the next window + , ((modm, xK_t ), windows W.focusDown) + + -- Move focus to the previous window + , ((modm, xK_n ), windows W.focusUp ) + + -- Move focus to the master window + , ((modm, xK_m ), windows W.focusMaster ) + + -- Swap the focused window and the master window + , ((modm .|. shiftMask, xK_m ), windows W.swapMaster) + + -- Swap the focused window with the next window + , ((modm .|. shiftMask, xK_t ), windows W.swapDown ) + + -- Swap the focused window with the previous window + , ((modm .|. shiftMask, xK_n ), windows W.swapUp ) + + -- Swap the focused window with the previous window + , ((modm .|. shiftMask .|. controlMask, xK_m), sendMessage SwapWindow) + + , ((modm, xK_Right), sendMessage $ Go R) + , ((modm, xK_Left ), sendMessage $ Go L) + , ((modm, xK_Up ), sendMessage $ Go U) + , ((modm, xK_Down ), sendMessage $ Go D) + , ((modm .|. shiftMask , xK_Right), sendMessage $ Move R) + , ((modm .|. shiftMask , xK_Left ), sendMessage $ Move L) + , ((modm .|. shiftMask , xK_Up ), sendMessage $ Move U) + , ((modm .|. shiftMask , xK_Down ), sendMessage $ Move D) + -- , ((modm .|. controlMask, xK_Right), withFocused $ keysMoveWindow (10, 0)) + -- , ((modm .|. controlMask, xK_Left ), withFocused $ keysMoveWindow (-10, 0)) + -- , ((modm .|. controlMask, xK_Up ), withFocused $ keysMoveWindow (0, -10)) + -- , ((modm .|. controlMask, xK_Down ), withFocused $ keysMoveWindow (0, 10)) + -- Shrink the master area + , ((modm, xK_h ), sendMessage Shrink) + + -- Expand the master area + , ((modm, xK_s ), sendMessage Expand) + + -- Push window back into tiling + , ((modm .|. shiftMask, xK_space ), withFocused $ windows . W.sink) + , ((modm, xK_BackSpace), focusUrgent) + , ((modm .|. shiftMask, xK_BackSpace), clearUrgents) + + -- Increment the number of windows in the master area + , ((modm , xK_comma ), sendMessage (IncMasterN 1)) + + -- Deincrement the number of windows in the master area + , ((modm , xK_period), sendMessage (IncMasterN (-1))) + + , ((0, xF86XK_AudioRaiseVolume), safeSpawn "pulseaudio-ctl" ["up", "2"]) + , ((0, xF86XK_AudioLowerVolume), safeSpawn "pulseaudio-ctl" ["down", "2"]) + , ((0, xF86XK_AudioMute), safeSpawn "pulseaudio-ctl" ["mute"]) + , ((0, xF86XK_AudioPause), mediaMpv $ MpvSetProperty "pause" False) + , ((0, {-xF86XK_AudioMicMute-} 269025202), safeSpawn "pulseaudio-ctl" ["mute-input"]) + , ((0, xF86XK_AudioPlay), mediaMpvTogglePause) + , ((modm .|. mod1Mask, xK_space), mediaMpvTogglePause) + + , ((0, xF86XK_MonBrightnessDown), backlight (subtract 5)) + , ((0, xF86XK_MonBrightnessUp), backlight (+ 5)) + + , ((modm , xK_Escape), cycleKbLayout (hKbLayouts host)) + , ((modm .|. controlMask, xK_Escape), safeSpawn "setxkbmap" $ fst (head $ hKbLayouts host) : maybeToList (snd . head $ hKbLayouts host)) + + -- Toggle the status bar gap + -- Use this binding with avoidStruts from Hooks.ManageDocks. + -- See also the statusBar function from Hooks.DynamicLog. + -- + , ((modm , xK_b ), sendMessage ToggleStruts) + + , ((modm .|. shiftMask, xK_p ), safeSpawn "playerctl" ["-a", "pause"]) + + -- Quit xmonad + , ((modm .|. shiftMask, xK_e ), io (exitWith ExitSuccess)) + + -- Restart xmonad + -- , ((modm .|. shiftMask .|. controlMask, xK_r ), void . xfork $ recompile False >>= flip when (safeSpawn "xmonad" ["--restart"])) + , ((modm .|. shiftMask, xK_r ), void . liftIO $ executeFile "xmonad" True [] Nothing) + , ((modm .|. shiftMask, xK_l ), void . xfork $ do + sessId <- getEnv "XDG_SESSION_ID" + safeSpawn "loginctl" ["lock-session", sessId] + ) + , ((modm .|. shiftMask, xK_s ), safeSpawn "systemctl" ["suspend"]) + , ((modm .|. shiftMask, xK_h ), safeSpawn "systemctl" ["hibernate"]) + , ((modm .|. shiftMask, xK_b ), backlight $ cycleThrough [1, 3 % 4, 1 % 2, 1 % 4, 1 % 10, 1 % 100, 0] + ) + , ((modm .|. shiftMask .|. controlMask, xK_b), backlight $ cycleThrough [0, 1 % 100, 1 % 10, 1 % 4, 1 % 2, 3 % 4, 1] + ) + , ((modm, xK_v ), windows copyToAll) -- @@ Make focused window always visible + , ((modm .|. shiftMask, xK_v ), killAllOtherCopies) -- @@ Toggle window state back + , ((modm .|. shiftMask, xK_g ), windowPrompt xPConfig Goto wsWindows) + , ((modm .|. shiftMask .|. controlMask, xK_g ), windowPrompt xPConfig Bring allWindows) + ] + ++ + + -- + -- mod-[1..9], Switch to workspace N + -- + -- mod-[1..9], Switch to workspace N + -- mod-shift-[1..9], Move client to workspace N + -- + [((m .|. modm, k), windows $ f i) + | (i, k) <- zip (XMonad.workspaces conf) $ numKeys + , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)] + ] + ++ + [((m .|. modm .|. controlMask, k), void . runMaybeT $ + MaybeT (P.getScreen def i) >>= MaybeT . screenWorkspace >>= lift . windows . f + ) + | (i, k) <- zip (hScreens host) [xK_g, xK_c, xK_r, xK_l] + , (f, m) <- [(W.view, 0), (W.shift, shiftMask)] + ] + where + modm = XMonad.modMask conf + + diff --git a/accounts/gkleen@sif/xresources.nix b/accounts/gkleen@sif/xresources.nix new file mode 100644 index 00000000..3bd9af2c --- /dev/null +++ b/accounts/gkleen@sif/xresources.nix @@ -0,0 +1,46 @@ +{ + "Xft.dpi" = 282; + "Xft.autohint" = false; + "Xft.lcdfilter" = "lcddefault"; + "Xft.hintstyle" = "hintfull"; + "Xft.hinting" = true; + "Xft.antialias" = true; + "Xft.rgba" = "rgb"; + + # special + "*.foreground" = "#d9d9d9"; + "*.background" = "#000000"; + "*.cursorColor" = "#d9d9d9"; + + # black + "*.color0" = "#000000"; + "*.color8" = "#757a80"; + + # red + "*.color1" = "#bf4949"; + "*.color9" = "#e66e6e"; + + # green + "*.color2" = "#9fb346"; + "*.color10" = "#cbd676"; + + # yellow + "*.color3" = "#e69650"; + "*.color11" = "#ffa74f"; + + # blue + "*.color4" = "#759fbf"; + "*.color12" = "#98b8d9"; + + # magenta + "*.color5" = "#9b79a6"; + "*.color13" = "#ceadd9"; + + # cyan + "*.color6" = "#79a69b"; + "*.color14" = "#a3d9ce"; + + # white + "*.color7" = "#d9d9d9"; + "*.color15" = "#ffffff"; +} \ No newline at end of file diff --git a/overlays/nerdfonts.nix b/overlays/nerdfonts.nix new file mode 100644 index 00000000..28581d72 --- /dev/null +++ b/overlays/nerdfonts.nix @@ -0,0 +1,5 @@ +final: prev: { + nerdfonts = prev.nerdfonts.override { + fonts = ["FiraMono" "FiraCode"]; + }; +} diff --git a/overlays/pidgin.nix b/overlays/pidgin.nix new file mode 100644 index 00000000..09103ade --- /dev/null +++ b/overlays/pidgin.nix @@ -0,0 +1,20 @@ +final: prev: +prev.lib.composeManyExtensions [ + (final: prev: + let + mucHistory = prev.fetchpatch { + url = "https://developer.pidgin.im/raw-attachment/ticket/16524/0001-only-request-unseed-chat-history-from-jabber-group-c.patch"; + sha256 = "083wvmq7417xz55fxxhllqwql1hgjvin2sak08844121yw1jvc44"; + }; + in { + pidgin = prev.pidgin.overrideAttrs (oldAttrs: { + patches = (oldAttrs.patches or []) ++ [mucHistory]; + }); + }) + (final: prev: { + pidgin-with-plugins = import (/. + prev.path + "/pkgs/applications/networking/instant-messengers/pidgin/wrapper.nix") { + inherit (prev) makeWrapper symlinkJoin pidgin; + plugins = with final; [ purple-lurch pidgin-carbons pidgin-opensteamworks pidgin-xmpp-receipts ]; + }; + }) +] final prev diff --git a/overlays/urxvt/52-osc.pl b/overlays/urxvt/52-osc.pl new file mode 100644 index 00000000..3292e8c4 --- /dev/null +++ b/overlays/urxvt/52-osc.pl @@ -0,0 +1,41 @@ +#! perl + +=head1 NAME + +52-osc - Implement OSC 32 ; Interact with X11 clipboard + +=head1 SYNOPSIS + + urxvt -pe 52-osc + +=head1 DESCRIPTION + +This extension implements OSC 52 for interacting with system clipboard + +Most code stolen from: +http://ailin.tucana.uberspace.de/static/nei/*/Code/urxvt/ + +=cut + +use MIME::Base64; +use Encode; + +sub on_osc_seq { + my ($term, $op, $args) = @_; + return () unless $op eq 52; + + my ($clip, $data) = split ';', $args, 2; + if ($data eq '?') { + # my $data_free = $term->selection(); + # Encode::_utf8_off($data_free); # XXX + # $term->tt_write("\e]52;$clip;".encode_base64($data_free, '')."\a"); + } + else { + my $data_decoded = decode_base64($data); + Encode::_utf8_on($data_decoded); # XXX + $term->selection($data_decoded, $clip =~ /c|^$/); + $term->selection_grab(urxvt::CurrentTime, $clip =~ /c|^$/); + } + + () +} diff --git a/overlays/urxvt/default.nix b/overlays/urxvt/default.nix new file mode 100644 index 00000000..3c57d000 --- /dev/null +++ b/overlays/urxvt/default.nix @@ -0,0 +1,21 @@ +final: prev: { + rxvt_unicode-with-plugins = prev.rxvt-unicode.override { + configure = { availablePlugins, ... }: { + plugins = [ final.urxvt_osc_52 ] ++ builtins.attrValues availablePlugins; + }; + }; + urxvt_osc_52 = prev.stdenv.mkDerivation { + name = "rxvt_unicode-osc_52-0"; + src = ./52-osc.pl; + unpackPhase = '' + cp $src 52-osc + ''; + buildPhase = '' + sed -i 's|#! perl|#! ${final.perl}/bin/perl|g' 52-osc + ''; + installPhase = '' + mkdir -p $out/lib/urxvt/perl + cp 52-osc $out/lib/urxvt/perl + ''; + }; +} diff --git a/user-profiles/mpv/default.nix b/user-profiles/mpv/default.nix new file mode 100644 index 00000000..ae791668 --- /dev/null +++ b/user-profiles/mpv/default.nix @@ -0,0 +1,83 @@ +{ userName, pkgs, ... }: +{ + home-manager.users.${userName}.programs.mpv = { + enable = true; + bindings = { + "CTRL+n" = "af toggle \"lavfi=[dynaudnorm=f=100:g=31:s=20.0]\""; + }; + config = { + ytdl = true; + ytdl-format = "bestvideo[width<=2560][height<=1440][fps<=60][protocol!=http_dash_segments]+bestaudio[protocol!=http_dash_segments]/best[width<=2560][height<=1440][fps<=60][protocol!=http_dash_segments]/best[protocol!=http_dash_segments]"; + ytdl-raw-options = "netrc=,mark-watched="; + sub = false; + osd-font = "DejaVu Sans"; + vo = "gpu"; + hwdec = "auto"; + force-window = "yes"; + script-opts = "osc-layout=topbar,vidscale=no,deadzonesize=0.9"; + af = "lavfi=[dynaudnorm=f=100:g=31:s=20.0]"; + }; + scripts = let + reload = pkgs.stdenv.mkDerivation rec { + version = "2b8a719f"; + pname = "reload"; + name = "${pname}-${version}"; + + src = pkgs.fetchFromGitHub { + owner = "4e6"; + repo = "mpv-reload"; + rev = "2b8a719fe166d6d42b5f1dd64761f97997b54a86"; + sha256 = "19ycvnwzf8vgv0g63d4k1ll6hlfrd92is9gl8hzfic7w32ycphbg"; + }; + + installPhase = '' + install -d $out/share/mpv/scripts + install -m 0644 reload.lua $out/share/mpv/scripts/${passthru.scriptName} + ''; + + passthru.scriptName = "reload.lua"; + }; + autosave = pkgs.stdenv.mkDerivation rec { + version = "0bv9wjrq"; + pname = "autosave"; + name = "${pname}-${version}.lua"; + + src = pkgs.fetchzip { + url = "https://gist.github.com/Hakkin/5489e511bd6c8068a0fc09304c9c5a82/archive/7a19f7cdb6dd0b1c6878b41e13b244e2503c15fc.zip"; + sha256 = "0bv9wjrqm2ragd7rp8vw768bja2ghascwlljd6rzzf2ybi10fxs2"; + }; + + installPhase = '' + install -d $out/share/mpv/scripts + install -m 0644 autosave.lua $out/share/mpv/scripts/${passthru.scriptName} + ''; + + passthru.scriptName = "autosave.lua"; + }; + mpris = pkgs.stdenv.mkDerivation rec { + version = "0.4"; + pname = "mpv-mpris"; + name = "${pname}-${version}.so"; + + src = pkgs.fetchFromGitHub { + owner = "hoyon"; + repo = "mpv-mpris"; + rev = version; + sha256 = "1fr3jvja8s2gdpx8qyk9r17977flms3qpm8zci62nd9r5wjdvr5i"; + }; + + installPhase = '' + install -d $out/share/mpv/scripts + install -m 0644 mpris.so $out/share/mpv/scripts/${passthru.scriptName} + ''; + + nativeBuildInputs = with pkgs; [ pkgconfig glib mpv ]; + + passthru.scriptName = "mpris.so"; + }; + in [ reload + autosave + mpris + ]; + }; +} diff --git a/user-profiles/tmux/default.nix b/user-profiles/tmux/default.nix new file mode 100644 index 00000000..9e66cadd --- /dev/null +++ b/user-profiles/tmux/default.nix @@ -0,0 +1,26 @@ +{ userName, pkgs, lib, ... }: +{ + home-manager.users.${userName} = { + programs.tmux = { + enable = true; + clock24 = true; + historyLimit = 50000; + extraConfig = lib.readFile (pkgs.stdenv.mkDerivation { + name = "tmux.conf"; + src = ./tmux.conf; + + buildInputs = with pkgs; [ makeWrapper ]; + + phases = [ "installPhase" ]; + + inherit (pkgs) zsh; + mandb = pkgs.man-db; + + installPhase = '' + substituteAll $src $out + ''; + }); + tmuxp.enable = true; + }; + }; +} diff --git a/user-profiles/tmux/tmux.conf b/user-profiles/tmux/tmux.conf new file mode 100644 index 00000000..1403698d --- /dev/null +++ b/user-profiles/tmux/tmux.conf @@ -0,0 +1,25 @@ +set-option -g history-limit 50000 +set-option -g status-bg black +set-option -g status-fg white +set-option -g clock-mode-colour white +set-option -g clock-mode-style 24 +set-option -g bell-action any +set-option -g default-shell @zsh@/bin/zsh +set-option -g update-environment 'DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY PROMPT_INFO PATH PGHOST PGLOG' +set-option -g mouse on +set-option -g set-clipboard on +set-option -g terminal-overrides 'rxvt-uni*:XT:Ms=\E]52;%p1%s;%p2%s\007' + +## determine if we should enable 256-colour support +if "[[ ''${TERM} =~ 256color || ''${TERM} == fbterm ]]" 'set -g default-terminal tmux-256color' + +set-option -g status-right "" + +bind / command-prompt "split-window -h 'exec @mandb@/bin/man %%'" +bind C clock-mode +bind r respawn-pane -k + +bind -n M-Left select-pane -L +bind -n M-Right select-pane -R +bind -n M-Up select-pane -U +bind -n M-Down select-pane -D \ No newline at end of file diff --git a/user-profiles/utils.nix b/user-profiles/utils.nix new file mode 100644 index 00000000..1de9e4eb --- /dev/null +++ b/user-profiles/utils.nix @@ -0,0 +1,22 @@ +{ userName, pkgs, ... }: +{ + home-manager.users.${userName} = { + programs = { + htop = { + enable = true; + delay = 5; + highlightBaseName = true; + treeView = true; + }; + + jq.enable = true; + }; + + home.packages = with pkgs; [ + autossh usbutils pciutils exa ag pwgen unzip magic-wormhole + qrencode tty-clock dnsutils openssl sshfs psmisc mosh tree + vnstat file pv bc fast-cli zip nmap aspell aspellDicts.de + aspellDicts.en borgbackup man-pages rsync socat telnet yq + ]; + }; +} diff --git a/user-profiles/zsh/default.nix b/user-profiles/zsh/default.nix new file mode 100644 index 00000000..58fa0376 --- /dev/null +++ b/user-profiles/zsh/default.nix @@ -0,0 +1,30 @@ +{ userName, pkgs, customUtils, lib, config, ... }: +let + dotDir = ".config/zsh"; + p10kZsh = "${dotDir}/.p10k.zsh"; + cfg = config.home-manager.users.${userName}; +in { + home-manager.users.${userName} = { + programs.zsh = { + inherit dotDir; + enable = true; + autocd = true; + enableCompletion = true; + + plugins = [ + { name = "powerlevel10k"; + file = "share/zsh-powerlevel10k/powerlevel10k.zsh-theme"; + src = pkgs.zsh-powerlevel10k; + } + ]; + initExtraBeforeCompInit = '' + source "${cfg.home.homeDirectory}/${p10kZsh}" + ''; + initExtra = lib.mkAfter '' + source "${pkgs.zsh-syntax-highlighting}/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" + ''; + }; + + home.file.${p10kZsh}.source = ./p10k.zsh; + }; +} diff --git a/user-profiles/zsh/p10k.zsh b/user-profiles/zsh/p10k.zsh new file mode 100644 index 00000000..517b6a9b --- /dev/null +++ b/user-profiles/zsh/p10k.zsh @@ -0,0 +1,1548 @@ +# Generated by Powerlevel10k configuration wizard on 2020-10-15 at 12:01 UTC. +# Based on romkatv/powerlevel10k/config/p10k-lean.zsh. +# Wizard options: nerdfont-complete + powerline, small icons, unicode, lean, 24h time, +# 2 lines, solid, no frame, dark-ornaments, sparse, many icons, concise, +# transient_prompt, instant_prompt=off. +# Type `p10k configure` to generate another config. +# +# Config for Powerlevel10k with lean prompt style. Type `p10k configure` to generate +# your own config based on it. +# +# Tip: Looking for a nice color? Here's a one-liner to print colormap. +# +# for i in {0..255}; do print -Pn "%K{$i} %k%F{$i}${(l:3::0:)i}%f " ${${(M)$((i%6)):#3}:+$'\n'}; done + +# Temporarily change options. +'builtin' 'local' '-a' 'p10k_config_opts' +[[ ! -o 'aliases' ]] || p10k_config_opts+=('aliases') +[[ ! -o 'sh_glob' ]] || p10k_config_opts+=('sh_glob') +[[ ! -o 'no_brace_expand' ]] || p10k_config_opts+=('no_brace_expand') +'builtin' 'setopt' 'no_aliases' 'no_sh_glob' 'brace_expand' + +() { + emulate -L zsh -o extended_glob + + # Unset all configuration options. This allows you to apply configuration changes without + # restarting zsh. Edit ~/.p10k.zsh and type `source ~/.p10k.zsh`. + unset -m '(POWERLEVEL9K_*|DEFAULT_USER)~POWERLEVEL9K_GITSTATUS_DIR' + + # Zsh >= 5.1 is required. + autoload -Uz is-at-least && is-at-least 5.1 || return + + # The list of segments shown on the left. Fill it with the most important segments. + typeset -g POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=( + # =========================[ Line #1 ]========================= + os_icon # os identifier + dir # current directory + vcs # git status + # =========================[ Line #2 ]========================= + newline # \n + prompt_char # prompt symbol + ) + + # The list of segments shown on the right. Fill it with less important segments. + # Right prompt on the last prompt line (where you are typing your commands) gets + # automatically hidden when the input line reaches it. Right prompt above the + # last prompt line gets hidden if it would overlap with left prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=( + # =========================[ Line #1 ]========================= + status # exit code of the last command + command_execution_time # duration of the last command + background_jobs # presence of background jobs + direnv # direnv status (https://direnv.net/) + asdf # asdf version manager (https://github.com/asdf-vm/asdf) + virtualenv # python virtual environment (https://docs.python.org/3/library/venv.html) + anaconda # conda environment (https://conda.io/) + pyenv # python environment (https://github.com/pyenv/pyenv) + goenv # go environment (https://github.com/syndbg/goenv) + nodenv # node.js version from nodenv (https://github.com/nodenv/nodenv) + nvm # node.js version from nvm (https://github.com/nvm-sh/nvm) + nodeenv # node.js environment (https://github.com/ekalinin/nodeenv) + # node_version # node.js version + # go_version # go version (https://golang.org) + # rust_version # rustc version (https://www.rust-lang.org) + # dotnet_version # .NET version (https://dotnet.microsoft.com) + # php_version # php version (https://www.php.net/) + # laravel_version # laravel php framework version (https://laravel.com/) + # java_version # java version (https://www.java.com/) + # package # name@version from package.json (https://docs.npmjs.com/files/package.json) + rbenv # ruby version from rbenv (https://github.com/rbenv/rbenv) + rvm # ruby version from rvm (https://rvm.io) + fvm # flutter version management (https://github.com/leoafarias/fvm) + luaenv # lua version from luaenv (https://github.com/cehoffman/luaenv) + jenv # java version from jenv (https://github.com/jenv/jenv) + plenv # perl version from plenv (https://github.com/tokuhirom/plenv) + phpenv # php version from phpenv (https://github.com/phpenv/phpenv) + haskell_stack # haskell version from stack (https://haskellstack.org/) + kubecontext # current kubernetes context (https://kubernetes.io/) + terraform # terraform workspace (https://www.terraform.io) + aws # aws profile (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) + aws_eb_env # aws elastic beanstalk environment (https://aws.amazon.com/elasticbeanstalk/) + azure # azure account name (https://docs.microsoft.com/en-us/cli/azure) + gcloud # google cloud cli account and project (https://cloud.google.com/) + google_app_cred # google application credentials (https://cloud.google.com/docs/authentication/production) + context # user@hostname + nordvpn # nordvpn connection status, linux only (https://nordvpn.com/) + ranger # ranger shell (https://github.com/ranger/ranger) + nnn # nnn shell (https://github.com/jarun/nnn) + vim_shell # vim shell indicator (:sh) + midnight_commander # midnight commander shell (https://midnight-commander.org/) + nix_shell # nix shell (https://nixos.org/nixos/nix-pills/developing-with-nix-shell.html) + # vpn_ip # virtual private network indicator + # load # CPU load + # disk_usage # disk usage + # ram # free RAM + # swap # used swap + todo # todo items (https://github.com/todotxt/todo.txt-cli) + timewarrior # timewarrior tracking status (https://timewarrior.net/) + taskwarrior # taskwarrior task count (https://taskwarrior.org/) + time # current time + # =========================[ Line #2 ]========================= + newline + # ip # ip address and bandwidth usage for a specified network interface + # public_ip # public IP address + # proxy # system-wide http/https/ftp proxy + # battery # internal battery + # wifi # wifi speed + # example # example user-defined segment (see prompt_example function below) + ) + + # Defines character set used by powerlevel10k. It's best to let `p10k configure` set it for you. + typeset -g POWERLEVEL9K_MODE=nerdfont-complete + # When set to `moderate`, some icons will have an extra space after them. This is meant to avoid + # icon overlap when using non-monospace fonts. When set to `none`, spaces are not added. + typeset -g POWERLEVEL9K_ICON_PADDING=none + + # Basic style options that define the overall look of your prompt. You probably don't want to + # change them. + typeset -g POWERLEVEL9K_BACKGROUND= # transparent background + typeset -g POWERLEVEL9K_{LEFT,RIGHT}_{LEFT,RIGHT}_WHITESPACE= # no surrounding whitespace + typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SUBSEGMENT_SEPARATOR=' ' # separate segments with a space + typeset -g POWERLEVEL9K_{LEFT,RIGHT}_SEGMENT_SEPARATOR= # no end-of-line symbol + + # When set to true, icons appear before content on both sides of the prompt. When set + # to false, icons go after content. If empty or not set, icons go before content in the left + # prompt and after content in the right prompt. + # + # You can also override it for a specific segment: + # + # POWERLEVEL9K_STATUS_ICON_BEFORE_CONTENT=false + # + # Or for a specific segment in specific state: + # + # POWERLEVEL9K_DIR_NOT_WRITABLE_ICON_BEFORE_CONTENT=false + typeset -g POWERLEVEL9K_ICON_BEFORE_CONTENT=true + + # Add an empty line before each prompt. + typeset -g POWERLEVEL9K_PROMPT_ADD_NEWLINE=true + + # Connect left prompt lines with these symbols. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_PREFIX= + typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_PREFIX= + typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_PREFIX= + # Connect right prompt lines with these symbols. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_SUFFIX= + typeset -g POWERLEVEL9K_MULTILINE_NEWLINE_PROMPT_SUFFIX= + typeset -g POWERLEVEL9K_MULTILINE_LAST_PROMPT_SUFFIX= + + # The left end of left prompt. + typeset -g POWERLEVEL9K_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL= + # The right end of right prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_LAST_SEGMENT_END_SYMBOL= + + # Ruler, a.k.a. the horizontal line before each prompt. If you set it to true, you'll + # probably want to set POWERLEVEL9K_PROMPT_ADD_NEWLINE=false above and + # POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR=' ' below. + typeset -g POWERLEVEL9K_SHOW_RULER=false + typeset -g POWERLEVEL9K_RULER_CHAR='─' # reasonable alternative: '·' + typeset -g POWERLEVEL9K_RULER_FOREGROUND=240 + + # Filler between left and right prompt on the first prompt line. You can set it to '·' or '─' + # to make it easier to see the alignment between left and right prompt and to separate prompt + # from command output. It serves the same purpose as ruler (see above) without increasing + # the number of prompt lines. You'll probably want to set POWERLEVEL9K_SHOW_RULER=false + # if using this. You might also like POWERLEVEL9K_PROMPT_ADD_NEWLINE=false for more compact + # prompt. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR='─' + if [[ $POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR != ' ' ]]; then + # The color of the filler. + typeset -g POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_FOREGROUND=240 + # Add a space between the end of left prompt and the filler. + typeset -g POWERLEVEL9K_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL=' ' + # Add a space between the filler and the start of right prompt. + typeset -g POWERLEVEL9K_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL=' ' + # Start filler from the edge of the screen if there are no left segments on the first line. + typeset -g POWERLEVEL9K_EMPTY_LINE_LEFT_PROMPT_FIRST_SEGMENT_END_SYMBOL='%{%}' + # End filler on the edge of the screen if there are no right segments on the first line. + typeset -g POWERLEVEL9K_EMPTY_LINE_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL='%{%}' + fi + + #################################[ os_icon: os identifier ]################################## + # OS identifier color. + typeset -g POWERLEVEL9K_OS_ICON_FOREGROUND= + # Make the icon bold. + typeset -g POWERLEVEL9K_OS_ICON_CONTENT_EXPANSION='${P9K_CONTENT}' + + ################################[ prompt_char: prompt symbol ]################################ + # Green prompt symbol if the last command succeeded. + typeset -g POWERLEVEL9K_PROMPT_CHAR_OK_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=76 + # Red prompt symbol if the last command failed. + typeset -g POWERLEVEL9K_PROMPT_CHAR_ERROR_{VIINS,VICMD,VIVIS,VIOWR}_FOREGROUND=196 + # Default prompt symbol. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIINS_CONTENT_EXPANSION='❯' + # Prompt symbol in command vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VICMD_CONTENT_EXPANSION='❮' + # Prompt symbol in visual vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIVIS_CONTENT_EXPANSION='V' + # Prompt symbol in overwrite vi mode. + typeset -g POWERLEVEL9K_PROMPT_CHAR_{OK,ERROR}_VIOWR_CONTENT_EXPANSION='▶' + typeset -g POWERLEVEL9K_PROMPT_CHAR_OVERWRITE_STATE=true + # No line terminator if prompt_char is the last segment. + typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL='' + # No line introducer if prompt_char is the first segment. + typeset -g POWERLEVEL9K_PROMPT_CHAR_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL= + + ##################################[ dir: current directory ]################################## + # Default current directory color. + typeset -g POWERLEVEL9K_DIR_FOREGROUND=31 + # If directory is too long, shorten some of its segments to the shortest possible unique + # prefix. The shortened directory can be tab-completed to the original. + typeset -g POWERLEVEL9K_SHORTEN_STRATEGY=truncate_to_unique + # Replace removed segment suffixes with this symbol. + typeset -g POWERLEVEL9K_SHORTEN_DELIMITER= + # Color of the shortened directory segments. + typeset -g POWERLEVEL9K_DIR_SHORTENED_FOREGROUND=103 + # Color of the anchor directory segments. Anchor segments are never shortened. The first + # segment is always an anchor. + typeset -g POWERLEVEL9K_DIR_ANCHOR_FOREGROUND=39 + # Display anchor directory segments in bold. + typeset -g POWERLEVEL9K_DIR_ANCHOR_BOLD=true + # Don't shorten directories that contain any of these files. They are anchors. + local anchor_files=( + .bzr + .citc + .git + .hg + .node-version + .python-version + .go-version + .ruby-version + .lua-version + .java-version + .perl-version + .php-version + .tool-version + .shorten_folder_marker + .svn + .terraform + CVS + Cargo.toml + composer.json + go.mod + package.json + stack.yaml + ) + typeset -g POWERLEVEL9K_SHORTEN_FOLDER_MARKER="(${(j:|:)anchor_files})" + # If set to "first" ("last"), remove everything before the first (last) subdirectory that contains + # files matching $POWERLEVEL9K_SHORTEN_FOLDER_MARKER. For example, when the current directory is + # /foo/bar/git_repo/nested_git_repo/baz, prompt will display git_repo/nested_git_repo/baz (first) + # or nested_git_repo/baz (last). This assumes that git_repo and nested_git_repo contain markers + # and other directories don't. + typeset -g POWERLEVEL9K_DIR_TRUNCATE_BEFORE_MARKER=false + # Don't shorten this many last directory segments. They are anchors. + typeset -g POWERLEVEL9K_SHORTEN_DIR_LENGTH=1 + # Shorten directory if it's longer than this even if there is space for it. The value can + # be either absolute (e.g., '80') or a percentage of terminal width (e.g, '50%'). If empty, + # directory will be shortened only when prompt doesn't fit or when other parameters demand it + # (see POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS and POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT below). + # If set to `0`, directory will always be shortened to its minimum length. + typeset -g POWERLEVEL9K_DIR_MAX_LENGTH=80 + # When `dir` segment is on the last prompt line, try to shorten it enough to leave at least this + # many columns for typing commands. + typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS=40 + # When `dir` segment is on the last prompt line, try to shorten it enough to leave at least + # COLUMNS * POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT * 0.01 columns for typing commands. + typeset -g POWERLEVEL9K_DIR_MIN_COMMAND_COLUMNS_PCT=50 + # If set to true, embed a hyperlink into the directory. Useful for quickly + # opening a directory in the file manager simply by clicking the link. + # Can also be handy when the directory is shortened, as it allows you to see + # the full directory that was used in previous commands. + typeset -g POWERLEVEL9K_DIR_HYPERLINK=false + + # Enable special styling for non-writable directories. See POWERLEVEL9K_LOCK_ICON and + # POWERLEVEL9K_DIR_CLASSES below. + typeset -g POWERLEVEL9K_DIR_SHOW_WRITABLE=v2 + + # The default icon shown next to non-writable directories when POWERLEVEL9K_DIR_SHOW_WRITABLE is + # set to v2. + # typeset -g POWERLEVEL9K_LOCK_ICON='⭐' + + # POWERLEVEL9K_DIR_CLASSES allows you to specify custom icons and colors for different + # directories. It must be an array with 3 * N elements. Each triplet consists of: + # + # 1. A pattern against which the current directory ($PWD) is matched. Matching is done with + # extended_glob option enabled. + # 2. Directory class for the purpose of styling. + # 3. An empty string. + # + # Triplets are tried in order. The first triplet whose pattern matches $PWD wins. + # + # If POWERLEVEL9K_DIR_SHOW_WRITABLE is set to v2 and the current directory is not writable, + # its class gets suffix _NOT_WRITABLE. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_DIR_CLASSES=( + # '~/work(|/*)' WORK '' + # '~(|/*)' HOME '' + # '*' DEFAULT '') + # + # Whenever the current directory is ~/work or a subdirectory of ~/work, it gets styled with class + # WORK or WORK_NOT_WRITABLE. + # + # Simply assigning classes to directories don't have any visible effects. It merely gives you an + # option to define custom colors and icons for different directory classes. + # + # # Styling for WORK. + # typeset -g POWERLEVEL9K_DIR_WORK_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_DIR_WORK_FOREGROUND=31 + # typeset -g POWERLEVEL9K_DIR_WORK_SHORTENED_FOREGROUND=103 + # typeset -g POWERLEVEL9K_DIR_WORK_ANCHOR_FOREGROUND=39 + # + # # Styling for WORK_NOT_WRITABLE. + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_FOREGROUND=31 + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_SHORTENED_FOREGROUND=103 + # typeset -g POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_ANCHOR_FOREGROUND=39 + # + # If a styling parameter isn't explicitly defined for some class, it falls back to the classless + # parameter. For example, if POWERLEVEL9K_DIR_WORK_NOT_WRITABLE_FOREGROUND is not set, it falls + # back to POWERLEVEL9K_DIR_FOREGROUND. + # + # typeset -g POWERLEVEL9K_DIR_CLASSES=() + + # Custom prefix. + # typeset -g POWERLEVEL9K_DIR_PREFIX='%fin ' + + #####################################[ vcs: git status ]###################################### + # Branch icon. Set this parameter to '\uF126 ' for the popular Powerline branch icon. + typeset -g POWERLEVEL9K_VCS_BRANCH_ICON='\uF126 ' + + # Untracked files icon. It's really a question mark, your font isn't broken. + # Change the value of this parameter to show a different icon. + typeset -g POWERLEVEL9K_VCS_UNTRACKED_ICON='?' + + # Formatter for Git status. + # + # Example output: master ⇣42⇡42 *42 merge ~42 +42 !42 ?42. + # + # You can edit the function to customize how Git status looks. + # + # VCS_STATUS_* parameters are set by gitstatus plugin. See reference: + # https://github.com/romkatv/gitstatus/blob/master/gitstatus.plugin.zsh. + function my_git_formatter() { + emulate -L zsh + + if [[ -n $P9K_CONTENT ]]; then + # If P9K_CONTENT is not empty, use it. It's either "loading" or from vcs_info (not from + # gitstatus plugin). VCS_STATUS_* parameters are not available in this case. + typeset -g my_git_format=$P9K_CONTENT + return + fi + + if (( $1 )); then + # Styling for up-to-date Git status. + local meta='%f' # default foreground + local clean='%76F' # green foreground + local modified='%178F' # yellow foreground + local untracked='%39F' # blue foreground + local conflicted='%196F' # red foreground + else + # Styling for incomplete and stale Git status. + local meta='%244F' # grey foreground + local clean='%244F' # grey foreground + local modified='%244F' # grey foreground + local untracked='%244F' # grey foreground + local conflicted='%244F' # grey foreground + fi + + local res + local where # branch or tag + if [[ -n $VCS_STATUS_LOCAL_BRANCH ]]; then + res+="${clean}${(g::)POWERLEVEL9K_VCS_BRANCH_ICON}" + where=${(V)VCS_STATUS_LOCAL_BRANCH} + elif [[ -n $VCS_STATUS_TAG ]]; then + res+="${meta}#" + where=${(V)VCS_STATUS_TAG} + fi + + # If local branch name or tag is at most 32 characters long, show it in full. + # Otherwise show the first 12 … the last 12. + # Tip: To always show local branch name in full without truncation, delete the next line. + (( $#where > 32 )) && where[13,-13]="…" + res+="${clean}${where//\%/%%}" # escape % + + # Display the current Git commit if there is no branch or tag. + # Tip: To always display the current Git commit, remove `[[ -z $where ]] &&` from the next line. + [[ -z $where ]] && res+="${meta}@${clean}${VCS_STATUS_COMMIT[1,8]}" + + # Show tracking branch name if it differs from local branch. + if [[ -n ${VCS_STATUS_REMOTE_BRANCH:#$VCS_STATUS_LOCAL_BRANCH} ]]; then + res+="${meta}:${clean}${(V)VCS_STATUS_REMOTE_BRANCH//\%/%%}" # escape % + fi + + # ⇣42 if behind the remote. + (( VCS_STATUS_COMMITS_BEHIND )) && res+=" ${clean}⇣${VCS_STATUS_COMMITS_BEHIND}" + # ⇡42 if ahead of the remote; no leading space if also behind the remote: ⇣42⇡42. + (( VCS_STATUS_COMMITS_AHEAD && !VCS_STATUS_COMMITS_BEHIND )) && res+=" " + (( VCS_STATUS_COMMITS_AHEAD )) && res+="${clean}⇡${VCS_STATUS_COMMITS_AHEAD}" + # ⇠42 if behind the push remote. + (( VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" ${clean}⇠${VCS_STATUS_PUSH_COMMITS_BEHIND}" + (( VCS_STATUS_PUSH_COMMITS_AHEAD && !VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" " + # ⇢42 if ahead of the push remote; no leading space if also behind: ⇠42⇢42. + (( VCS_STATUS_PUSH_COMMITS_AHEAD )) && res+="${clean}⇢${VCS_STATUS_PUSH_COMMITS_AHEAD}" + # *42 if have stashes. + (( VCS_STATUS_STASHES )) && res+=" ${clean}*${VCS_STATUS_STASHES}" + # 'merge' if the repo is in an unusual state. + [[ -n $VCS_STATUS_ACTION ]] && res+=" ${conflicted}${VCS_STATUS_ACTION}" + # ~42 if have merge conflicts. + (( VCS_STATUS_NUM_CONFLICTED )) && res+=" ${conflicted}~${VCS_STATUS_NUM_CONFLICTED}" + # +42 if have staged changes. + (( VCS_STATUS_NUM_STAGED )) && res+=" ${modified}+${VCS_STATUS_NUM_STAGED}" + # !42 if have unstaged changes. + (( VCS_STATUS_NUM_UNSTAGED )) && res+=" ${modified}!${VCS_STATUS_NUM_UNSTAGED}" + # ?42 if have untracked files. It's really a question mark, your font isn't broken. + # See POWERLEVEL9K_VCS_UNTRACKED_ICON above if you want to use a different icon. + # Remove the next line if you don't want to see untracked files at all. + (( VCS_STATUS_NUM_UNTRACKED )) && res+=" ${untracked}${(g::)POWERLEVEL9K_VCS_UNTRACKED_ICON}${VCS_STATUS_NUM_UNTRACKED}" + # "─" if the number of unstaged files is unknown. This can happen due to + # POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY (see below) being set to a non-negative number lower + # than the number of files in the Git index, or due to bash.showDirtyState being set to false + # in the repository config. The number of staged and untracked files may also be unknown + # in this case. + (( VCS_STATUS_HAS_UNSTAGED == -1 )) && res+=" ${modified}─" + + typeset -g my_git_format=$res + } + functions -M my_git_formatter 2>/dev/null + + # Don't count the number of unstaged, untracked and conflicted files in Git repositories with + # more than this many files in the index. Negative value means infinity. + # + # If you are working in Git repositories with tens of millions of files and seeing performance + # sagging, try setting POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY to a number lower than the output + # of `git ls-files | wc -l`. Alternatively, add `bash.showDirtyState = false` to the repository's + # config: `git config bash.showDirtyState false`. + typeset -g POWERLEVEL9K_VCS_MAX_INDEX_SIZE_DIRTY=-1 + + # Don't show Git status in prompt for repositories whose workdir matches this pattern. + # For example, if set to '~', the Git repository at $HOME/.git will be ignored. + # Multiple patterns can be combined with '|': '~(|/foo)|/bar/baz/*'. + typeset -g POWERLEVEL9K_VCS_DISABLED_WORKDIR_PATTERN='~' + + # Disable the default Git status formatting. + typeset -g POWERLEVEL9K_VCS_DISABLE_GITSTATUS_FORMATTING=true + # Install our own Git status formatter. + typeset -g POWERLEVEL9K_VCS_CONTENT_EXPANSION='${$((my_git_formatter(1)))+${my_git_format}}' + typeset -g POWERLEVEL9K_VCS_LOADING_CONTENT_EXPANSION='${$((my_git_formatter(0)))+${my_git_format}}' + # Enable counters for staged, unstaged, etc. + typeset -g POWERLEVEL9K_VCS_{STAGED,UNSTAGED,UNTRACKED,CONFLICTED,COMMITS_AHEAD,COMMITS_BEHIND}_MAX_NUM=-1 + + # Icon color. + typeset -g POWERLEVEL9K_VCS_VISUAL_IDENTIFIER_COLOR=76 + typeset -g POWERLEVEL9K_VCS_LOADING_VISUAL_IDENTIFIER_COLOR=244 + # Custom icon. + # typeset -g POWERLEVEL9K_VCS_VISUAL_IDENTIFIER_EXPANSION='⭐' + # Custom prefix. + # typeset -g POWERLEVEL9K_VCS_PREFIX='%fon ' + + # Show status of repositories of these types. You can add svn and/or hg if you are + # using them. If you do, your prompt may become slow even when your current directory + # isn't in an svn or hg reposotiry. + typeset -g POWERLEVEL9K_VCS_BACKENDS=(git) + + # These settings are used for repositories other than Git or when gitstatusd fails and + # Powerlevel10k has to fall back to using vcs_info. + typeset -g POWERLEVEL9K_VCS_CLEAN_FOREGROUND=76 + typeset -g POWERLEVEL9K_VCS_UNTRACKED_FOREGROUND=76 + typeset -g POWERLEVEL9K_VCS_MODIFIED_FOREGROUND=178 + + ##########################[ status: exit code of the last command ]########################### + # Enable OK_PIPE, ERROR_PIPE and ERROR_SIGNAL status states to allow us to enable, disable and + # style them independently from the regular OK and ERROR state. + typeset -g POWERLEVEL9K_STATUS_EXTENDED_STATES=true + + # Status on success. No content, just an icon. No need to show it if prompt_char is enabled as + # it will signify success by turning green. + typeset -g POWERLEVEL9K_STATUS_OK=false + typeset -g POWERLEVEL9K_STATUS_OK_FOREGROUND=70 + typeset -g POWERLEVEL9K_STATUS_OK_VISUAL_IDENTIFIER_EXPANSION='✔' + + # Status when some part of a pipe command fails but the overall exit status is zero. It may look + # like this: 1|0. + typeset -g POWERLEVEL9K_STATUS_OK_PIPE=true + typeset -g POWERLEVEL9K_STATUS_OK_PIPE_FOREGROUND=70 + typeset -g POWERLEVEL9K_STATUS_OK_PIPE_VISUAL_IDENTIFIER_EXPANSION='✔' + + # Status when it's just an error code (e.g., '1'). No need to show it if prompt_char is enabled as + # it will signify error by turning red. + typeset -g POWERLEVEL9K_STATUS_ERROR=false + typeset -g POWERLEVEL9K_STATUS_ERROR_FOREGROUND=160 + typeset -g POWERLEVEL9K_STATUS_ERROR_VISUAL_IDENTIFIER_EXPANSION='✘' + + # Status when the last command was terminated by a signal. + typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL=true + typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_FOREGROUND=160 + # Use terse signal names: "INT" instead of "SIGINT(2)". + typeset -g POWERLEVEL9K_STATUS_VERBOSE_SIGNAME=false + typeset -g POWERLEVEL9K_STATUS_ERROR_SIGNAL_VISUAL_IDENTIFIER_EXPANSION='✘' + + # Status when some part of a pipe command fails and the overall exit status is also non-zero. + # It may look like this: 1|0. + typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE=true + typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_FOREGROUND=160 + typeset -g POWERLEVEL9K_STATUS_ERROR_PIPE_VISUAL_IDENTIFIER_EXPANSION='✘' + + ###################[ command_execution_time: duration of the last command ]################### + # Show duration of the last command if takes longer than this many seconds. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_THRESHOLD=3 + # Show this many fractional digits. Zero means round to seconds. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_PRECISION=0 + # Execution time color. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FOREGROUND=101 + # Duration format: 1d 2h 3m 4s. + typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_FORMAT='d h m s' + # Custom icon. + # typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_VISUAL_IDENTIFIER_EXPANSION='⭐' + # Custom prefix. + # typeset -g POWERLEVEL9K_COMMAND_EXECUTION_TIME_PREFIX='%ftook ' + + #######################[ background_jobs: presence of background jobs ]####################### + # Don't show the number of background jobs. + typeset -g POWERLEVEL9K_BACKGROUND_JOBS_VERBOSE=false + # Background jobs color. + typeset -g POWERLEVEL9K_BACKGROUND_JOBS_FOREGROUND=70 + # Custom icon. + # typeset -g POWERLEVEL9K_BACKGROUND_JOBS_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ direnv: direnv status (https://direnv.net/) ]######################## + # Direnv color. + typeset -g POWERLEVEL9K_DIRENV_FOREGROUND=178 + # Custom icon. + # typeset -g POWERLEVEL9K_DIRENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ asdf: asdf version manager (https://github.com/asdf-vm/asdf) ]############### + # Default asdf color. Only used to display tools for which there is no color override (see below). + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_FOREGROUND. + typeset -g POWERLEVEL9K_ASDF_FOREGROUND=66 + + # There are four parameters that can be used to hide asdf tools. Each parameter describes + # conditions under which a tool gets hidden. Parameters can hide tools but not unhide them. If at + # least one parameter decides to hide a tool, that tool gets hidden. If no parameter decides to + # hide a tool, it gets shown. + # + # Special note on the difference between POWERLEVEL9K_ASDF_SOURCES and + # POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW. Consider the effect of the following commands: + # + # asdf local python 3.8.1 + # asdf global python 3.8.1 + # + # After running both commands the current python version is 3.8.1 and its source is "local" as + # it takes precedence over "global". If POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW is set to false, + # it'll hide python version in this case because 3.8.1 is the same as the global version. + # POWERLEVEL9K_ASDF_SOURCES will hide python version only if the value of this parameter doesn't + # contain "local". + + # Hide tool versions that don't come from one of these sources. + # + # Available sources: + # + # - shell `asdf current` says "set by ASDF_${TOOL}_VERSION environment variable" + # - local `asdf current` says "set by /some/not/home/directory/file" + # - global `asdf current` says "set by /home/username/file" + # + # Note: If this parameter is set to (shell local global), it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SOURCES. + typeset -g POWERLEVEL9K_ASDF_SOURCES=(shell local global) + + # If set to false, hide tool versions that are the same as global. + # + # Note: The name of this parameter doesn't reflect its meaning at all. + # Note: If this parameter is set to true, it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_PROMPT_ALWAYS_SHOW. + typeset -g POWERLEVEL9K_ASDF_PROMPT_ALWAYS_SHOW=false + + # If set to false, hide tool versions that are equal to "system". + # + # Note: If this parameter is set to true, it won't hide tools. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SHOW_SYSTEM. + typeset -g POWERLEVEL9K_ASDF_SHOW_SYSTEM=true + + # If set to non-empty value, hide tools unless there is a file matching the specified file pattern + # in the current directory, or its parent diretory, or its grandparent directory, and so on. + # + # Note: If this parameter is set to empty value, it won't hide tools. + # Note: SHOW_ON_UPGLOB isn't specific to asdf. It works with all prompt segments. + # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_SHOW_ON_UPGLOB. + # + # Example: Hide nodejs version when there is no package.json and no *.js files in the current + # directory, in `..`, in `../..` and so on. + # + # typeset -g POWERLEVEL9K_ASDF_NODEJS_SHOW_ON_UPGLOB='*.js|package.json' + typeset -g POWERLEVEL9K_ASDF_SHOW_ON_UPGLOB= + + # Ruby version from asdf. + typeset -g POWERLEVEL9K_ASDF_RUBY_FOREGROUND=168 + # typeset -g POWERLEVEL9K_ASDF_RUBY_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_RUBY_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Python version from asdf. + typeset -g POWERLEVEL9K_ASDF_PYTHON_FOREGROUND=37 + # typeset -g POWERLEVEL9K_ASDF_PYTHON_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PYTHON_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Go version from asdf. + typeset -g POWERLEVEL9K_ASDF_GOLANG_FOREGROUND=37 + # typeset -g POWERLEVEL9K_ASDF_GOLANG_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_GOLANG_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Node.js version from asdf. + typeset -g POWERLEVEL9K_ASDF_NODEJS_FOREGROUND=70 + # typeset -g POWERLEVEL9K_ASDF_NODEJS_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_NODEJS_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Rust version from asdf. + typeset -g POWERLEVEL9K_ASDF_RUST_FOREGROUND=37 + # typeset -g POWERLEVEL9K_ASDF_RUST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_RUST_SHOW_ON_UPGLOB='*.foo|*.bar' + + # .NET Core version from asdf. + typeset -g POWERLEVEL9K_ASDF_DOTNET_CORE_FOREGROUND=134 + # typeset -g POWERLEVEL9K_ASDF_DOTNET_CORE_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_DOTNET_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Flutter version from asdf. + typeset -g POWERLEVEL9K_ASDF_FLUTTER_FOREGROUND=38 + # typeset -g POWERLEVEL9K_ASDF_FLUTTER_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_FLUTTER_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Lua version from asdf. + typeset -g POWERLEVEL9K_ASDF_LUA_FOREGROUND=32 + # typeset -g POWERLEVEL9K_ASDF_LUA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_LUA_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Java version from asdf. + typeset -g POWERLEVEL9K_ASDF_JAVA_FOREGROUND=32 + # typeset -g POWERLEVEL9K_ASDF_JAVA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_JAVA_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Perl version from asdf. + typeset -g POWERLEVEL9K_ASDF_PERL_FOREGROUND=67 + # typeset -g POWERLEVEL9K_ASDF_PERL_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PERL_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Erlang version from asdf. + typeset -g POWERLEVEL9K_ASDF_ERLANG_FOREGROUND=125 + # typeset -g POWERLEVEL9K_ASDF_ERLANG_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_ERLANG_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Elixir version from asdf. + typeset -g POWERLEVEL9K_ASDF_ELIXIR_FOREGROUND=129 + # typeset -g POWERLEVEL9K_ASDF_ELIXIR_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_ELIXIR_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Postgres version from asdf. + typeset -g POWERLEVEL9K_ASDF_POSTGRES_FOREGROUND=31 + # typeset -g POWERLEVEL9K_ASDF_POSTGRES_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_POSTGRES_SHOW_ON_UPGLOB='*.foo|*.bar' + + # PHP version from asdf. + typeset -g POWERLEVEL9K_ASDF_PHP_FOREGROUND=99 + # typeset -g POWERLEVEL9K_ASDF_PHP_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_PHP_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Haskell version from asdf. + typeset -g POWERLEVEL9K_ASDF_HASKELL_FOREGROUND=172 + # typeset -g POWERLEVEL9K_ASDF_HASKELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_HASKELL_SHOW_ON_UPGLOB='*.foo|*.bar' + + # Julia version from asdf. + typeset -g POWERLEVEL9K_ASDF_JULIA_FOREGROUND=70 + # typeset -g POWERLEVEL9K_ASDF_JULIA_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_ASDF_JULIA_SHOW_ON_UPGLOB='*.foo|*.bar' + + ##########[ nordvpn: nordvpn connection status, linux only (https://nordvpn.com/) ]########### + # NordVPN connection indicator color. + typeset -g POWERLEVEL9K_NORDVPN_FOREGROUND=39 + # Hide NordVPN connection indicator when not connected. + typeset -g POWERLEVEL9K_NORDVPN_{DISCONNECTED,CONNECTING,DISCONNECTING}_CONTENT_EXPANSION= + typeset -g POWERLEVEL9K_NORDVPN_{DISCONNECTED,CONNECTING,DISCONNECTING}_VISUAL_IDENTIFIER_EXPANSION= + # Custom icon. + # typeset -g POWERLEVEL9K_NORDVPN_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #################[ ranger: ranger shell (https://github.com/ranger/ranger) ]################## + # Ranger shell color. + typeset -g POWERLEVEL9K_RANGER_FOREGROUND=178 + # Custom icon. + # typeset -g POWERLEVEL9K_RANGER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################[ nnn: nnn shell (https://github.com/jarun/nnn) ]####################### + # Nnn shell color. + typeset -g POWERLEVEL9K_NNN_FOREGROUND=72 + # Custom icon. + # typeset -g POWERLEVEL9K_NNN_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########################[ vim_shell: vim shell indicator (:sh) ]########################### + # Vim shell indicator color. + typeset -g POWERLEVEL9K_VIM_SHELL_FOREGROUND=34 + # Custom icon. + # typeset -g POWERLEVEL9K_VIM_SHELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######[ midnight_commander: midnight commander shell (https://midnight-commander.org/) ]###### + # Midnight Commander shell color. + typeset -g POWERLEVEL9K_MIDNIGHT_COMMANDER_FOREGROUND=178 + # Custom icon. + # typeset -g POWERLEVEL9K_MIDNIGHT_COMMANDER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ nix_shell: nix shell (https://nixos.org/nixos/nix-pills/developing-with-nix-shell.html) ]## + # Nix shell color. + typeset -g POWERLEVEL9K_NIX_SHELL_FOREGROUND=74 + + # Tip: If you want to see just the icon without "pure" and "impure", uncomment the next line. + # typeset -g POWERLEVEL9K_NIX_SHELL_CONTENT_EXPANSION= + + # Custom icon. + # typeset -g POWERLEVEL9K_NIX_SHELL_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##################################[ disk_usage: disk usage ]################################## + # Colors for different levels of disk usage. + typeset -g POWERLEVEL9K_DISK_USAGE_NORMAL_FOREGROUND=35 + typeset -g POWERLEVEL9K_DISK_USAGE_WARNING_FOREGROUND=220 + typeset -g POWERLEVEL9K_DISK_USAGE_CRITICAL_FOREGROUND=160 + # Thresholds for different levels of disk usage (percentage points). + typeset -g POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL=90 + typeset -g POWERLEVEL9K_DISK_USAGE_CRITICAL_LEVEL=95 + # If set to true, hide disk usage when below $POWERLEVEL9K_DISK_USAGE_WARNING_LEVEL percent. + typeset -g POWERLEVEL9K_DISK_USAGE_ONLY_WARNING=false + # Custom icon. + # typeset -g POWERLEVEL9K_DISK_USAGE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################################[ ram: free RAM ]####################################### + # RAM color. + typeset -g POWERLEVEL9K_RAM_FOREGROUND=66 + # Custom icon. + # typeset -g POWERLEVEL9K_RAM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #####################################[ swap: used swap ]###################################### + # Swap color. + typeset -g POWERLEVEL9K_SWAP_FOREGROUND=96 + # Custom icon. + # typeset -g POWERLEVEL9K_SWAP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ######################################[ load: CPU load ]###################################### + # Show average CPU load over this many last minutes. Valid values are 1, 5 and 15. + typeset -g POWERLEVEL9K_LOAD_WHICH=5 + # Load color when load is under 50%. + typeset -g POWERLEVEL9K_LOAD_NORMAL_FOREGROUND=66 + # Load color when load is between 50% and 70%. + typeset -g POWERLEVEL9K_LOAD_WARNING_FOREGROUND=178 + # Load color when load is over 70%. + typeset -g POWERLEVEL9K_LOAD_CRITICAL_FOREGROUND=166 + # Custom icon. + # typeset -g POWERLEVEL9K_LOAD_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################[ todo: todo items (https://github.com/todotxt/todo.txt-cli) ]################ + # Todo color. + typeset -g POWERLEVEL9K_TODO_FOREGROUND=110 + # Hide todo when the total number of tasks is zero. + typeset -g POWERLEVEL9K_TODO_HIDE_ZERO_TOTAL=true + # Hide todo when the number of tasks after filtering is zero. + typeset -g POWERLEVEL9K_TODO_HIDE_ZERO_FILTERED=false + + # Todo format. The following parameters are available within the expansion. + # + # - P9K_TODO_TOTAL_TASK_COUNT The total number of tasks. + # - P9K_TODO_FILTERED_TASK_COUNT The number of tasks after filtering. + # + # These variables correspond to the last line of the output of `todo.sh -p ls`: + # + # TODO: 24 of 42 tasks shown + # + # Here 24 is P9K_TODO_FILTERED_TASK_COUNT and 42 is P9K_TODO_TOTAL_TASK_COUNT. + # + # typeset -g POWERLEVEL9K_TODO_CONTENT_EXPANSION='$P9K_TODO_FILTERED_TASK_COUNT' + + # Custom icon. + # typeset -g POWERLEVEL9K_TODO_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ timewarrior: timewarrior tracking status (https://timewarrior.net/) ]############ + # Timewarrior color. + typeset -g POWERLEVEL9K_TIMEWARRIOR_FOREGROUND=110 + # If the tracked task is longer than 24 characters, truncate and append "…". + # Tip: To always display tasks without truncation, delete the following parameter. + # Tip: To hide task names and display just the icon when time tracking is enabled, set the + # value of the following parameter to "". + typeset -g POWERLEVEL9K_TIMEWARRIOR_CONTENT_EXPANSION='${P9K_CONTENT:0:24}${${P9K_CONTENT:24}:+…}' + + # Custom icon. + # typeset -g POWERLEVEL9K_TIMEWARRIOR_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############[ taskwarrior: taskwarrior task count (https://taskwarrior.org/) ]############## + # Taskwarrior color. + typeset -g POWERLEVEL9K_TASKWARRIOR_FOREGROUND=74 + + # Taskwarrior segment format. The following parameters are available within the expansion. + # + # - P9K_TASKWARRIOR_PENDING_COUNT The number of pending tasks: `task +PENDING count`. + # - P9K_TASKWARRIOR_OVERDUE_COUNT The number of overdue tasks: `task +OVERDUE count`. + # + # Zero values are represented as empty parameters. + # + # The default format: + # + # '${P9K_TASKWARRIOR_OVERDUE_COUNT:+"!$P9K_TASKWARRIOR_OVERDUE_COUNT/"}$P9K_TASKWARRIOR_PENDING_COUNT' + # + # typeset -g POWERLEVEL9K_TASKWARRIOR_CONTENT_EXPANSION='$P9K_TASKWARRIOR_PENDING_COUNT' + + # Custom icon. + # typeset -g POWERLEVEL9K_TASKWARRIOR_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##################################[ context: user@hostname ]################################## + # Context color when running with privileges. + typeset -g POWERLEVEL9K_CONTEXT_ROOT_FOREGROUND=178 + # Context color in SSH without privileges. + typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_FOREGROUND=180 + # Default context color (no privileges, no SSH). + typeset -g POWERLEVEL9K_CONTEXT_FOREGROUND=180 + + # Context format when running with privileges: bold user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_ROOT_TEMPLATE='%B%n@%m' + # Context format when in SSH without privileges: user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_{REMOTE,REMOTE_SUDO}_TEMPLATE='%n@%m' + # Default context format (no privileges, no SSH): user@hostname. + typeset -g POWERLEVEL9K_CONTEXT_TEMPLATE='%n@%m' + + # Don't show context unless running with privileges or in SSH. + # Tip: Remove the next line to always show context. + typeset -g POWERLEVEL9K_CONTEXT_{DEFAULT,SUDO}_{CONTENT,VISUAL_IDENTIFIER}_EXPANSION= + + # Custom icon. + # typeset -g POWERLEVEL9K_CONTEXT_VISUAL_IDENTIFIER_EXPANSION='⭐' + # Custom prefix. + # typeset -g POWERLEVEL9K_CONTEXT_PREFIX='%fwith ' + + ###[ virtualenv: python virtual environment (https://docs.python.org/3/library/venv.html) ]### + # Python virtual environment color. + typeset -g POWERLEVEL9K_VIRTUALENV_FOREGROUND=37 + # Don't show Python version next to the virtual environment name. + typeset -g POWERLEVEL9K_VIRTUALENV_SHOW_PYTHON_VERSION=false + # Don't show virtualenv if pyenv is already shown. + typeset -g POWERLEVEL9K_VIRTUALENV_SHOW_WITH_PYENV=false + # Separate environment name from Python version only with a space. + typeset -g POWERLEVEL9K_VIRTUALENV_{LEFT,RIGHT}_DELIMITER= + # Custom icon. + # typeset -g POWERLEVEL9K_VIRTUALENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #####################[ anaconda: conda environment (https://conda.io/) ]###################### + # Anaconda environment color. + typeset -g POWERLEVEL9K_ANACONDA_FOREGROUND=37 + + # Anaconda segment format. The following parameters are available within the expansion. + # + # - CONDA_PREFIX Absolute path to the active Anaconda/Miniconda environment. + # - CONDA_DEFAULT_ENV Name of the active Anaconda/Miniconda environment. + # - CONDA_PROMPT_MODIFIER Configurable prompt modifier (see below). + # - P9K_ANACONDA_PYTHON_VERSION Current python version (python --version). + # + # CONDA_PROMPT_MODIFIER can be configured with the following command: + # + # conda config --set env_prompt '({default_env}) ' + # + # The last argument is a Python format string that can use the following variables: + # + # - prefix The same as CONDA_PREFIX. + # - default_env The same as CONDA_DEFAULT_ENV. + # - name The last segment of CONDA_PREFIX. + # - stacked_env Comma-separated list of names in the environment stack. The first element is + # always the same as default_env. + # + # Note: '({default_env}) ' is the default value of env_prompt. + # + # The default value of POWERLEVEL9K_ANACONDA_CONTENT_EXPANSION expands to $CONDA_PROMPT_MODIFIER + # without the surrounding parentheses, or to the last path component of CONDA_PREFIX if the former + # is empty. + typeset -g POWERLEVEL9K_ANACONDA_CONTENT_EXPANSION='${${${${CONDA_PROMPT_MODIFIER#\(}% }%\)}:-${CONDA_PREFIX:t}}' + + # Custom icon. + # typeset -g POWERLEVEL9K_ANACONDA_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################[ pyenv: python environment (https://github.com/pyenv/pyenv) ]################ + # Pyenv color. + typeset -g POWERLEVEL9K_PYENV_FOREGROUND=37 + # Hide python version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PYENV_SOURCES=(shell local global) + # If set to false, hide python version if it's the same as global: + # $(pyenv version-name) == $(pyenv global). + typeset -g POWERLEVEL9K_PYENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide python version if it's equal to "system". + typeset -g POWERLEVEL9K_PYENV_SHOW_SYSTEM=true + + # Pyenv segment format. The following parameters are available within the expansion. + # + # - P9K_CONTENT Current pyenv environment (pyenv version-name). + # - P9K_PYENV_PYTHON_VERSION Current python version (python --version). + # + # The default format has the following logic: + # + # 1. Display "$P9K_CONTENT $P9K_PYENV_PYTHON_VERSION" if $P9K_PYENV_PYTHON_VERSION is not + # empty and unequal to $P9K_CONTENT. + # 2. Otherwise display just "$P9K_CONTENT". + typeset -g POWERLEVEL9K_PYENV_CONTENT_EXPANSION='${P9K_CONTENT}${${P9K_PYENV_PYTHON_VERSION:#$P9K_CONTENT}:+ $P9K_PYENV_PYTHON_VERSION}' + + # Custom icon. + # typeset -g POWERLEVEL9K_PYENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################[ goenv: go environment (https://github.com/syndbg/goenv) ]################ + # Goenv color. + typeset -g POWERLEVEL9K_GOENV_FOREGROUND=37 + # Hide go version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_GOENV_SOURCES=(shell local global) + # If set to false, hide go version if it's the same as global: + # $(goenv version-name) == $(goenv global). + typeset -g POWERLEVEL9K_GOENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide go version if it's equal to "system". + typeset -g POWERLEVEL9K_GOENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_GOENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ nodenv: node.js version from nodenv (https://github.com/nodenv/nodenv) ]########## + # Nodenv color. + typeset -g POWERLEVEL9K_NODENV_FOREGROUND=70 + # Hide node version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_NODENV_SOURCES=(shell local global) + # If set to false, hide node version if it's the same as global: + # $(nodenv version-name) == $(nodenv global). + typeset -g POWERLEVEL9K_NODENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide node version if it's equal to "system". + typeset -g POWERLEVEL9K_NODENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_NODENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############[ nvm: node.js version from nvm (https://github.com/nvm-sh/nvm) ]############### + # Nvm color. + typeset -g POWERLEVEL9K_NVM_FOREGROUND=70 + # Custom icon. + # typeset -g POWERLEVEL9K_NVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ############[ nodeenv: node.js environment (https://github.com/ekalinin/nodeenv) ]############ + # Nodeenv color. + typeset -g POWERLEVEL9K_NODEENV_FOREGROUND=70 + # Don't show Node version next to the environment name. + typeset -g POWERLEVEL9K_NODEENV_SHOW_NODE_VERSION=false + # Separate environment name from Node version only with a space. + typeset -g POWERLEVEL9K_NODEENV_{LEFT,RIGHT}_DELIMITER= + # Custom icon. + # typeset -g POWERLEVEL9K_NODEENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##############################[ node_version: node.js version ]############################### + # Node version color. + typeset -g POWERLEVEL9K_NODE_VERSION_FOREGROUND=70 + # Show node version only when in a directory tree containing package.json. + typeset -g POWERLEVEL9K_NODE_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_NODE_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ go_version: go version (https://golang.org) ]######################## + # Go version color. + typeset -g POWERLEVEL9K_GO_VERSION_FOREGROUND=37 + # Show go version only when in a go project subdirectory. + typeset -g POWERLEVEL9K_GO_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_GO_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #################[ rust_version: rustc version (https://www.rust-lang.org) ]################## + # Rust version color. + typeset -g POWERLEVEL9K_RUST_VERSION_FOREGROUND=37 + # Show rust version only when in a rust project subdirectory. + typeset -g POWERLEVEL9K_RUST_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_RUST_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ dotnet_version: .NET version (https://dotnet.microsoft.com) ]################ + # .NET version color. + typeset -g POWERLEVEL9K_DOTNET_VERSION_FOREGROUND=134 + # Show .NET version only when in a .NET project subdirectory. + typeset -g POWERLEVEL9K_DOTNET_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_DOTNET_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #####################[ php_version: php version (https://www.php.net/) ]###################### + # PHP version color. + typeset -g POWERLEVEL9K_PHP_VERSION_FOREGROUND=99 + # Show PHP version only when in a PHP project subdirectory. + typeset -g POWERLEVEL9K_PHP_VERSION_PROJECT_ONLY=true + # Custom icon. + # typeset -g POWERLEVEL9K_PHP_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ laravel_version: laravel php framework version (https://laravel.com/) ]########### + # Laravel version color. + typeset -g POWERLEVEL9K_LARAVEL_VERSION_FOREGROUND=161 + # Custom icon. + # typeset -g POWERLEVEL9K_LARAVEL_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ####################[ java_version: java version (https://www.java.com/) ]#################### + # Java version color. + typeset -g POWERLEVEL9K_JAVA_VERSION_FOREGROUND=32 + # Show java version only when in a java project subdirectory. + typeset -g POWERLEVEL9K_JAVA_VERSION_PROJECT_ONLY=true + # Show brief version. + typeset -g POWERLEVEL9K_JAVA_VERSION_FULL=false + # Custom icon. + # typeset -g POWERLEVEL9K_JAVA_VERSION_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###[ package: name@version from package.json (https://docs.npmjs.com/files/package.json) ]#### + # Package color. + typeset -g POWERLEVEL9K_PACKAGE_FOREGROUND=117 + # Package format. The following parameters are available within the expansion. + # + # - P9K_PACKAGE_NAME The value of `name` field in package.json. + # - P9K_PACKAGE_VERSION The value of `version` field in package.json. + # + # typeset -g POWERLEVEL9K_PACKAGE_CONTENT_EXPANSION='${P9K_PACKAGE_NAME//\%/%%}@${P9K_PACKAGE_VERSION//\%/%%}' + # Custom icon. + # typeset -g POWERLEVEL9K_PACKAGE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #############[ rbenv: ruby version from rbenv (https://github.com/rbenv/rbenv) ]############## + # Rbenv color. + typeset -g POWERLEVEL9K_RBENV_FOREGROUND=168 + # Hide ruby version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_RBENV_SOURCES=(shell local global) + # If set to false, hide ruby version if it's the same as global: + # $(rbenv version-name) == $(rbenv global). + typeset -g POWERLEVEL9K_RBENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide ruby version if it's equal to "system". + typeset -g POWERLEVEL9K_RBENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_RBENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #######################[ rvm: ruby version from rvm (https://rvm.io) ]######################## + # Rvm color. + typeset -g POWERLEVEL9K_RVM_FOREGROUND=168 + # Don't show @gemset at the end. + typeset -g POWERLEVEL9K_RVM_SHOW_GEMSET=false + # Don't show ruby- at the front. + typeset -g POWERLEVEL9K_RVM_SHOW_PREFIX=false + # Custom icon. + # typeset -g POWERLEVEL9K_RVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ fvm: flutter version management (https://github.com/leoafarias/fvm) ]############ + # Fvm color. + typeset -g POWERLEVEL9K_FVM_FOREGROUND=38 + # Custom icon. + # typeset -g POWERLEVEL9K_FVM_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ luaenv: lua version from luaenv (https://github.com/cehoffman/luaenv) ]########### + # Lua color. + typeset -g POWERLEVEL9K_LUAENV_FOREGROUND=32 + # Hide lua version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_LUAENV_SOURCES=(shell local global) + # If set to false, hide lua version if it's the same as global: + # $(luaenv version-name) == $(luaenv global). + typeset -g POWERLEVEL9K_LUAENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide lua version if it's equal to "system". + typeset -g POWERLEVEL9K_LUAENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_LUAENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###############[ jenv: java version from jenv (https://github.com/jenv/jenv) ]################ + # Java color. + typeset -g POWERLEVEL9K_JENV_FOREGROUND=32 + # Hide java version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_JENV_SOURCES=(shell local global) + # If set to false, hide java version if it's the same as global: + # $(jenv version-name) == $(jenv global). + typeset -g POWERLEVEL9K_JENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide java version if it's equal to "system". + typeset -g POWERLEVEL9K_JENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_JENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ plenv: perl version from plenv (https://github.com/tokuhirom/plenv) ]############ + # Perl color. + typeset -g POWERLEVEL9K_PLENV_FOREGROUND=67 + # Hide perl version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PLENV_SOURCES=(shell local global) + # If set to false, hide perl version if it's the same as global: + # $(plenv version-name) == $(plenv global). + typeset -g POWERLEVEL9K_PLENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide perl version if it's equal to "system". + typeset -g POWERLEVEL9K_PLENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_PLENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ############[ phpenv: php version from phpenv (https://github.com/phpenv/phpenv) ]############ + # PHP color. + typeset -g POWERLEVEL9K_PHPENV_FOREGROUND=99 + # Hide php version if it doesn't come from one of these sources. + typeset -g POWERLEVEL9K_PHPENV_SOURCES=(shell local global) + # If set to false, hide php version if it's the same as global: + # $(phpenv version-name) == $(phpenv global). + typeset -g POWERLEVEL9K_PHPENV_PROMPT_ALWAYS_SHOW=false + # If set to false, hide php version if it's equal to "system". + typeset -g POWERLEVEL9K_PHPENV_SHOW_SYSTEM=true + # Custom icon. + # typeset -g POWERLEVEL9K_PHPENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ haskell_stack: haskell version from stack (https://haskellstack.org/) ]########### + # Haskell color. + typeset -g POWERLEVEL9K_HASKELL_STACK_FOREGROUND=172 + # Hide haskell version if it doesn't come from one of these sources. + # + # shell: version is set by STACK_YAML + # local: version is set by stack.yaml up the directory tree + # global: version is set by the implicit global project (~/.stack/global-project/stack.yaml) + typeset -g POWERLEVEL9K_HASKELL_STACK_SOURCES=(shell local) + # If set to false, hide haskell version if it's the same as in the implicit global project. + typeset -g POWERLEVEL9K_HASKELL_STACK_ALWAYS_SHOW=true + # Custom icon. + # typeset -g POWERLEVEL9K_HASKELL_STACK_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #############[ kubecontext: current kubernetes context (https://kubernetes.io/) ]############# + # Show kubecontext only when the the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show kubecontext. + typeset -g POWERLEVEL9K_KUBECONTEXT_SHOW_ON_COMMAND='kubectl|helm|kubens|kubectx|oc|istioctl|kogito' + + # Kubernetes context classes for the purpose of using different colors, icons and expansions with + # different contexts. + # + # POWERLEVEL9K_KUBECONTEXT_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current kubernetes context gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_KUBECONTEXT_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_KUBECONTEXT_CLASSES defines the context class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_KUBECONTEXT_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' DEFAULT) + # + # If your current kubernetes context is "deathray-testing/default", its class is TEST + # because "deathray-testing/default" doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_FOREGROUND=28 + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_KUBECONTEXT_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_KUBECONTEXT_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_FOREGROUND=134 + # typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use POWERLEVEL9K_KUBECONTEXT_CONTENT_EXPANSION to specify the content displayed by kubecontext + # segment. Parameter expansions are very flexible and fast, too. See reference: + # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion. + # + # Within the expansion the following parameters are always available: + # + # - P9K_CONTENT The content that would've been displayed if there was no content + # expansion defined. + # - P9K_KUBECONTEXT_NAME The current context's name. Corresponds to column NAME in the + # output of `kubectl config get-contexts`. + # - P9K_KUBECONTEXT_CLUSTER The current context's cluster. Corresponds to column CLUSTER in the + # output of `kubectl config get-contexts`. + # - P9K_KUBECONTEXT_NAMESPACE The current context's namespace. Corresponds to column NAMESPACE + # in the output of `kubectl config get-contexts`. If there is no + # namespace, the parameter is set to "default". + # - P9K_KUBECONTEXT_USER The current context's user. Corresponds to column AUTHINFO in the + # output of `kubectl config get-contexts`. + # + # If the context points to Google Kubernetes Engine (GKE) or Elastic Kubernetes Service (EKS), + # the following extra parameters are available: + # + # - P9K_KUBECONTEXT_CLOUD_NAME Either "gke" or "eks". + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT Account/project ID. + # - P9K_KUBECONTEXT_CLOUD_ZONE Availability zone. + # - P9K_KUBECONTEXT_CLOUD_CLUSTER Cluster. + # + # P9K_KUBECONTEXT_CLOUD_* parameters are derived from P9K_KUBECONTEXT_CLUSTER. For example, + # if P9K_KUBECONTEXT_CLUSTER is "gke_my-account_us-east1-a_my-cluster-01": + # + # - P9K_KUBECONTEXT_CLOUD_NAME=gke + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT=my-account + # - P9K_KUBECONTEXT_CLOUD_ZONE=us-east1-a + # - P9K_KUBECONTEXT_CLOUD_CLUSTER=my-cluster-01 + # + # If P9K_KUBECONTEXT_CLUSTER is "arn:aws:eks:us-east-1:123456789012:cluster/my-cluster-01": + # + # - P9K_KUBECONTEXT_CLOUD_NAME=eks + # - P9K_KUBECONTEXT_CLOUD_ACCOUNT=123456789012 + # - P9K_KUBECONTEXT_CLOUD_ZONE=us-east-1 + # - P9K_KUBECONTEXT_CLOUD_CLUSTER=my-cluster-01 + typeset -g POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION= + # Show P9K_KUBECONTEXT_CLOUD_CLUSTER if it's not empty and fall back to P9K_KUBECONTEXT_NAME. + POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION+='${P9K_KUBECONTEXT_CLOUD_CLUSTER:-${P9K_KUBECONTEXT_NAME}}' + # Append the current context's namespace if it's not "default". + POWERLEVEL9K_KUBECONTEXT_DEFAULT_CONTENT_EXPANSION+='${${:-/$P9K_KUBECONTEXT_NAMESPACE}:#/default}' + + # Custom prefix. + # typeset -g POWERLEVEL9K_KUBECONTEXT_PREFIX='%fat ' + + ################[ terraform: terraform workspace (https://www.terraform.io) ]################# + # Don't show terraform workspace if it's literally "default". + typeset -g POWERLEVEL9K_TERRAFORM_SHOW_DEFAULT=false + # POWERLEVEL9K_TERRAFORM_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current terraform workspace gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_TERRAFORM_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_TERRAFORM_CLASSES defines the workspace class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_TERRAFORM_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' OTHER) + # + # If your current terraform workspace is "project_test", its class is TEST because "project_test" + # doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_FOREGROUND=28 + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_TERRAFORM_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_TERRAFORM_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' OTHER) + typeset -g POWERLEVEL9K_TERRAFORM_OTHER_FOREGROUND=38 + # typeset -g POWERLEVEL9K_TERRAFORM_OTHER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ aws: aws profile (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) ]# + # Show aws only when the the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show aws. + typeset -g POWERLEVEL9K_AWS_SHOW_ON_COMMAND='aws|awless|terraform|pulumi' + + # POWERLEVEL9K_AWS_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current AWS profile gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_AWS_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_AWS_CLASSES defines the profile class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_AWS_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' DEFAULT) + # + # If your current AWS profile is "company_test", its class is TEST + # because "company_test" doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_AWS_TEST_FOREGROUND=28 + # typeset -g POWERLEVEL9K_AWS_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_AWS_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_AWS_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + typeset -g POWERLEVEL9K_AWS_DEFAULT_FOREGROUND=208 + # typeset -g POWERLEVEL9K_AWS_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ aws_eb_env: aws elastic beanstalk environment (https://aws.amazon.com/elasticbeanstalk/) ]# + # AWS Elastic Beanstalk environment color. + typeset -g POWERLEVEL9K_AWS_EB_ENV_FOREGROUND=70 + # Custom icon. + # typeset -g POWERLEVEL9K_AWS_EB_ENV_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ azure: azure account name (https://docs.microsoft.com/en-us/cli/azure) ]########## + # Show azure only when the the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show azure. + typeset -g POWERLEVEL9K_AZURE_SHOW_ON_COMMAND='az|terraform|pulumi' + # Azure account name color. + typeset -g POWERLEVEL9K_AZURE_FOREGROUND=32 + # Custom icon. + # typeset -g POWERLEVEL9K_AZURE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ##########[ gcloud: google cloud account and project (https://cloud.google.com/) ]########### + # Show gcloud only when the the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show gcloud. + typeset -g POWERLEVEL9K_GCLOUD_SHOW_ON_COMMAND='gcloud|gcs' + # Google cloud color. + typeset -g POWERLEVEL9K_GCLOUD_FOREGROUND=32 + + # Google cloud format. Change the value of POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION and/or + # POWERLEVEL9K_GCLOUD_COMPLETE_CONTENT_EXPANSION if the default is too verbose or not informative + # enough. You can use the following parameters in the expansions. Each of them corresponds to the + # output of `gcloud` tool. + # + # Parameter | Source + # -------------------------|-------------------------------------------------------------------- + # P9K_GCLOUD_CONFIGURATION | gcloud config configurations list --format='value(name)' + # P9K_GCLOUD_ACCOUNT | gcloud config get-value account + # P9K_GCLOUD_PROJECT_ID | gcloud config get-value project + # P9K_GCLOUD_PROJECT_NAME | gcloud projects describe $P9K_GCLOUD_PROJECT_ID --format='value(name)' + # + # Note: ${VARIABLE//\%/%%} expands to ${VARIABLE} with all occurences of '%' replaced with '%%'. + # + # Obtaining project name requires sending a request to Google servers. This can take a long time + # and even fail. When project name is unknown, P9K_GCLOUD_PROJECT_NAME is not set and gcloud + # prompt segment is in state PARTIAL. When project name gets known, P9K_GCLOUD_PROJECT_NAME gets + # set and gcloud prompt segment transitions to state COMPLETE. + # + # You can customize the format, icon and colors of gcloud segment separately for states PARTIAL + # and COMPLETE. You can also hide gcloud in state PARTIAL by setting + # POWERLEVEL9K_GCLOUD_PARTIAL_VISUAL_IDENTIFIER_EXPANSION and + # POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION to empty. + typeset -g POWERLEVEL9K_GCLOUD_PARTIAL_CONTENT_EXPANSION='${P9K_GCLOUD_PROJECT_ID//\%/%%}' + typeset -g POWERLEVEL9K_GCLOUD_COMPLETE_CONTENT_EXPANSION='${P9K_GCLOUD_PROJECT_NAME//\%/%%}' + + # Send a request to Google (by means of `gcloud projects describe ...`) to obtain project name + # this often. Negative value disables periodic polling. In this mode project name is retrieved + # only when the current configuration, account or project id changes. + typeset -g POWERLEVEL9K_GCLOUD_REFRESH_PROJECT_NAME_SECONDS=60 + + # Custom icon. + # typeset -g POWERLEVEL9K_GCLOUD_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #[ google_app_cred: google application credentials (https://cloud.google.com/docs/authentication/production) ]# + # Show google_app_cred only when the the command you are typing invokes one of these tools. + # Tip: Remove the next line to always show google_app_cred. + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_SHOW_ON_COMMAND='terraform|pulumi' + + # Google application credentials classes for the purpose of using different colors, icons and + # expansions with different credentials. + # + # POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES is an array with even number of elements. The first + # element in each pair defines a pattern against which the current kubernetes context gets + # matched. More specifically, it's P9K_CONTENT prior to the application of context expansion + # (see below) that gets matched. If you unset all POWERLEVEL9K_GOOGLE_APP_CRED_*CONTENT_EXPANSION + # parameters, you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES defines the context class. Patterns are tried in order. + # The first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES=( + # '*:*prod*:*' PROD + # '*:*test*:*' TEST + # '*' DEFAULT) + # + # If your current Google application credentials is "service_account deathray-testing x@y.com", + # its class is TEST because it doesn't match the pattern '* *prod* *' but does match '* *test* *'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_FOREGROUND=28 + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_TEST_CONTENT_EXPANSION='$P9K_GOOGLE_APP_CRED_PROJECT_ID' + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_CLASSES=( + # '*:*prod*:*' PROD # These values are examples that are unlikely + # '*:*test*:*' TEST # to match your needs. Customize them as needed. + '*' DEFAULT) + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_FOREGROUND=32 + # typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use POWERLEVEL9K_GOOGLE_APP_CRED_CONTENT_EXPANSION to specify the content displayed by + # google_app_cred segment. Parameter expansions are very flexible and fast, too. See reference: + # http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion. + # + # You can use the following parameters in the expansion. Each of them corresponds to one of the + # fields in the JSON file pointed to by GOOGLE_APPLICATION_CREDENTIALS. + # + # Parameter | JSON key file field + # ---------------------------------+--------------- + # P9K_GOOGLE_APP_CRED_TYPE | type + # P9K_GOOGLE_APP_CRED_PROJECT_ID | project_id + # P9K_GOOGLE_APP_CRED_CLIENT_EMAIL | client_email + # + # Note: ${VARIABLE//\%/%%} expands to ${VARIABLE} with all occurences of '%' replaced by '%%'. + typeset -g POWERLEVEL9K_GOOGLE_APP_CRED_DEFAULT_CONTENT_EXPANSION='${P9K_GOOGLE_APP_CRED_PROJECT_ID//\%/%%}' + + ###############################[ public_ip: public IP address ]############################### + # Public IP color. + typeset -g POWERLEVEL9K_PUBLIC_IP_FOREGROUND=94 + # Custom icon. + # typeset -g POWERLEVEL9K_PUBLIC_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ########################[ vpn_ip: virtual private network indicator ]######################### + # VPN IP color. + typeset -g POWERLEVEL9K_VPN_IP_FOREGROUND=81 + # When on VPN, show just an icon without the IP address. + # Tip: To display the private IP address when on VPN, remove the next line. + typeset -g POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION= + # Regular expression for the VPN network interface. Run `ifconfig` or `ip -4 a show` while on VPN + # to see the name of the interface. + typeset -g POWERLEVEL9K_VPN_IP_INTERFACE='(wg|(.*tun))[0-9]*' + # If set to true, show one segment per matching network interface. If set to false, show only + # one segment corresponding to the first matching network interface. + # Tip: If you set it to true, you'll probably want to unset POWERLEVEL9K_VPN_IP_CONTENT_EXPANSION. + typeset -g POWERLEVEL9K_VPN_IP_SHOW_ALL=false + # Custom icon. + # typeset -g POWERLEVEL9K_VPN_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ###########[ ip: ip address and bandwidth usage for a specified network interface ]########### + # IP color. + typeset -g POWERLEVEL9K_IP_FOREGROUND=38 + # The following parameters are accessible within the expansion: + # + # Parameter | Meaning + # ----------------------+--------------- + # P9K_IP_IP | IP address + # P9K_IP_INTERFACE | network interface + # P9K_IP_RX_BYTES | total number of bytes received + # P9K_IP_TX_BYTES | total number of bytes sent + # P9K_IP_RX_RATE | receive rate (since last prompt) + # P9K_IP_TX_RATE | send rate (since last prompt) + typeset -g POWERLEVEL9K_IP_CONTENT_EXPANSION='$P9K_IP_IP${P9K_IP_RX_RATE:+ %70F⇣$P9K_IP_RX_RATE}${P9K_IP_TX_RATE:+ %215F⇡$P9K_IP_TX_RATE}' + # Show information for the first network interface whose name matches this regular expression. + # Run `ifconfig` or `ip -4 a show` to see the names of all network interfaces. + typeset -g POWERLEVEL9K_IP_INTERFACE='e.*' + # Custom icon. + # typeset -g POWERLEVEL9K_IP_VISUAL_IDENTIFIER_EXPANSION='⭐' + + #########################[ proxy: system-wide http/https/ftp proxy ]########################## + # Proxy color. + typeset -g POWERLEVEL9K_PROXY_FOREGROUND=68 + # Custom icon. + # typeset -g POWERLEVEL9K_PROXY_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ################################[ battery: internal battery ]################################# + # Show battery in red when it's below this level and not connected to power supply. + typeset -g POWERLEVEL9K_BATTERY_LOW_THRESHOLD=20 + typeset -g POWERLEVEL9K_BATTERY_LOW_FOREGROUND=160 + # Show battery in green when it's charging or fully charged. + typeset -g POWERLEVEL9K_BATTERY_{CHARGING,CHARGED}_FOREGROUND=70 + # Show battery in yellow when it's discharging. + typeset -g POWERLEVEL9K_BATTERY_DISCONNECTED_FOREGROUND=178 + # Battery pictograms going from low to high level of charge. + typeset -g POWERLEVEL9K_BATTERY_STAGES='\uf58d\uf579\uf57a\uf57b\uf57c\uf57d\uf57e\uf57f\uf580\uf581\uf578' + # Don't show the remaining time to charge/discharge. + typeset -g POWERLEVEL9K_BATTERY_VERBOSE=false + + #####################################[ wifi: wifi speed ]##################################### + # WiFi color. + typeset -g POWERLEVEL9K_WIFI_FOREGROUND=68 + # Custom icon. + # typeset -g POWERLEVEL9K_WIFI_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Use different colors and icons depending on signal strength ($P9K_WIFI_BARS). + # + # # Wifi colors and icons for different signal strength levels (low to high). + # typeset -g my_wifi_fg=(68 68 68 68 68) # <-- change these values + # typeset -g my_wifi_icon=('WiFi' 'WiFi' 'WiFi' 'WiFi' 'WiFi') # <-- change these values + # + # typeset -g POWERLEVEL9K_WIFI_CONTENT_EXPANSION='%F{${my_wifi_fg[P9K_WIFI_BARS+1]}}$P9K_WIFI_LAST_TX_RATE Mbps' + # typeset -g POWERLEVEL9K_WIFI_VISUAL_IDENTIFIER_EXPANSION='%F{${my_wifi_fg[P9K_WIFI_BARS+1]}}${my_wifi_icon[P9K_WIFI_BARS+1]}' + # + # The following parameters are accessible within the expansions: + # + # Parameter | Meaning + # ----------------------+--------------- + # P9K_WIFI_SSID | service set identifier, a.k.a. network name + # P9K_WIFI_LINK_AUTH | authentication protocol such as "wpa2-psk" or "none" + # P9K_WIFI_LAST_TX_RATE | wireless transmit rate in megabits per second + # P9K_WIFI_RSSI | signal strength in dBm, from -120 to 0 + # P9K_WIFI_NOISE | noise in dBm, from -120 to 0 + # P9K_WIFI_BARS | signal strength in bars, from 0 to 4 (derived from P9K_WIFI_RSSI and P9K_WIFI_NOISE) + # + # All parameters except P9K_WIFI_BARS are extracted from the output of the following command: + # + # /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I + + ####################################[ time: current time ]#################################### + # Current time color. + typeset -g POWERLEVEL9K_TIME_FOREGROUND=66 + # Format for the current time: 09:51:02. See `man 3 strftime`. + typeset -g POWERLEVEL9K_TIME_FORMAT='%D{%H:%M:%S}' + # If set to true, time will update when you hit enter. This way prompts for the past + # commands will contain the start times of their commands as opposed to the default + # behavior where they contain the end times of their preceding commands. + typeset -g POWERLEVEL9K_TIME_UPDATE_ON_COMMAND=false + # Custom icon. + # typeset -g POWERLEVEL9K_TIME_VISUAL_IDENTIFIER_EXPANSION='⭐' + # Custom prefix. + # typeset -g POWERLEVEL9K_TIME_PREFIX='%fat ' + + # Example of a user-defined prompt segment. Function prompt_example will be called on every + # prompt if `example` prompt segment is added to POWERLEVEL9K_LEFT_PROMPT_ELEMENTS or + # POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS. It displays an icon and orange text greeting the user. + # + # Type `p10k help segment` for documentation and a more sophisticated example. + function prompt_example() { + p10k segment -f 208 -i '⭐' -t 'hello, %n' + } + + # User-defined prompt segments may optionally provide an instant_prompt_* function. Its job + # is to generate the prompt segment for display in instant prompt. See + # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # + # Powerlevel10k will call instant_prompt_* at the same time as the regular prompt_* function + # and will record all `p10k segment` calls it makes. When displaying instant prompt, Powerlevel10k + # will replay these calls without actually calling instant_prompt_*. It is imperative that + # instant_prompt_* always makes the same `p10k segment` calls regardless of environment. If this + # rule is not observed, the content of instant prompt will be incorrect. + # + # Usually, you should either not define instant_prompt_* or simply call prompt_* from it. If + # instant_prompt_* is not defined for a segment, the segment won't be shown in instant prompt. + function instant_prompt_example() { + # Since prompt_example always makes the same `p10k segment` calls, we can call it from + # instant_prompt_example. This will give us the same `example` prompt segment in the instant + # and regular prompts. + prompt_example + } + + # User-defined prompt segments can be customized the same way as built-in segments. + # typeset -g POWERLEVEL9K_EXAMPLE_FOREGROUND=208 + # typeset -g POWERLEVEL9K_EXAMPLE_VISUAL_IDENTIFIER_EXPANSION='⭐' + + # Transient prompt works similarly to the builtin transient_rprompt option. It trims down prompt + # when accepting a command line. Supported values: + # + # - off: Don't change prompt when accepting a command line. + # - always: Trim down prompt when accepting a command line. + # - same-dir: Trim down prompt when accepting a command line unless this is the first command + # typed after changing current working directory. + typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=always + + # Instant prompt mode. + # + # - off: Disable instant prompt. Choose this if you've tried instant prompt and found + # it incompatible with your zsh configuration files. + # - quiet: Enable instant prompt and don't print warnings when detecting console output + # during zsh initialization. Choose this if you've read and understood + # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # - verbose: Enable instant prompt and print a warning when detecting console output during + # zsh initialization. Choose this if you've never tried instant prompt, haven't + # seen the warning, or if you are unsure what this all means. + typeset -g POWERLEVEL9K_INSTANT_PROMPT=off + + # Hot reload allows you to change POWERLEVEL9K options after Powerlevel10k has been initialized. + # For example, you can type POWERLEVEL9K_BACKGROUND=red and see your prompt turn red. Hot reload + # can slow down prompt by 1-2 milliseconds, so it's better to keep it turned off unless you + # really need it. + typeset -g POWERLEVEL9K_DISABLE_HOT_RELOAD=true + + # If p10k is already loaded, reload configuration. + # This works even with POWERLEVEL9K_DISABLE_HOT_RELOAD=true. + (( ! $+functions[p10k] )) || p10k reload +} + +# Tell `p10k configure` which file it should overwrite. +typeset -g POWERLEVEL9K_CONFIG_FILE=${${(%):-%x}:a} + +(( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]} +'builtin' 'unset' 'p10k_config_opts' diff --git a/users/gkleen/default.nix b/users/gkleen/default.nix index f74701a5..26f7a1d4 100644 --- a/users/gkleen/default.nix +++ b/users/gkleen/default.nix @@ -1,5 +1,9 @@ -{ userName, pkgs, customUtils, lib, ... }: +{ flake, userName, pkgs, customUtils, lib, ... }: { + imports = with flake.nixosModules.userProfiles.${userName}; [ + zsh tmux utils + ]; + users.users.${userName} = { description = "Gregor Kleen"; extraGroups = [ "wheel" "networkmanager" "lp" "dialout" "audio" "video" "xmpp" "mail" "ssh" "vboxusers" "libvirtd" "wireshark" "games"]; @@ -12,4 +16,32 @@ openssh.authorizedKeys.keyFiles = lib.attrValues (customUtils.recImport rec { dir = ./authorized-keys; _import = name: _base: dir + "/${name}"; }); hashedPassword = "$6$rounds=500000$dOMgCU7DAk$yQFYGOURTEt12387LIYBnFKSWmtwXMUk1LJWnV0m7OFt.y2TnxQn2abdGA5dhwG9EmMB5wZGXf4J5F71c746C/"; }; + + home-manager.users.${userName} = { + programs = { + git = { + enable = true; + userEmail = "gkleen@yggdrasil.li"; + userName = "Gregor Kleen"; + delta.enable = true; + extraConfig = { + pull.rebase = false; + }; + }; + + ssh = { + enable = true; + controlMaster = "auto"; + controlPersist = "30m"; + serverAliveInterval = 6; + hashKnownHosts = true; + extraConfig = '' + IdentitiesOnly true + ServerAliveCountMax 10 + ''; + }; + + gpg.enable = true; + }; + }; } diff --git a/users/root.nix b/users/root.nix index 95fe37c4..c6e7d712 100644 --- a/users/root.nix +++ b/users/root.nix @@ -1,7 +1,30 @@ -{ flake, lib, config, hostName, ... }: -{ - users.users.root = lib.mkIf (flake.nixosModules.accounts ? "gkleen@${hostName}") { +{ flake, lib, config, hostName, userName, pkgs, ... }: +let + haveGKleen = flake.nixosModules.accounts ? "gkleen@${hostName}"; +in { + imports = with flake.nixosModules.userProfiles.${userName}; [ + zsh tmux utils + ]; + + users.users.${userName} = lib.mkIf haveGKleen { inherit (config.users.users."gkleen") hashedPassword shell; openssh.authorizedKeys.keyFiles = config.users.users."gkleen".openssh.authorizedKeys.keyFiles; }; + + home-manager.users.${userName} = { + programs = lib.mkIf haveGKleen { + inherit (config.home-manager.users.gkleen.programs) git ssh gpg; + }; + + services = { + gpg-agent = { + enable = true; + enableSshSupport = true; + extraConfig = '' + pinentry-program ${pkgs.pinentry-curses}/bin/pinentry + grab + ''; + }; + }; + }; } -- cgit v1.2.3