commit b63a90059a01f4d075a9a217f5e2fc7fbe9c097a Author: Joseph Ferano Date: Thu May 25 20:18:46 2023 +0700 Only include what I'm using diff --git a/.config/emacs/init.org b/.config/emacs/init.org new file mode 100644 index 0000000..16b4846 --- /dev/null +++ b/.config/emacs/init.org @@ -0,0 +1,2232 @@ +#+TITLE: Emacs Config +#+AUTHOR: Joseph Ferano +#+PROPERTY: header-args:emacs-lisp :tangle ./init.el +#+STARTUP: overview +#+TOC: true + +** Early Init +*** Filename handler alist +Skipping a bunch of regular expression searching in the file-name-handler-alist should improve start time. + +#+begin_src emacs-lisp +(defvar default-file-name-handler-alist file-name-handler-alist) +(setq file-name-handler-alist nil) +#+end_src +*** Garbage Collection + +The default Garbage Collector is triggered at 800 KB, way too conservative, let's bump to 512 MB. +Garbage collection is a big contributor to startup times. This fends it off, then is reset later by +enabling `gcmh-mode'. Not resetting it will cause stuttering/freezes. + +#+begin_src emacs-lisp :tangle ./early-init.el +;; -*- lexical-binding: t -*- +(setq gc-cons-threshold (expt 2 32)) + +(add-hook 'emacs-startup-hook + (lambda () + "Restore defalut values after init." + (setq file-name-handler-alist default-file-name-handler-alist) + (if (boundp 'after-focus-change-function) + (add-function :after after-focus-change-function + (lambda () + (unless (frame-focus-state) + (garbage-collect)))) + (add-hook 'focus-out-hook 'garbage-collect)))) + +(setq native-comp-async-report-warnings-errors nil) +#+end_src + +Disabling these classic visual options during early-init seems to net a 0.04 ms boost in init time + +#+begin_src emacs-lisp :tangle ./early-init.el +(setq max-specpdl-size 1200) +(setq max-lisp-eval-depth 800) + +(scroll-bar-mode -1) +(tool-bar-mode -1) +(menu-bar-mode -1) +(tooltip-mode -1) +#+end_src +*** Enhancements + +Disable package.el, since we will be using elpaca.el. According to the elpaca.el +documentation; + +#+BEGIN_SRC emacs-lisp :tangle ./early-init.el +(setq package-enable-at-startup nil) +#+END_SRC + +Prioritize old byte-compiled source files over newer sources. It saves us a +little IO time to skip all the mtime checks on each lookup. + +#+begin_src emacs-lisp :tangle ./early-init.el +(setq load-prefer-newer nil) + +(setq safe-local-variable-values + '((org-src-preserve-indentation . t) + (eval add-hook 'after-save-hook + '(lambda nil + (org-babel-tangle)) + nil t))) + +;; (setq server-name (format "Emacs-%d" (emacs-pid))) +;; (add-hook 'after-init-hook #'server-start) +#+end_src + +Prevent instructions on how to close an emacsclient frame. + +#+begin_src emacs-lisp +(setq server-client-instructions nil) +#+end_src + +Implicitly resizing the Emacs frame adds to init time. Fonts larger than the +system default can cause frame resizing, which adds to startup time. + +#+begin_src emacs-lisp +(setq frame-inhibit-implied-resize t) +#+end_src + +Ignore X resources. + +#+begin_src emacs-lisp +(advice-add #'x-apply-session-resources :override #'ignore) +#+end_src +*** UTF-8 Support +#+begin_src emacs-lisp :tangle ./early-init.el +(setq default-input-method nil) +(setq utf-translate-cjk-mode nil) ; disable CJK coding/encoding (Chinese/Japanese/Korean characters) +(set-language-environment 'utf-8) +(set-keyboard-coding-system 'utf-8-mac) ; For old Carbon emacs on OS X only +(setq locale-coding-system 'utf-8) +(set-default-coding-systems 'utf-8) +(set-terminal-coding-system 'utf-8) +(set-selection-coding-system 'utf-8) +(prefer-coding-system 'utf-8) +#+end_src + +Finish up +#+begin_src emacs-lisp +(provide 'early-init) +;;; early-init.el ends here +#+end_src +** COMMENT Elpaca +#+BEGIN_SRC emacs-lisp + ;; -*- lexical-binding: t -*- +(defvar elpaca-installer-version 0.3) +(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory)) +(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) +(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) +(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" + :ref nil + :files (:defaults (:exclude "extensions")) + :build (:not elpaca--activate-package))) +(let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) + (build (expand-file-name "elpaca/" elpaca-builds-directory)) + (order (cdr elpaca-order)) + (default-directory repo)) + (add-to-list 'load-path (if (file-exists-p build) build repo)) + (unless (file-exists-p repo) + (make-directory repo t) + (condition-case-unless-debug err + (if-let ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*")) + ((zerop (call-process "git" nil buffer t "clone" + (plist-get order :repo) repo))) + ((zerop (call-process "git" nil buffer t "checkout" + (or (plist-get order :ref) "--")))) + (emacs (concat invocation-directory invocation-name)) + ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" + "--eval" "(byte-recompile-directory \".\" 0 'force)"))) + ((require 'elpaca)) + ((elpaca-generate-autoloads "elpaca" repo))) + (kill-buffer buffer) + (error "%s" (with-current-buffer buffer (buffer-string)))) + ((error) (warn "%s" err) (delete-directory repo 'recursive)))) + (unless (require 'elpaca-autoloads nil t) + (require 'elpaca) + (elpaca-generate-autoloads "elpaca" repo) + (load "./elpaca-autoloads"))) + +(add-hook 'after-init-hook #'elpaca-process-queues) + +(elpaca `(,@elpaca-order)) + +(setq elpaca-queue-limit 30) + +#+END_SRC +** Package Management +#+begin_src emacs-lisp +;; Also read: +(setq package-archives + '(("elpa" . "https://elpa.gnu.org/packages/") + ("elpa-devel" . "https://elpa.gnu.org/devel/") + ("nongnu" . "https://elpa.nongnu.org/nongnu/") + ("melpa" . "https://melpa.org/packages/"))) +;; Add MELPA to `package-archives' +(add-to-list 'package-archives + '("melpa" . "https://melpa.org/packages/")) + + +;; Proof-of-concept to install a list of packages +(mapc + (lambda (package) + (unless (package-installed-p package) + (package-install package))) + '(recentf + benchmark-init + ;; dashboard + olivetti + ;; ligature + highlight-quoted + doom-modeline + ;; hydra + ;; multiple-cursors + evil + evil-collection + evil-surround + evil-snipe + evil-commentary + evil-goggles + all-the-icons-ibuffer + ;; ace-window + popper + centaur-tabs + all-the-icons-completion + vertico + vertico-posframe + savehist + embark + embark-consult + marginalia + all-the-icons-completion + orderless + consult + consult-eglot + dirvish + smtpmail + sendmail + age + avy + helpful + vterm + undo-fu + undo-fu-session + vundo + which-key + ;; company + mono-complete + ;; lsp-mode + ;; lsp-ui + ;; flycheck + ;; dap-mode + rustic + ob-rust + typescript-mode + disaster + haskell-mode + clojure-mode + cider + fsharp-mode + go-mode + json-mode + markdown-mode + org-bullets + org-kanban + restclient + magit)) + +(setopt package-vc-selected-packages + '((dotenv :url "https://github.com/pkulev/dotenv.el") + (doom-themes :url "https://github.com/JosephFerano/doom-themes"))) +(package-initialize) + +#+end_src +** COMMENT Benchmarking + +This is commented out since it adds ever so slightly to init time, but keep it around in case we +need to benchmark slow init times later. + +#+begin_src emacs-lisp +(require 'benchmark-init) +(add-hook 'after-init-hook 'benchmark-init/deactivate) +#+end_src +** Misc Stuff + +#+begin_SRC emacs-lisp +(setq default-directory "/home/joe/") +(setq vc-follow-symlinks t) ; Visit real file when editing a symlink without prompting. +(global-auto-revert-mode t) ; Revert buffer's file when the file changes on disk + +(setq confirm-kill-emacs 'y-or-n-p) + +(require 'recentf) +(recentf-mode t) +(setq recentf-auto-cleanup 10) +(setq recentf-keep '(file-remote-p file-readable-p)) +(setq recentf-max-saved-items 1000) +(setq package-native-compile t) +#+end_src + +This avoids those annoying *#backup#* files that get added and eventually slow down loading the file again. + +#+begin_src emacs-lisp +(setq auto-save-default nil) +(setq create-lockfiles nil) +#+end_src + +#+begin_src emacs-lisp +(setq use-dialog-box nil) +(fset 'yes-or-no-p 'y-or-n-p) +(setq large-file-warning-threshold 100000000) +(setq backup-directory-alist `((".*" . ,(expand-file-name "backups" user-emacs-directory)))) +(setq backup-by-copying t + delete-old-versions t + kept-new-versions 6 + kept-old-versions 2 + version-control t) +#+END_SRC + +I don't even know how you resume from GUI mode, we'll find a use for this keybinding later on + +#+begin_src emacs-lisp +(when (display-graphic-p) + (global-unset-key (kbd "C-z"))) +#+end_src +** Visuals +*** COMMENT Dashboard + +Use Dashboard.el. First load `all-the-icons` for nicer rendering +#+begin_src emacs-lisp + +;; (elpaca 'all-the-icons) +;; (package-vc-install (dashboard :ref) +(require 'dashboard) +(dashboard-setup-startup-hook) + (setq dashboard-items '((recents . 6) + (projects . 5) + (bookmarks . 5))) + (setq dashboard-startup-banner 'logo) + (setq dashboard-center-content t) + (setq dashboard-set-file-icons t) + (setq dashboard-set-navigator t) + (setq dashboard-set-heading-icons t) + (setq dashboard-projects-backend 'project-el) + + (add-hook 'dashboard-mode-hook + (lambda () + (setq-local line-spacing 12) +;; TODO: It's not jumping + (dashboard-jump-to-recents))) + + ;; (defun joe/launch-dashboard () + ;; "Jump to the dashboard buffer, if doesn't exists create one." + ;; (interactive) + ;; (switch-to-buffer dashboard-buffer-name) + ;; (dashboard-mode) + ;; (dashboard-insert-startupify-lists)) +#+end_src +*** Olivetti + +#+begin_src emacs-lisp +(require 'olivetti) +(setq olivetti-minimum-body-width 100) +(global-set-key (kbd "C-x x o") 'olivetti-mode) +#+end_src +*** Themes + +#+begin_src emacs-lisp +;; Small changes to my favorite themes + +;; (load-theme 'doom-nord-light)) + +(setq custom-safe-themes t) + +(custom-set-faces + '(dashboard-items-face ((t (:inherit widget-button :weight normal))))) + +#+end_src + +We want to add whatever custom theme we selected to the custom variables since emacs will just +automatically read it on startup but we don't want emacs to add these settings to init.el, which in +our case is worse since we have a literate file. Send all custom variables to ~custom.el~ + +#+begin_src emacs-lisp +(setq custom-file (expand-file-name "custom.el" user-emacs-directory)) +(load custom-file) +#+end_src + +Save the chosen theme after picking a new one + +#+begin_src emacs-lisp +(defun joe/save-current-theme (THEME) + (let ((inhibit-message t) + (message-log-max nil)) + (customize-save-variable 'custom-enabled-themes custom-enabled-themes))) +(advice-add 'consult-theme :after #'joe/save-current-theme) + +#+end_src +*** Other + +Setup other stuff + +#+begin_src emacs-lisp +(setq ring-bell-function 'ignore) +(add-to-list 'default-frame-alist '(undecorated . t)) +(add-to-list 'default-frame-alist '(fullscreen . maximized)) +(add-to-list 'default-frame-alist '(vertical-scroll-bars . nil)) + +(add-hook 'text-mode-hook (lambda () (setq fill-column 80) (turn-on-auto-fill))) + +(setq-default display-line-numbers 'relative) +(make-variable-buffer-local 'global-hl-line-mode) + +(defun joe/disable-line-numbers () (display-line-numbers-mode 0)) + +(dolist (mode '( dashboard-mode-hook org-mode-hook term-mode-hook eww-mode-hook + vterm-mode-hook dirvish-directory-view-mode-hook eshell-mode-hook + dired-mode-hook shell-mode-hook magit-mode-hook compilation-mode-hook + mu4e-headers-mode-hook mu4e-main-mode-hook)) + (add-hook mode #'joe/disable-line-numbers)) + +(set-window-margins nil 0) +(setq-default right-fringe-width 10) +(setq scroll-margin 0 + scroll-conservatively 100000 + scroll-preserve-screen-position 1) + +(global-hl-line-mode +1) +(column-number-mode +1) + +(modify-all-frames-parameters + '((right-divider-width . 5) + (tab-bar-lines . 0) + (internal-border-width . 12))) + +(when (>= emacs-major-version 29) + (pixel-scroll-precision-mode t)) + +(setq inhibit-startup-screen t) + +;; Don’t compact font caches during GC, in case doom modeline gets laggy issue +(setq inhibit-compacting-font-caches t) + +(require 'highlight-quoted) +(add-hook 'emacs-lisp-mode-hook 'highlight-quoted-mode) + +(require 'doom-modeline) +(doom-modeline-mode) +(doom-modeline-def-modeline 'main + '(bar modals bar window-number matches buffer-info remote-host buffer-position word-count selection-info) + '(parrot objed-state misc-info battery grip irc mu4e gnus github debug repl lsp bar input-method indent-info buffer-encoding bar major-mode process)) +;; Show the tab names, just put this at the car of the previous list +;; workspace-name +;; Set default mode-line +(add-hook 'doom-modeline-mode-hook + (lambda () + (doom-modeline-set-modeline 'main 'default))) + + +;; TODO Likely not needed anymore +(dolist (mode '(dired-mode-hook lsp-help-mode-hook fundamental-mode-hook)) + (add-hook mode (lambda () (setq truncate-lines t)))) +#+end_src + +Ligatures... are they that useful? +#+begin_src emacs-lisp :tangle no +(require 'ligature) +(global-ligature-mode) +#+end_src +** Text + +#+begin_src emacs-lisp +;; (set-face-attribute 'default nil :family "Fira Code Nerd Font Mono" :height 110) +(set-face-attribute 'default nil :family "FiraCode Nerd Font Mono" :height 110) +;; (set-face-attribute 'variable-pitch nil :family "Source Code Pro" :height 120) +(setq-default c-basic-offset 4) ;; This is annoying +(setq-default indent-tabs-mode nil) +(setq-default tab-width 4) +(setq-default line-spacing 5) +(setq indent-line-function #'indent-relative) + +(set-default 'truncate-lines t) +;; (add-hook 'before-save-hook 'whitespace-cleanup) +#+end_src +** Text Editor + +Emacs is an great operating system, if only it had a good text editor... + +*** Text editing +#+begin_src emacs-lisp + +;; TODO Find out what to do with this +(defun joe/bookmark-set-and-save () + "Save the current buffer as a bookmark" + (interactive) + (bookmark-set) + (bookmark-save)) + +(global-set-key (kbd "M-z") #'zap-up-to-char) +(global-set-key (kbd "M-Z") #'zap-to-char) + +(defun joe/duplicate-line-comment () + (interactive) + (let ((col (current-column))) + (duplicate-line) + (comment-line 1) + (move-to-column col))) + +(global-set-key (kbd "C-c d") 'duplicate-line) +(global-set-key (kbd "C-c C-;") 'joe/duplicate-line-comment) + +(global-set-key (kbd "M-n") (kbd "C-u 1 C-v")) +(global-set-key (kbd "M-p") (kbd "C-u 1 M-v")) + +(defun joe/insert-line-below () + "Insert an empty line below the current line." + (interactive) + (save-excursion + (end-of-line) + (open-line 1))) + +(defun joe/insert-line-above () + "Insert an empty line above the current line." + (interactive) + (save-excursion + (end-of-line 0) + (open-line 1))) + +(global-set-key (kbd "M-o") #'joe/insert-line-below) +(global-set-key (kbd "M-O") #'joe/insert-line-above) + +#+end_src + +For the longest time I had no idea why the ~(~ and ~)~ vim motions for sentences +weren't working, until I randomly saw this in someone's init.el + +#+begin_src emacs-lisp +(setq sentence-end-double-space nil) +#+end_src + +#+end_src +*** COMMENT Hydra +#+begin_src emacs-lisp +(require 'hydra) + +(defhydra hydra-navigate (global-map "") + "Window Navigation" + ("q" nil "quit") + ("d" joe/smooth-scroll-half-page-down "half page down") + ("u" joe/smooth-scroll-half-page-up "half page up") + ("e" joe/smooth-scroll-short-down "line down") + ("y" joe/smooth-scroll-short-up "line up") + ("n" next-line "line down") + ("p" previous-line "line up") + ("M-r" move-to-window-line-top-bottom "Reposition cursor")) +#+end_src +*** COMMENT Multiple Cursors + +#+begin_src emacs-lisp +(require 'multiple-cursors) +#+end_src +*** COMMENT Meow +#+begin_src emacs-lisp +(elpaca 'meow) +(defun meow-setup () + (setq meow-cheatsheet-layout meow-cheatsheet-layout-qwerty) + (meow-motion-overwrite-define-key + '("j" . meow-next) + '("k" . meow-prev) + '("" . ignore)) + (meow-leader-define-key + ;; SPC j/k will run the original command in MOTION state. + '("j" . "H-j") + '("k" . "H-k") + ;; Use SPC (0-9) for digit arguments. + '("1" . meow-digit-argument) + '("2" . meow-digit-argument) + '("3" . meow-digit-argument) + '("4" . meow-digit-argument) + '("5" . meow-digit-argument) + '("6" . meow-digit-argument) + '("7" . meow-digit-argument) + '("8" . meow-digit-argument) + '("9" . meow-digit-argument) + '("0" . meow-digit-argument) + '("/" . meow-keypad-describe-key) + '("?" . meow-cheatsheet)) + (meow-normal-define-key + '("0" . meow-expand-0) + '("9" . meow-expand-9) + '("8" . meow-expand-8) + '("7" . meow-expand-7) + '("6" . meow-expand-6) + '("5" . meow-expand-5) + '("4" . meow-expand-4) + '("3" . meow-expand-3) + '("2" . meow-expand-2) + '("1" . meow-expand-1) + '("-" . negative-argument) + '(";" . meow-reverse) + '("," . meow-inner-of-thing) + '("." . meow-bounds-of-thing) + '("[" . meow-beginning-of-thing) + '("]" . meow-end-of-thing) + '("a" . meow-append) + '("A" . meow-open-below) + '("b" . meow-back-word) + '("B" . meow-back-symbol) + '("c" . meow-change) + '("d" . meow-delete) + '("D" . meow-backward-delete) + '("e" . meow-next-word) + '("E" . meow-next-symbol) + '("f" . meow-find) + '("g" . meow-cancel-selection) + '("G" . meow-grab) + '("h" . meow-left) + '("H" . meow-left-expand) + '("i" . meow-insert) + '("I" . meow-open-above) + '("j" . meow-next) + '("J" . meow-next-expand) + '("k" . meow-prev) + '("K" . meow-prev-expand) + '("l" . meow-right) + '("L" . meow-right-expand) + '("m" . meow-join) + '("n" . meow-search) + '("o" . meow-block) + '("O" . meow-to-block) + '("p" . meow-yank) + '("q" . meow-quit) + '("Q" . meow-goto-line) + '("r" . meow-replace) + '("R" . meow-swap-grab) + '("s" . meow-kill) + '("t" . meow-till) + '("u" . meow-undo) + '("U" . meow-undo-in-selection) + '("v" . meow-visit) + '("w" . meow-mark-word) + '("W" . meow-mark-symbol) + '("x" . meow-line) + '("X" . meow-goto-line) + '("y" . meow-save) + '("Y" . meow-sync-grab) + '("z" . meow-pop-selection) + '("'" . repeat) + '("" . ignore))) +(require 'meow) +(meow-setup) +(meow-global-mode t) +(setq scroll-preserve-screen-position nil) +#+end_src +*** Boon +#+begin_src emacs-lisp :tangle no +(defun joe/psp-scroll-down-half-page () + (interactive) + (pixel-scroll-precision-scroll-down-page (/ (window-pixel-height) 2))) +(defun joe/psp-scroll-up-half-page () + (interactive) + (pixel-scroll-precision-scroll-up-page (/ (window-pixel-height) 2))) + +(elpaca 'boon + (require 'boon-qwerty) + (boon-mode) + (define-key boon-moves-map "h" 'backward-char) + (define-key boon-moves-map "j" 'next-line) + (define-key boon-moves-map "k" 'previous-line) + (define-key boon-moves-map "l" 'forward-char) + (define-key boon-moves-map "b" 'boon-smarter-backward) + (define-key boon-moves-map "w" 'boon-smarter-forward) + (define-key boon-moves-map "q" '("hop" . avy-goto-char-2)) + (define-key boon-command-map (kbd "C-k") #'joe/scroll-down-line) + (define-key boon-command-map (kbd "C-j") #'joe/scroll-up-line) + + (define-key boon-command-map (kbd "C-d") #'joe/psp-scroll-down-half-page) + (define-key boon-command-map (kbd "C-u") #'joe/psp-scroll-up-half-page) + + + (defun joe/scroll-up-line () (interactive) (scroll-up-line 2)) + (defun joe/scroll-down-line () (interactive) (scroll-down-line 2)) + + (define-key boon-moves-map "H" 'backward-paragraph) + (define-key boon-moves-map "L" 'forward-paragraph) + (define-key boon-moves-map "K" 'boon-smarter-upward) + + (define-key boon-moves-map "J" 'boon-smarter-downward) + + (define-key boon-moves-map "o" 'boon-open-next-line-and-insert) + (define-key boon-moves-map "O" 'boon-open-line-and-insert) + + (define-key boon-moves-map "i" 'boon-set-insert-like-state) + (define-key boon-moves-map "r" 'boon-replace-by-character) + (define-key boon-moves-map "y" 'boon-replace-by-character) + (define-key boon-moves-map "p" 'boon-splice) + (define-key boon-moves-map "y" 'boon-treasure-region) + + (define-key ctl-x-map "s" 'save-buffer)) + +#+end_src +*** Evil +#+begin_src emacs-lisp + +(setq evil-want-keybinding nil) +(setq evil-undo-system 'undo-fu) +(setq evil-want-C-u-scroll t) +(setq evil-want-Y-yank-to-eol t) +(setq evil-disable-insert-state-bindings t) +(setq evil-echo-state nil) + +(require 'evil) + (evil-mode t) + + (evil-global-set-key 'insert (kbd "C-w") #'evil-delete-backward-word) + (evil-define-key 'normal 'global (kbd "q") 'avy-goto-word-0) + + ;; vv to expand selection to line + (evil-global-set-key 'visual + (kbd "v") + (lambda () + (interactive) + (evil-first-non-blank) + (exchange-point-and-mark) + (evil-end-of-line))) + + + (defvar joe/evil-space-mode-map (make-sparse-keymap) + "High precedence keymap.") + + (define-minor-mode joe/evil-space-mode + "Global minor mode for higher precedence evil keybindings." + :global t) + + (joe/evil-space-mode) + + (dolist (state '(normal visual insert)) + (evil-make-intercept-map + ;; NOTE: This requires an evil version from 2018-03-20 or later + (evil-get-auxiliary-keymap joe/evil-space-mode-map state t t) + state)) + + (evil-define-key 'normal joe/evil-space-mode-map + (kbd "K") #'eldoc + (kbd "SPC t") tab-prefix-map + (kbd "SPC p") project-prefix-map + (kbd "SPC q") 'kill-buffer-and-window + (kbd "SPC k") 'kill-this-buffer + (kbd "SPC h") 'help-command + (kbd "SPC hf") 'helpful-callable + (kbd "SPC hv") 'helpful-variable + (kbd "SPC hk") 'helpful-key + (kbd "SPC ho") 'helpful-symbol + (kbd "SPC hg") 'helpful-at-point + (kbd "SPC fb") 'bookmark-jump + (kbd "SPC fr") 'consult-recent-file + (kbd "SPC ff") 'project-find-file + (kbd "SPC fa") '(lambda () (interactive) (project-find-file t)) + (kbd "SPC fi") 'joe/edit-init + (kbd "SPC bl") 'mode-line-other-buffer + (kbd "SPC ba") 'switch-to-buffer + (kbd "SPC bb") 'consult-buffer + (kbd "SPC bi") 'ibuffer + (kbd "SPC bm") 'joe/toggle-buffer-mode + (kbd "SPC br") 'joe/revert-buffer-no-confirm + (kbd "SPC gg") 'magit-status + (kbd "SPC gc") 'magit-clone + (kbd "SPC ss") 'joe/vterm-here + (kbd "SPC sv") 'vterm + (kbd "SPC Ba") 'joe/bookmark-set-and-save + (kbd "SPC Bd") 'bookmark-delete + (kbd "SPC mr") 'joe/compile-run + (kbd "SPC mc") 'joe/compile-comp + (kbd "SPC ct") 'consult-theme + (kbd "SPC cl") 'consult-line + (kbd "SPC ci") 'consult-imenu + (kbd "SPC cy") 'consult-yank-from-kill-ring + (kbd "SPC cg") 'consult-ripgrep + (kbd "SPC cF") 'consult-find + (kbd "SPC co") 'consult-outline) + + (define-key evil-window-map "u" #'winner-undo) + (define-key evil-window-map "U" #'winner-redo) + + (defvar joe-mode-map + (let ((map (make-sparse-keymap))) + ;; (define-key map (kbd "C-'") #'embark-act) + map) + "my-keys-minor-mode keymap.") + +(define-key joe/evil-space-mode-map (kbd "M-'") #'embark-dwim) +(define-key joe/evil-space-mode-map (kbd "C-'") #'embark-act) +(define-key joe/evil-space-mode-map (kbd "C-/") #'comment-line) + + (defun joe/scroll-up-line () (interactive) (scroll-up-line 2)) + (defun joe/scroll-down-line () (interactive) (scroll-down-line 2)) + (evil-global-set-key 'normal (kbd "C-e") #'joe/scroll-up-line) + (evil-global-set-key 'normal (kbd "C-y") #'joe/scroll-down-line) + + +(require 'evil-collection) +(evil-collection-init) + +(require 'evil-surround) +(global-evil-surround-mode t) + +(require 'evil-snipe) +(evil-snipe-override-mode +1) + +(require 'evil-commentary) +(evil-commentary-mode t) + +(require 'evil-goggles) + (evil-goggles-mode t) + (setq evil-goggles-duration 0.075) + (setq evil-goggles-pulse t) + (setq evil-goggles-async-duration 0.55) + +#+end_src +** Buffers +#+begin_src emacs-lisp +(defun joe/kill-this-buffer-or-popup () + (interactive) + "Kill the buffer normally, but if it's a popper popup, call the popper version" + (with-current-buffer (current-buffer) + (if (or (eq popper-popup-status nil) + (eq popper-popup-status 'raised)) + (kill-this-buffer) + (popper-kill-latest-popup)))) + +(global-set-key (kbd "C-x k") #'joe/kill-this-buffer-or-popup) +(global-set-key (kbd "C-x M-k") #'kill-buffer) +(require 'all-the-icons-ibuffer) +(add-hook 'ibuffer-mode-hook #'all-the-icons-ibuffer-mode) +(global-set-key [remap list-buffers] 'ibuffer) +(global-set-key (kbd "C-x B") 'ibuffer) +(global-set-key (kbd "C-x b") 'consult-project-buffer) +(global-set-key (kbd "C-x C-b") 'consult-buffer) + +(defun joe/switch-other-buffer () + "Switch to other buffer" + (interactive) + (switch-to-buffer (other-buffer))) + +(global-set-key (kbd "C-x l") 'joe/switch-other-buffer) + +(save-place-mode t) +(setq save-place-file (expand-file-name "places" user-emacs-directory)) +#+end_src + +The theme of `C-x 4` bindings is that they operate on other windows, so this function matches that behavior. + +#+begin_src emacs-lisp +(defun joe/kill-other-buffer-and-window () + "Kill other buffer and window" + (interactive) + (other-window 1) + (kill-buffer-and-window)) +(global-set-key (kbd "C-x 4 0") 'joe/kill-other-buffer-and-window) +(global-set-key (kbd "C-x C-0") 'kill-buffer-and-window) + +#+end_src +** Windows +*** Window Management + +#+begin_src emacs-lisp +(add-hook 'after-init-hook (lambda () (winner-mode t))) + +(setq joe/popper-side-toggle 'right) +(defun joe/window-split-vertical () (interactive) (set 'joe/popper-side-toggle 'right)) +(defun joe/window-split-horizontal () (interactive) (set 'joe/popper-side-toggle 'below)) + +(define-key ctl-x-4-map (kbd "|") #'joe/window-split-vertical) +(define-key ctl-x-4-map (kbd "-") #'joe/window-split-horizontal) +(define-key ctl-x-4-map (kbd "t") #'rotate-window) + +(global-set-key (kbd "s-h") #'windmove-left) +(global-set-key (kbd "s-l") #'windmove-right) +(global-set-key (kbd "s-k") #'windmove-up) +(global-set-key (kbd "s-j") #'windmove-down) + +;; There's a bug in Gnome where frames are resized to the wrong dimensions +(defun joe/resize-frames () + (interactive) + (dolist (frame (frame-list)) + (toggle-frame-maximized frame) + (toggle-frame-maximized frame))) + +(global-set-key (kbd "s-") #'joe/resize-frames) +#+end_src + +Ace Window will show a hint if there are more than 2 windows, but I don't really use it + +#+begin_src emacs-lisp :tangle no + +(require 'ace-window) +(global-set-key (kbd "C-x o") #'ace-window) +(global-set-key (kbd "C-x C-o") #'ace-swap-window) + +#+end_src + +#+begin_src emacs-lisp :tangle no + +;; TODO Prot help improving workflow +(global-set-key (kbd "C-`") #'window-toggle-side-windows) + +(defvar joe/side-window-buffers '("^\\*Flycheck errors\\*$" + "^\\*Completions\\*$" + "^\\*Occur\\*$" + "^\\*Help\\*$" + "^\\*Embark.*" + "^\\*helpful .*" + "^\\*Compilation\\*$" + "^\\*SQL.*" + "^\\*HTTP Response\\*$" + "^\\*grep\\*$" + "^\\*Colors\\*$" + "^\\*Async Shell Command\\*$")) +(dolist (bufname joe/side-window-buffers) + (add-to-list 'display-buffer-alist + `(,bufname + display-buffer-in-side-window + (side . right) + (window-width . 0.43) + (slot . 0) + (window-parameters + (no-delete-other-windows . t))))) + +#+end_src +*** Beframe +#+begin_src emacs-lisp +(defvar consult-buffer-sources) +(declare-function consult--buffer-state "consult") + +(with-eval-after-load 'consult + (defface beframe-buffer + '((t :inherit font-lock-string-face)) + "Face for `consult' framed buffers.") + + ;; If you want to filter the current buffer you can use this and replace :items in the + ;; beframe-consult-source var + ;; (defun joe/consult-beframe-names-minus-current () + ;; (delete (buffer-name) (beframe-buffer-names))) +;; :items ,#'joe/consult-beframe-names-minus-current + + (defvar beframe-consult-source + `( :name "Frame-specific buffers (current frame)" + :narrow ?F + :category buffer + :face beframe-buffer + :history beframe-history + :items ,#'beframe-buffer-names + :action ,#'switch-to-buffer + :state ,#'consult--buffer-state)) + + (add-to-list 'consult-buffer-sources 'beframe-consult-source)) + +(beframe-mode +1) +#+end_src +*** Popper + +#+begin_src emacs-lisp +(require 'popper) +(setq popper-reference-buffers + '("\\*compilation\\*" compilation-mode + "^\\*vterm\\*" vterm-mode + "^\\*Flymake.*" flymake-mode + "^\\*Flycheck.*" flycheck-error-list-mode + "^\\*Occur\\*$" occur-mode + "^\\*lsp-help\\*" lsp-help-mode + "^\\*eldoc\\*" special-mode + "^\\*ert\\*" ert-results-mode + "^\\*HTTP Response\\*" javascript-mode + "^\\*SQL.*" sql-interactive-mode + "^\\*cargo-test\\*" cargo-test-mode + "^\\*cargo-run\\*" cargo-run-mode + "^\\*rustic-compilation\\*" rustic-compilation-mode + "^\\*ansi-term\\*$" term-mode + ("^\\*Warnings\\*$" . hide) + help-mode + helpful-mode)) + +(global-set-key (kbd "C-`") 'popper-toggle-latest) +(global-set-key (kbd "C-~") 'popper-cycle) +(global-set-key (kbd "C-M-`") 'popper-toggle-type) +(require 'popper-echo) +(popper-echo-mode t) + +(defun joe/get-popper-dir () + (with-current-buffer (current-buffer) + (if (or (> (window-width) 170) (eq olivetti-mode t)) + joe/popper-side-toggle + 'below))) + +;; TODO Prot We need to revisit this function and change the rules; I +;; just saw that Popper uses side-window for it's internal popup at +;; the bottom function. I prefer the way Popper does it for anything +;; that is going to display horizontally at the bottom. However for +;; side splits I much prefer the functionality we have here where if +;; there's a window on the right, then overtake it and then when I +;; close it, keep whatever window was there open. The issue with +;; side-windows is that they keep the two window splits in tact and +;; that's not what I want. Sort of like how Magit does it, that's what +;; I want to copy. But like I have it here, it should respect my +;; "popper side" variable so I can toggle whether it appears at the +;; bottom or above. +(defun joe/popper-display-func (buffer &optional _alist) + (cond + ((eq joe/popper-side-toggle 'below) + (popper-select-popup-at-bottom buffer _alist)) + ((when-let ((popup-buffer + (cl-find-if + #'popper-popup-p + (mapcar #'window-buffer (window-list))))) + (window--display-buffer + buffer (get-buffer-window popup-buffer) 'reuse + `((body-function . ,#'select-window))))) + + ((and (eq joe/popper-side-toggle 'right) + (window-in-direction 'left)) + (window--display-buffer + buffer (get-buffer-window (current-buffer)) 'reuse)) + + ((when-let ((right-window (window-in-direction 'right)) + ((eq joe/popper-side-toggle 'right))) + (window--display-buffer + buffer right-window 'reuse + `((body-function . ,#'select-window))))) + + ((and (not (window-in-direction 'right)) + (not (window-in-direction 'left))) + (display-buffer-in-direction + buffer + `((window-height . 0.45) + (window-width . 0.45) + (direction . right) + (body-function . ,#'select-window)))) + (t + (display-buffer-in-direction + buffer + `((window-height . 0.45) + (window-width . 0.45) + (direction . below) + (body-function . ,#'select-window)))))) + +(setq popper-display-function #'joe/popper-display-func) + +(popper-mode t) +#+end_src +*** COMMENT Tab-bar & Tab-line +#+begin_src emacs-lisp +(global-set-key (kbd "s-n") #'tab-line-switch-to-next-tab) +(global-set-key (kbd "s-p") #'tab-line-switch-to-prev-tab) + +#+end_src +*** COMMENT Scrolling +#+begin_src emacs-lisp +(require 'pixel-scroll) +(setq pixel-scroll-precision-large-scroll-height 10.0) +(setq pixel-scroll-precision-interpolation-factor 30) + + +(defun joe/pixel-scroll-lerp (amount direction) + (let ((half-height (* direction (/ (window-height) amount))) + (point-min-or-max (if (> direction 0) (point-min) (point-max)))) + (when (or (and (pos-visible-in-window-p (point-min)) + (< direction 0))) + (pixel-scroll-precision-interpolate (* 5 half-height))) + (pixel-scroll-precision-interpolate (* 5 half-height)))) + +(defun joe/smooth-scroll-half-page-down () + "Smooth scroll down" + (interactive) + (joe/pixel-scroll-lerp 1.5 -1)) + ;; (pixel-scroll-kbd-up)) + +(defun joe/smooth-scroll-half-page-up () + "Smooth scroll up" + (interactive) + (joe/pixel-scroll-lerp 1.5 1)) + +(defun joe/smooth-scroll-short-down () + "Smooth scroll down" + (interactive) + (joe/pixel-scroll-lerp 8 -1)) + +(defun joe/smooth-scroll-short-up () + "Smooth scroll down" + (interactive) + (joe/pixel-scroll-lerp 8 1)) + +;; scroll-up-command +(global-set-key (kbd "C-v") #'joe/smooth-scroll-half-page-down) +(global-set-key (kbd "M-v") #'joe/smooth-scroll-half-page-up) +(global-set-key (kbd "C-S-v") #'joe/smooth-scroll-short-down) +(global-set-key (kbd "M-S-v") #'joe/smooth-scroll-short-up) + +(defun joe/scroll-other-half-down () + (interactive) + (scroll-other-window 8)) +(defun joe/scroll-other-half-up () + (interactive) + (scroll-other-window -8)) + +(global-set-key (kbd "C-M-v") #'joe/scroll-other-half-down) +(global-set-key (kbd "C-M-S-V") #'joe/scroll-other-half-up) + +(require 'topspace) + +#+end_src +** Tabs/Workspaces +*** COMMENT Centaur Tabs +#+begin_src emacs-lisp +;; (require 'centaur-tabs) +(setq centaur-tabs-set-bar 'under) +(setq x-underline-at-descent-line t) +(setq centaur-tabs-set-close-button nil) +(setq centaur-tabs-set-icons t) +(setq centaur-tabs-show-navigation-buttons nil) +(setq centaur-tabs-set-close-button nil) +(setq centaur-tabs-set-modified-marker nil) +(setq centaur-tabs-show-new-tab-button nil) +(setq centaur-tabs-label-fixed-length 16) + +(defun joe/forward-tab-or-popup () + (interactive) + (if (popper-popup-p (current-buffer)) + (popper-cycle) + (centaur-tabs-forward-tab))) +(defun joe/backward-tab-or-popup () + (interactive) + (if (popper-popup-p (current-buffer)) + (popper-cycle) + (centaur-tabs-backward-tab))) + +;; (global-set-key (kbd "s-n") #'centaur-tabs-forward-tab) +;; (global-set-key (kbd "s-p") #'centaur-tabs-backward-tab) + +(global-set-key (kbd "s-n") #'joe/forward-tab-or-popup) +(global-set-key (kbd "s-p") #'joe/backward-tab-or-popup) + +(global-set-key (kbd "s-N") #'centaur-tabs-forward-group) +(global-set-key (kbd "s-P") #'centaur-tabs-backward-group) +(global-set-key (kbd "C-s-p") #'centaur-tabs-move-current-tab-to-left) +(global-set-key (kbd "C-s-n") #'centaur-tabs-move-current-tab-to-right) + +(dolist (mode '(dashboard-mode-hook)) + (add-hook mode 'centaur-tabs-local-mode)) + +(with-eval-after-load 'centaur-tabs + (defun joe/fix-centaur-tabs (THEME) + (centaur-tabs-mode -1) + (centaur-tabs-mode)) + + (advice-add 'consult-theme :after #'joe/fix-centaur-tabs) + (defun centaur-tabs-buffer-groups () + "`centaur-tabs-buffer-groups' control buffers' group rules. + + Group centaur-tabs with mode if buffer is derived from `eshell-mode' `emacs-lisp-mode' `dired-mode' `org-mode' `magit-mode'. + All buffer name start with * will group to \"Emacs\". + Other buffer group by `centaur-tabs-get-group-name' with project name." + (list + (cond + ((or (derived-mode-p 'comint-mode) + (derived-mode-p 'sql-interactive-mode) + (string-match "*HTTP" (buffer-name)) + (derived-mode-p 'compilation-mode)) + "REPLs") + ((or (and (string-equal "*" (substring (buffer-name) 0 1)) + (not (string-match "*Org Src" (buffer-name)))) + (memq major-mode '(magit-process-mode + magit-status-mode + magit-diff-mode + magit-log-mode + magit-file-mode + magit-blob-mode + magit-blame-mode))) + "*Buffers*") + (t + "Emacs"))))) + +(centaur-tabs-mode +1) +#+end_src +*** COMMENT iflipb +#+begin_src emacs-lisp +(global-set-key (kbd "s-n") #'iflipb-next-buffer) +(global-set-key (kbd "s-p") #'iflipb-previous-buffer) +(setq iflipb-permissive-flip-back t) +(setq iflipb-other-buffer-template " %s ") +(setq iflipb-current-buffer-template "<[%s]>") +(setq iflipb-buffer-list-function #'tabspaces--buffer-list) +#+end_src +*** COMMENT Tabspaces +#+begin_src emacs-lisp +(tabspaces-mode +1) + +;; Filter Buffers for Consult-Buffer +(with-eval-after-load 'consult + ;; hide full buffer list (still available with "b" prefix) + (consult-customize consult--source-buffer :hidden t :default nil) + ;; set consult-workspace buffer list + (defvar consult--source-workspace + (list :name "Workspace Buffers" + :narrow ?w + :history 'buffer-name-history + :category 'buffer + :state #'consult--buffer-state + :default t + :items (lambda () (consult--buffer-query + :predicate #'tabspaces--local-buffer-p + :sort 'visibility + :as #'buffer-name))) + + "Set workspace buffer list for consult-buffer.") + (add-to-list 'consult-buffer-sources 'consult--source-workspace)) + +#+end_src +*** COMMENT Tabs +#+begin_src emacs-lisp +;; (setq tab-bar-mode t) +;; (setq tab-bar-show nil) + +;; (global-set-key (kbd "M-1") '(lambda () (interactive) (tab-bar-select-tab 1))) +;; (global-set-key (kbd "M-2") '(lambda () (interactive) (tab-bar-select-tab 2))) +;; (global-set-key (kbd "M-3") '(lambda () (interactive) (tab-bar-select-tab 3))) +;; (global-set-key (kbd "M-4") '(lambda () (interactive) (tab-bar-select-tab 4))) +;; (global-set-key (kbd "M-5") '(lambda () (interactive) (tab-bar-select-tab 5))) +;; (global-set-key (kbd "M-6") '(lambda () (interactive) (tab-bar-select-tab 6))) +;; (global-set-key (kbd "M-7") '(lambda () (interactive) (tab-bar-select-tab 7))) +;; (global-set-key (kbd "M-8") '(lambda () (interactive) (tab-bar-select-tab 8))) +;; (global-set-key (kbd "M-9") '(lambda () (interactive) (tab-bar-select-tab 9))) + +;; (evil-global-set-key 'insert (kbd "M-1") '(lambda () (interactive) (tab-bar-select-tab 1))) +;; (evil-global-set-key 'insert (kbd "M-2") '(lambda () (interactive) (tab-bar-select-tab 2))) +;; (evil-global-set-key 'insert (kbd "M-3") '(lambda () (interactive) (tab-bar-select-tab 3))) +;; (evil-global-set-key 'insert (kbd "M-4") '(lambda () (interactive) (tab-bar-select-tab 4))) +;; (evil-global-set-key 'insert (kbd "M-5") '(lambda () (interactive) (tab-bar-select-tab 5))) +;; (evil-global-set-key 'insert (kbd "M-6") '(lambda () (interactive) (tab-bar-select-tab 6))) +;; (evil-global-set-key 'insert (kbd "M-7") '(lambda () (interactive) (tab-bar-select-tab 7))) +;; (evil-global-set-key 'insert (kbd "M-8") '(lambda () (interactive) (tab-bar-select-tab 8))) +;; (evil-global-set-key 'insert (kbd "M-9") '(lambda () (interactive) (tab-bar-select-tab 9))) + +;; (evil-global-set-key 'normal (kbd "M-1") '(lambda () (interactive) (tab-bar-select-tab 1))) +;; (evil-global-set-key 'normal (kbd "M-2") '(lambda () (interactive) (tab-bar-select-tab 2))) +;; (evil-global-set-key 'normal (kbd "M-3") '(lambda () (interactive) (tab-bar-select-tab 3))) +;; (evil-global-set-key 'normal (kbd "M-4") '(lambda () (interactive) (tab-bar-select-tab 4))) +;; (evil-global-set-key 'normal (kbd "M-5") '(lambda () (interactive) (tab-bar-select-tab 5))) +;; (evil-global-set-key 'normal (kbd "M-6") '(lambda () (interactive) (tab-bar-select-tab 6))) +;; (evil-global-set-key 'normal (kbd "M-7") '(lambda () (interactive) (tab-bar-select-tab 7))) +;; (evil-global-set-key 'normal (kbd "M-8") '(lambda () (interactive) (tab-bar-select-tab 8))) +;; (evil-global-set-key 'normal (kbd "M-9") '(lambda () (interactive) (tab-bar-select-tab 9))) + +#+end_src +** Projects +#+begin_src emacs-lisp +(with-eval-after-load 'project + (setq project-vc-ignores '("target/" "bin/" "obj/")) + (add-to-list 'project-switch-commands '(magit-project-status "Magit" ?m)) + (add-to-list 'project-vc-extra-root-markers ".dir-locals.el") + (setq frame-title-format "%b") + + (defun joe/project-root-override (dir) + (let ((proj-name (project-try-vc dir))) + (when (and proj-name + (not (frame-parameter (selected-frame) 'explicit-name))) + (progn + (set-frame-name (file-name-nondirectory (directory-file-name (nth 2 proj-name))))) + proj-name))) + +;; TODO: There's an issue with this and it's causing some weird nesting/recursion + ;; (add-hook 'project-find-functions #'joe/project-root-override) + + (define-key 'ctl-x-5-prefix "n" #'set-frame-name)) + +#+end_src +** VEMCO +*** Vertico +#+begin_src emacs-lisp +(require 'all-the-icons-completion) +;; (require '(vertico :files (:defaults "extensions/*") +;; :includes (vertico-indexed +;; vertico-repeat +;; vertico-directory)) + +(require 'vertico) +(vertico-mode) +;; (elpaca 'vertico-posframe) + +;; (define-key vertico-map (kbd "C-w") #'vertico-directory-delete-word) +;; (define-key vertico-map (kbd "C-r") #'vertico-repeat-) + +;; (vertico-posframe-mode t) +;; (vertico-indexed-mode) +;; (setq vertico-posframe-parameters +;; '((left-fringe . 100) +;; (right-fringe . 100))) + +;; (setq vertico-posframe-border-width 5) +;; (setq vertico-posframe-min-height 20) +(defun posframe-poshandler-slightly-below-top (info) + (cons (/ (- (plist-get info :parent-frame-width) + (plist-get info :posframe-width)) + 2) + 180)) + +;; (setq vertico-posframe-poshandler #'posframe-poshandler-frame-center) +(setq vertico-posframe-poshandler #'posframe-poshandler-slightly-below-top) + +(defun joe/consult-buffer-vertico-indexed (start-index) + (interactive) + (let ((vertico-count 12) + (vertico-posframe-width 110) + (vertico-posframe-height 20) + (vertico-group-format nil) + (vertico-indexed-start 1) + (vertico--index start-index) + (consult-buffer-sources '(beframe-consult-source))) + (consult-buffer))) + +(defun joe/consult-buffer-vertico-next () + (interactive) + (joe/consult-buffer-vertico-indexed 1)) +(defun joe/consult-buffer-vertico-last () + (interactive) + (joe/consult-buffer-vertico-indexed (1- (length (beframe-buffer-names))))) + +(global-set-key (kbd "s-n") #'joe/consult-buffer-vertico-next) +(global-set-key (kbd "s-p") #'joe/consult-buffer-vertico-last) + +(setq vertico-count 20 + vertico-resize nil + vertico-cycle t) +(setq vertico-posframe-width 130) +(setq vertico-posframe-height 30) +(setq vertico-posframe-parameters + '((child-frame-border-width . 5) + (left-fringe . 30) + (right-fringe . 30))) + +(require 'savehist) +(savehist-mode) +(add-hook 'minibuffer-setup-hook #'vertico-repeat-save) +(add-to-list 'savehist-additional-variables 'vertico-repeat-history) + +(define-key vertico-map (kbd "C-M-n") #'vertico-next-group) +(define-key vertico-map (kbd "s-p") #'vertico-previous) +(define-key vertico-map (kbd "s-n") #'vertico-next) +;; #' "C-M-p" #'vertico-previous-group) + + +;; (elpaca 'vertico-directory) +;; :bind (:map vertico-map +;; ("RET" . vertico-directory-enter) +;; ("DEL" . vertico-directory-delete-char) +;; ("M-DEL" . vertico-directory-delete-word)) +;; :hook (rfn-eshadow-update-overlay . vertico-directory-tidy)) + +#+end_src +*** Embark +#+begin_src emacs-lisp +(require 'embark) + +;; TODO Try using embark to kill this buffer +(defun prot-simple-kill-buffer-current (&optional arg) + "Kill current buffer. +With optional prefix ARG (\\[universal-argument]) delete the +buffer's window as well." + (interactive "P") + (let ((kill-buffer-query-functions nil)) + (if (and arg (not (one-window-p))) + (kill-buffer-and-window) + (kill-buffer)))) + +(defun prot-simple-kill-buffer (buffer) + "Kill current BUFFER. +When called interactively, prompt for BUFFER." + (interactive (list (read-buffer "Select buffer: "))) + (let ((kill-buffer-query-functions nil)) + (kill-buffer (or buffer (current-buffer))))) + +(setq embark-quit-after-action '((kill-buffer . nil))) + +;; TODO Add this to display-buffer-alist +;; ("\\*Embark Actions\\*" +;; (display-buffer-reuse-mode-window display-buffer-at-bottom) +;; (window-height . fit-window-to-buffer) +;; (window-parameters . ((no-other-window . t) +;; (mode-line-format . none)))) + +;; TODO Remove the which-key stuff because it seems to be breaking things +(defun embark-which-key-indicator () + "An embark indicator that displays keymaps using which-key. + The which-key help message will show the type and value of the + current target followed by an ellipsis if there are further + targets." + (lambda (&optional keymap targets prefix) + (if (null keymap) + (which-key--hide-popup-ignore-command) + (which-key--show-keymap + (if (eq (plist-get (car targets) :type) 'embark-become) + "Become" + (format "Act on %s '%s'%s" + (plist-get (car targets) :type) + (embark--truncate-target (plist-get (car targets) :target)) + (if (cdr targets) "…" ""))) + (if prefix + (pcase (lookup-key keymap prefix 'accept-default) + ((and (pred keymapp) km) km) + (_ (key-binding prefix 'accept-default))) + keymap) + nil nil t (lambda (binding) + (not (string-suffix-p "-argument" (cdr binding)))))))) + +(setq embark-indicators + '(embark-which-key-indicator + embark-highlight-indicator + embark-isearch-highlight-indicator)) + +(defun embark-hide-which-key-indicator (fn &rest args) + "Hide the which-key indicator immediately when using the completing-read prompter." + (which-key--hide-popup-ignore-command) + (let ((embark-indicators + (remq #'embark-which-key-indicator embark-indicators))) + (apply fn args))) + +(advice-add #'embark-completing-read-prompter + :around #'embark-hide-which-key-indicator) +(advice-remove #'embark-completing-read-prompter #'embark-hide-which-key-indicator) +#+end_src +*** Marginalia +#+begin_src emacs-lisp + (require 'marginalia) + (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)) + (setq marginalia-align 'right) + (setq marginalia-max-relative-age most-positive-fixnum) + (marginalia-mode) + (define-key minibuffer-local-map (kbd "M-A") #'marginalia-cycle) + (require 'all-the-icons-completion) + (all-the-icons-completion-mode) + (all-the-icons-completion-marginalia-setup) + + (add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup) + +#+end_src +*** Consult +#+begin_src emacs-lisp +(require 'embark-consult) + +(require 'consult) + +;; (require 'consult-lsp) + +(global-set-key (kbd "C-. C-l") 'consult-line) +(global-set-key (kbd "C-. C-i") 'consult-imenu) +(global-set-key (kbd "C-. C-t") 'consult-theme) +(global-set-key (kbd "C-. C-r") 'consult-recent-file) +(global-set-key (kbd "C-. C-y") 'consult-yank-from-kill-ring) + +#+end_src +*** Orderless + +#+begin_src emacs-lisp + + (require 'orderless) + (setq completion-styles '(orderless basic) + completion-category-overrides '((file (styles basic partial-completion)))) +#+end_src +** Dirvish/Dired +#+begin_src emacs-lisp +(require 'dirvish) +(with-eval-after-load 'dirvish + (dirvish-override-dired-mode) + (setq delete-by-moving-to-trash t) + (setq dired-dwim-target t) + (setq dirvish-reuse-session nil) + + ;; (add-hook 'dired-mode-hook 'centaur-tabs-local-mode) + + (dirvish-define-preview exa (file) + "Use `exa' to generate directory preview." + :require ("exa") ; tell Dirvish to check if we have the executable + (when (file-directory-p file) ; we only interest in directories here + `(shell . ("exa" "--icons" "--color=always" "--no-user" "-al" "--group-directories-first" ,file)))) + (add-to-list 'dirvish-preview-dispatchers 'exa) + + (setq dired-listing-switches "-l --almost-all --human-readable --time-style=long-iso --group-directories-first --no-group") + (setq dirvish-preview-dispatchers (cl-substitute 'pdf-preface 'pdf dirvish-preview-dispatchers)) + (setq dirvish-attributes '(all-the-icons file-size collapse subtree-state)) + + (defun joe/dirvish-find-directory (dir) + (interactive "FDirvish Directory:") + (dirvish-dwim dir)) + + (setq dirvish-quick-access-entries + '(("h" "~/" "Home") + ("d" "~/Downloads/" "Downloads") + ("D" "~/Documents/" "Documents") + ("b" "~/Documents/Books/" "Books") + ("p" "~/Development/" "Dev") + ("t" "~/TYCS/" "Teachyourselfcs") + ("r" "~/Repositories" "Repos") + ("B" "~/pCloudDrive/" "pCloud"))) + + (when (boundp 'evil-mode) + (evil-define-key 'normal dirvish-mode-map + (kbd "C-c f") #'dirvish-fd + (kbd "a") #'dirvish-quick-access + (kbd ".") #'dired-create-empty-file + (kbd "f") #'dirvish-file-info-menu + (kbd "y") #'dirvish-yank-menu + (kbd "h") #'dired-up-directory + (kbd "l") #'dired-find-file + (kbd "s") #'dirvish-quicksort + (kbd "v") #'dirvish-vc-menu + (kbd "q") #'dirvish-quit + (kbd "L") #'dirvish-history-go-forward + (kbd "H") #'dirvish-history-go-backward + (kbd "o") #'dired-open-file + (kbd "TAB") #'dirvish-subtree-toggle + (kbd "M-n") #'dirvish-narrow + (kbd "M-l") #'dirvish-ls-switches-menu + (kbd "M-m") #'dirvish-mark-menu + (kbd "M-t") #'dirvish-layout-toggle + (kbd "M-s") #'dirvish-setup-menu + (kbd "M-e") #'dirvish-emerge-menu + (kbd "M-j") #'dirvish-fd-jump))) + +;; There's an issue with the keybinding precedence so we need to run this since +;; joe/evil-space-mode-map takes precedence above all else and '-' doesn't do +;; what it should +(defun joe/dirvish-up-dwim () + (interactive) + (if (eq major-mode 'dired-mode) + (dired-up-directory) + (dirvish-dwim))) + +(when (boundp 'evil-mode) + (evil-define-key 'normal joe/evil-space-mode-map (kbd "_") #'project-dired) + (evil-define-key 'normal joe/evil-space-mode-map (kbd "-") #'joe/dirvish-up-dwim)) +(global-set-key (kbd "C-x d") #'dirvish-dwim) +(global-set-key (kbd "C-x C-d") #'joe/dirvish-find-directory) + +(defun dired-open-file () + "In dired, open the file named on this line." + (interactive) + (let* ((file (dired-get-filename nil t))) + (message "Opening %s..." file) + (call-process "xdg-open" nil 0 nil file) + (message "Opening %s done" file))) + +#+end_src +** Email +#+begin_src emacs-lisp +(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e/") +(require 'mu4e) + +(evil-global-set-key 'normal (kbd "SPC mm") #'mu4e) + +;; Attach files to a message composition buffer by going into `dired' +;; and doing C-c C-m C-a (M-x `gnus-dired-attach'). +(require 'gnus-dired) ; does not require `gnus' +(add-hook 'dired-mode-hook #'gnus-dired-mode) +(add-hook 'mu4e-main-mode-hook 'olivetti-mode) + +(add-to-list 'auto-mode-alist '("authinfo" . authinfo-mode)) + +(setq mu4e-get-mail-command "parallel mbsync -V \"-c ~/.config/mbsync/config\" ::: ferano.io.inbox gmail.allmail") + +;;; Sending email (SMTP) +(require 'smtpmail) +(setq smtpmail-default-smtp-server "mail.gandi.net" + smtpmail-smtp-server "mail.gandi.net" + smtpmail-stream-type 'ssl + smtpmail-smtp-service 465 + smtpmail-queue-mail nil) + +(require 'sendmail) +(setq send-mail-function 'smtpmail-send-it) + +(setq message-kill-buffer-on-exit nil) + +(setq mu4e-completing-read-function 'completing-read) +(setq mu4e-sent-messages-behavior 'sent) +(setq mu4e-context-policy 'pick-first) +(setq mu4e-compose-context-policy 'ask) +(setq mu4e-view-auto-mark-as-read nil) + +(setq message-kill-buffer-on-exit t) + +(require 'age) +(setq age-default-identity '("~/.local/credentials/personal")) +(setq age-default-recipient '("~/.local/credentials/personal.pub")) + +(setq auth-source-do-cache nil) + +(defun joe/mu4e-auth-get-field (host prop) + "Find PROP in `auth-sources' for HOST entry." + (when-let ((source (auth-source-search :host host))) + (if (eq prop :secret) + (funcall (plist-get (car source) prop)) + (plist-get (flatten-list source) prop)))) + +(setq auth-sources '("~/.local/credentials/authinfo.age")) + +(age-file-enable) +(age-encryption-mode +1) +(setq mu4e-bookmarks nil) +(setq mu4e-contexts + `(,(make-mu4e-context + :name "Ferano.io" + :enter-func (lambda () (mu4e-message "Entering ferano.io")) + :leave-func (lambda () (mu4e-message "Leaving ferano.io")) + :match-func (lambda (msg) + (when msg + (mu4e-message-contact-field-matches + msg :to (joe/mu4e-auth-get-field "mail.gandi.net" :user)))) + :vars `((user-mail-address . ,(joe/mu4e-auth-get-field "mail.gandi.net" :user)) + (user-full-name . "Joseph Ferano") + (mu4e-drafts-folder . "/ferano.io/Drafts/") + (mu4e-trash-folder . "/ferano.io/Trash/") + (mu4e-sent-folder . "/ferano.io/Sent/"))) + ,(make-mu4e-context + :name "Gmail" + :enter-func (lambda () (mu4e-message "Entering gmail")) + :leave-func (lambda () (mu4e-message "Leaving gmail")) + :match-func (lambda (msg) + (when msg + (mu4e-message-contact-field-matches + msg :to (joe/mu4e-auth-get-field "mail.gmail.com" :user)))) + :vars `((user-mail-address . ,(joe/mu4e-auth-get-field "mail.gmail.com" :user)) + (user-full-name . "Joseph Ferano") + (mu4e-drafts-folder . "/gmail/[Gmail]/Drafts/") + (mu4e-trash-folder . "/gmail/[Gmail]/Trash/") + (mu4e-sent-folder . "/gmail/[Gmail]/Sent Mail/"))))) + +(setq mu4e-maildir-shortcuts + '((:maildir "/ferano.io/Inbox" :key ?f) + (:maildir "/gmail/[Gmail]/All Mail" :key ?g))) + +;; (:name "Ferano.io Unread" :query "m:/ferano.io/Inbox AND g:unread" :key ?u))) +#+end_src + +Fold threads. This is a gist provided by Rougier [[https://gist.github.com/rougier/98e83fb50e19fb73fe34a7ecc5fc1ccc][here]]. His other package is +[[https://github.com/rougier/mu4e-thread-folding][mu4e-thread-folding]] but they work slightly differently. Code for the latter will +be kept here commented out in case we want to try it again. + +#+begin_src emacs-lisp + +(load-file "/home/joe/Dotfiles/.config/emacs/elisp/mu4e-fast-folding.el") + +(evil-define-key 'normal mu4e-headers-mode-map (kbd "TAB") + #'mu4e-fast-folding-thread-toggle) + +(evil-define-key 'normal mu4e-headers-mode-map (kbd "") + #'mu4e-fast-folding-thread-toggle-all) + +;; (load-file "/home/joe/Dotfiles/.config/emacs/elisp/mu4e-thread-folding.el") +;; (require 'mu4e-fast-folding) +;; (add-to-list 'mu4e-header-info-custom +;; '(:empty . (:name "Empty" +;; :shortname "" +;; :function (lambda (msg) " ")))) +;; (setq mu4e-headers-fields '((:empty . 2) +;; (:human-date . 12) +;; (:flags . 6) +;; (:mailing-list . 10) +;; (:from . 22) +;; (:subject . nil))) +;; (evil-define-key 'normal mu4e-headers-mode-map (kbd "TAB") +;; #'mu4e-headers-fold-at-point) + +;; (evil-define-key 'normal mu4e-headers-mode-map (kbd "") +;; #'mu4e-headers-unfold-at-point) + +;; (mu4e-thread-folding-mode +1) +#+end_src +** Avy + +#+begin_src emacs-lisp +(require 'avy) +(setq avy-case-fold-search nil) +(setq avy-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l ?q ?w ?e ?r ?u ?i ?o ?p ?z ?x ?c ?v ?n ?m)) +(define-key global-map (kbd "C-;") 'avy-goto-char) ;; I use this most frequently +;; (define-key global-map (kbd "C-'") 'avy-goto-line) ;; Consistent with ivy-avy +(define-key global-map (kbd "M-g c") 'avy-goto-char) +(define-key global-map (kbd "M-g e") 'avy-goto-word-0) ;; lots of candidates +(define-key global-map (kbd "M-g g") 'avy-goto-line) ;; digits behave like goto-line +(define-key global-map (kbd "M-g w") 'avy-goto-word-1) ;; first character of the word +(define-key global-map (kbd "M-g P") 'avy-pop-mark) +#+end_src +** Helpful +#+begin_src emacs-lisp +(require 'helpful) +(global-set-key (kbd "C-h f") #'helpful-callable) +(global-set-key (kbd "C-h v") #'helpful-variable) +(global-set-key (kbd "C-h k") #'helpful-key) +(global-set-key (kbd "C-h C-d") #'helpful-at-point) +(global-set-key (kbd "C-h F") #'helpful-function) +(global-set-key (kbd "C-h C") #'helpful-command) +#+end_src +** Terminals/Shells +#+begin_src emacs-lisp + (require 'vterm) + (setq vterm-shell "/bin/fish") + (setq vterm-timer-delay 0.01) + (setq vterm-buffer-name-string "VTerm - %s") + (setq vterm-max-scrollback 100000) + (setq vterm-kill-buffer-on-exit t) + + (defun joe/close-popup-buffer (vterm-buf event-msg) + (unless (or (eq popper-popup-status nil) + (eq popper-popup-status 'raised)) + (popper-close-latest))) + + (setq vterm-exit-functions '(joe/close-popup-buffer)) + + (defun joe/vterm-here () + (interactive) + (let ((vterm-buf (vterm--internal #'switch-to-buffer))) + (with-current-buffer vterm-buf + (setq popper-popup-status 'raised)))) + + (global-set-key (kbd "C-c t") #'vterm) + (global-set-key (kbd "C-c T") #'joe/vterm-here) + ;; (setq explicit-shell-file-name "~/Development/fell/fell") + (add-hook 'shell-mode (lambda () (setq-local global-hl-line-mode nil))) + (setq shell-kill-buffer-on-exit t) + + (add-hook 'vterm-mode-hook + (lambda () + (define-key vterm-mode-map (kbd "C-c C-x") #'vterm-send-C-x) + (when (boundp 'evil-mode) + (evil-define-key 'insert vterm-mode-map (kbd "C-w") #'vterm-send-C-w) + (evil-define-key 'insert vterm-mode-map (kbd "") #'vterm-send-delete)) + (setq-local global-hl-line-mode nil))) +#+end_src + +VTerm is loading TRAMP along with it which slows down init time noticeably so call this after +startup. Reason we have to call this is so the vterm fucntion can call `vterm--internal`. + +#+begin_src emacs-lisp :tangle no +;; (add-hook 'emacs-startup-hook (lambda () (require 'vterm))) +#+end_src +** Undo Fu +#+begin_src emacs-lisp +(require 'undo-fu) + (undo-fu-session-global-mode +1) + (setq undo-limit 6710886400) ;; 64mb. + (setq undo-strong-limit 100663296) ;; 96mb. + (setq undo-outer-limit 1006632960) ;; 960mb. + +(require 'undo-fu-session) + (setq undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'")) +(require 'vundo) +#+end_src +** Which Key + +#+begin_src emacs-lisp +(require 'which-key) + (setq which-key-idle-delay 0.3) + (which-key-mode) + (when (boundp 'evil-mode) + (which-key-add-keymap-based-replacements evil-normal-state-map + "SPC f" '("Files") + "SPC b" '("Buffers") + "SPC B" '("Bookmarks") + "SPC c" '("Consult") + "SPC d" '("Dired") + "SPC g" '("Git") + "SPC m" '("Make") + "SPC t" '("Tabs") + "SPC p" '("Packages") + "SPC s" '("Shell (vterm)") + "SPC h" '("Help"))) +#+end_src +** IDE Features +*** REPLs +#+begin_src emacs-lisp + +(when (boundp 'evil-mode) + (evil-define-key 'insert comint-mode-map (kbd "C-n") 'comint-next-input) + (evil-define-key 'insert comint-mode-map (kbd "C-p") 'comint-previous-input)) +#+end_src +*** Mono-complete +#+begin_src emacs-lisp +;; (evil-global-set-key 'insert (kbd "C-f") #'mono-complete-expand) +(require 'mono-complete) +(evil-global-set-key 'insert (kbd "M-/") #'mono-complete-expand-or-fallback) +(setq mono-complete-backends (list 'dabbrev 'filesystem)) +(setq mono-complete-backends (list 'capf 'dabbrev 'filesystem)) + +(setq mono-complete-backend-capf-complete-fn #'eglot-completion-at-point) +(setq mono-complete-preview-delay 0.1) + +;; (add-to-list 'face-remapping-alist '(mono-complete-preview-face . shadow)) + +(set-face-attribute 'mono-complete-preview-face nil + :foreground 'unspecified + :background 'unspecified + :inherit 'shadow) + +(mono-complete-mode +1) +#+end_src +*** Eldoc +#+begin_src emacs-lisp +(evil-global-set-key 'normal (kbd "K") #'eldoc) +(global-eldoc-mode -1) + +#+end_src +*** Eglot +#+begin_src emacs-lisp +(with-eval-after-load 'eglot + (global-eldoc-mode -1) + (flymake-mode -1) + (when (boundp 'evil-mode) + ;; (evil-global-set-key 'normal (kbd "M-d") #'lsp-describe-thing-at-point) + (evil-global-set-key 'normal (kbd "SPC li") 'eglot-inlay-hints-mode) + (evil-global-set-key 'normal (kbd "cs") 'consult-eglot-symbols))) +#+end_src +*** COMMENT LSP +#+begin_src emacs-lisp +(require 'lsp-mode) + (setq lsp-enable-which-key-integration t) + (setq lsp-keymap-prefix "C-c c") + + ;; (setq lsp-ui-peek-always-show t) + ;; (setq lsp-ui-doc-enable t) + ;; TODO: Disable lsp sideline + (setq lsp-headerline-breadcrumb-enable nil) + (setq lsp-eldoc-enable-hover t) + (setq max-mini-window-height 0.25) + (setq lsp-eldoc-enable-hover t) + (setq lsp-ui-doc-enable nil) + (setq eldoc-echo-area-use-multiline-p 'truncate-sym-name-if-fit) + (setq eldoc-idle-delay 0) + (setq lsp-idle-delay 0.2) + + ;; Signatures + (setq lsp-signature-doc-lines t) + (setq lsp-signature-render-documentation nil) + (setq lsp-eldoc-render-all nil) + +;; All this changes because we are using eglot now + (when (boundp 'evil-mode) + (evil-global-set-key 'normal (kbd "M-d") #'lsp-describe-thing-at-point) + (evil-global-set-key 'normal (kbd "lh") 'lsp-headerline-breadcrumb-mode) + (evil-global-set-key 'normal (kbd "SPC li") 'lsp-rust-analyzer-inlay-hints-mode) + (evil-global-set-key 'normal (kbd "cs") 'consult-lsp-symbols) + (evil-global-set-key 'normal (kbd "cf") 'consult-lsp-file-symbols)) + + ;; This function allows us to extract Rust's true function signature + (cl-defmethod lsp-clients-extract-signature-on-hover (contents (_server-id (eql rust-analyzer))) + (-let* (((&hash "value") contents) + (groups (--partition-by (s-blank? it) (s-lines (s-trim value)))) + (sig_group (if (s-equals? "```rust" (car (-third-item groups))) + (-third-item groups) + (car groups))) + (sig (--> sig_group + (--drop-while (s-equals? "```rust" it) it) + (--take-while (not (s-equals? "```" it)) it) + (--map (s-trim it) it) + (s-join " " it)))) + (lsp--render-element (concat "```rust\n" sig "\n```")))) + +(require 'lsp-ui) + +#+end_src +*** COMMENT Flycheck + +#+begin_src emacs-lisp +(require 'flycheck) +;; TODO Add wrapping to these functions +(when (boundp 'evil-mode) + (evil-global-set-key 'normal (kbd "M-e") #'flycheck-next-error) + (evil-global-set-key 'normal (kbd "M-E") #'flycheck-previous-error) + (evil-global-set-key 'normal (kbd "ee") 'flycheck-mode) + (evil-global-set-key 'normal (kbd "el") #'flycheck-list-errors) + (evil-global-set-key 'normal (kbd "ce") #'consult-lsp-diagnostics)) +#+end_src +*** Compilation +#+begin_src emacs-lisp +(setq compilation-auto-jump-to-first-error t) + +(defun joe/save-then-recompile () + "Save the buffer before recompiling" + (interactive) + (when (buffer-file-name) + (save-buffer)) + (recompile)) + +(defun joe/save-if-file-ignore-args (&rest _) + "Save the buffer before recompiling" + (interactive) + (joe/save-if-file)) + +(defun joe/save-if-file () + "Save buffer only if it has a backing file" + (interactive) + (when (buffer-file-name) + (save-buffer))) + +(add-hook 'evil-insert-state-exit-hook #'joe/save-if-file) +;; (add-hook 'after-change-functions #'joe/save-if-file-ignore-args) +;; (define-key global-map (kbd "C-x C-s) #'save-buffer) +(define-key global-map (kbd "") #'joe/save-then-recompile) +(define-key global-map (kbd "") #'compile) + +(defun joe/colorize-compilation-buffer () + (ansi-color-apply-on-region compilation-filter-start (point))) +(add-hook 'compilation-filter-hook 'joe/colorize-compilation-buffer) + +(defun joe/close-compilation-if-no-warn-err (buffer string) + "Bury a compilation buffer if succeeded without warnings " + (if (and + (string-match "compilation" (buffer-name buffer)) + (string-match "finished" string) + (not + (with-current-buffer (current-buffer) + (search-forward "warning" nil t)))) + (run-with-timer 1.5 nil + (lambda () + (and (eq (point) 1) + (string-match "compilation" (buffer-name (current-buffer))) + (popper-close-latest)))))) +(add-hook 'compilation-finish-functions 'joe/close-compilation-if-no-warn-err) +#+end_src +** Debugging +*** COMMENT DAP +#+begin_src emacs-lisp +(require 'dap-mode) +;; (setq dap-auto-configure-features '(locals breakpoints expressions tooltip)) + +(require 'dap-cpptools) +(dap-cpptools-setup) +(add-hook 'dap-stopped-hook + (lambda (arg) (call-interactively #'dap-hydra))) + +(setq dap-cpptools-extension-version "1.12.1") + +(setq dap-default-terminal-kind "integrated") +(dap-auto-configure-mode +1) +(dap-register-debug-template + "Rust::CppTools Run Configuration" + (list :type "cppdbg" + :request "launch" + :name "Rust::Run" + :MIMode "gdb" + :miDebuggerPath "rust-gdb" + :environment [] + :program "${workspaceFolder}/target/debug/kanban-tui" + :cwd "${workspaceFolder}" + :console "external" + :dap-compilation "cargo build" + :dap-compilation-dir "${workspaceFolder}")) +#+end_src +** Languages +*** Python +#+begin_src emacs-lisp +(require 'elpy) + +(define-key inferior-python-mode-map (kbd "C-n") #'comint-next-input) +(define-key inferior-python-mode-map (kbd "C-p") #'comint-previous-input) +#+end_src> +*** Rust +#+begin_src emacs-lisp +(require 'rustic) +(require 'ob-rust) +;; Org-Babel +;; Disabling until we figure out how to get it working +;; (elpaca 'parsec) ;; Required by evcxr-mode + +;; (elpaca +;; '(evcxr +;; :type git +;; :host github +;; :repo "serialdev/evcxr-mode")) + +(add-hook 'rust-mode-hook (lambda () (electric-pair-local-mode))) + +(add-hook 'rust-mode-hook + (lambda () + (evcxr-minor-mode) + (electric-pair-local-mode))) + +(with-eval-after-load 'rustic + ;; Don't autostart + (setq rustic-lsp-setup-p nil) + ;; (define-key rustic-mode-map (kbd "") #'joe/save-then-recompile) + + (setq lsp-rust-analyzer-server-display-inlay-hints t) + (setq lsp-rust-analyzer-display-lifetime-elision-hints-enable "always") + (setq lsp-rust-analyzer-display-chaining-hints t) + (setq lsp-rust-analyzer-display-lifetime-elision-hints-use-parameter-names t) + (setq lsp-rust-analyzer-display-closure-return-type-hints t) + (setq lsp-rust-analyzer-display-parameter-hints t) + (setq lsp-rust-analyzer-display-reborrow-hints t) + (setq lsp-rust-analyzer-cargo-watch-command "clippy")) +#+end_src +*** Elisp +#+begin_src emacs-lisp +(global-set-key (kbd "C-x C-r") 'eval-region) +(evil-define-key 'insert emacs-lisp-mode-map (kbd "C-j") 'eval-print-last-sexp) +#+end_src +*** Web +#+begin_src emacs-lisp +(require 'typescript-mode) +(setq typescript-indent-level 2) +#+end_src +*** SQL +#+begin_src emacs-lisp +(defun joe/mark-sql-defun () + "Mark the current SQL function definition." + (interactive) + (let ((beg (save-excursion + (re-search-backward "^create or replace function [^(]+" nil t) + (match-end 0))) + (end (save-excursion + (re-search-forward "\\(language\\)" nil t) + (line-end-position)))) + (when (and beg end) + (goto-char beg) + (set-mark end))) + (evil-visual-line) + (evil-visual-line)) + +(defun sql-send-pg-function () + "Send the current PGSQL function to sql interactive." + (interactive) + (let ((beg (save-excursion + (re-search-backward "^create or replace function [^(]+" nil t) + (line-beginning-position))) + (end (save-excursion + (re-search-forward "\\(language\\)" nil t) + (line-end-position)))) + (save-excursion + (when (and beg end) + (goto-char beg) + (set-mark end)) + (sql-send-region beg end) + (deactivate-mark)))) + +;; This is required so that .dir-locals that read env files for credentials works +(require 'dotenv) +(defun joe/sql-mode-hook () + (define-key sql-mode-map (kbd "C-M-h") #'joe/mark-sql-defun) + (define-key sql-mode-map (kbd "C-M-x") #'sql-send-pg-function) + (global-set-key (kbd "") #'sql-connect)) + +(add-hook 'sql-mode-hook #'joe/sql-mode-hook) + +(defun joe/sql-save-history-hook () + (let ((lval 'sql-input-ring-file-name) + (rval 'sql-product)) + (if (symbol-value rval) + (let ((filename + (concat user-emacs-directory "sql/" + (symbol-name (symbol-value rval)) + "-history.sql"))) + (set (make-local-variable lval) filename)) + (error + (format "SQL history will not be saved because %s is nil" + (symbol-name rval)))))) + +(add-hook 'sql-interactive-mode-hook 'joe/sql-save-history-hook) + +(defun joe/sql-login-hook () + "Custom SQL log-in behaviours. See `sql-login-hook'." + ;; n.b. If you are looking for a response and need to parse the + ;; response, use `sql-redirect-value' instead of `comint-send-string'. + (when (eq sql-product 'postgres) + (let ((proc (get-buffer-process (current-buffer)))) + ;; Output each query before executing it. (n.b. this also avoids + ;; the psql prompt breaking the alignment of query results.) + (comint-send-string proc "\\set ECHO queries\n")))) + +(add-hook 'sql-login-hook 'joe/sql-login-hook) +#+end_src +*** C + +Design some basic functions for compiling. There's also a hook to close the popper window if there +are no warnings or errors. It will check if we are still in the compilation buffer as well as +whether the point hasn't been moved. This way, if I switched to another popper buffer, like vterm, +it doesn't close it. + +#+begin_src emacs-lisp +(require 'disaster) +(defun joe/c-mode-hook () + (local-set-key (kbd "C-x c r") (defun joe/make-run () (interactive) (compile "make run"))) + (local-set-key (kbd "C-x c c") (defun joe/make () (interactive) (compile "make"))) + (electric-pair-local-mode t) + (c-toggle-comment-style -1)) +(add-hook 'c-mode-hook #'joe/c-mode-hook) +#+end_src +*** COMMENT Haskell +#+begin_src emacs-lisp + (require 'haskell-mode) + (setq haskell-interactive-popup-errors nil) + (when (boundp 'evil-mode) + + (evil-define-key 'insert haskell-interactive-mode-map (kbd "C-n") #'haskell-interactive-mode-history-next) + (evil-define-key 'insert haskell-interactive-mode-map (kbd "C-p") #'haskell-interactive-mode-history-previous)) + +#+end_src +*** COMMENT Clojure +#+begin_src emacs-lisp +(require 'clojure-mode) +(require 'cider) +(setq cider-show-error-buffer 'only-in-repl) +#+end_src +*** COMMENT OCaml +#+begin_src emacs-lisp +(require 'tuareg) +(require 'dune) +(require 'utop) +(require 'merlin) +(require 'merlin-eldoc) +;; Might be worth checking out, depeding on whether we stick with flycheck or not +;; (elpaca 'flycheck-ocaml) +;; Also check this out, see if it adds anything +;; (require 'ocp-indent) + +(defun opam-env () + "Load the opam env to get the PATH variables so everything works" + (interactive nil) + (dolist (var + (car (read-from-string + (shell-command-to-string "opam config env --sexp")))) + (setenv (car var) (cadr var)))) +(setq opam-share + (substring (shell-command-to-string + "opam config var share 2> /dev/null") 0 -1)) +(add-to-list 'load-path (expand-file-name "emacs/site-lisp" opam-share)) +#+end_src + +We won't use the LSP server but rather directly talk to Merlin, since I guess LSP just wraps Merlin +and there's no need for a middle-man when it's already been implemented. + +#+begin_src emacs-lisp + +;; (require 'utop) +;; Use the opam installed utop +(setq utop-command "opam exec -- utop -emacs") + +(let ((opam-share (ignore-errors (car (process-lines "opam" "var" "share"))))) + (when (and opam-share (file-directory-p opam-share)) + ;; Register Merlin + (add-to-list 'load-path (expand-file-name "emacs/site-lisp" opam-share)) + (autoload 'merlin-mode "merlin" nil t nil) + ;; Automatically start it in OCaml buffers + (add-hook 'tuareg-mode-hook 'merlin-mode t) + (add-hook 'caml-mode-hook 'merlin-mode t) + ;; Use opam switch to lookup ocamlmerlin binary + (setq merlin-command 'opam))) +#+end_src +*** COMMENT FSharp +#+begin_src emacs-lisp +(require 'fsharp-mode) +;; (elpaca 'eglot-fsharp) + +#+end_src +*** COMMENT Go + +#+begin_src emacs-lisp +(require 'go-mode) +;; (elpaca 'go-imports) +#+end_src +*** Other +#+begin_src emacs-lisp +(require 'json-mode) +(require 'markdown-mode) +#+end_src +** Org Mode + +#+begin_src emacs-lisp + (require 'org-bullets) + + (defun joe/org-init () + (setq org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE" "BACKLOG"))) + (setq org-agenda-files '("~/todo.org")) + + (org-babel-do-load-languages + 'org-babel-load-languages + '((emacs-lisp . t) + (makefile . t) + (ocaml . t) + (python . t) + (C . t) + (haskell . t) + ;; (rust . t) + (shell . t))) + + (require 'org-tempo) + (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) + (add-to-list 'org-structure-template-alist '("ml" . "src ocaml")) + (add-to-list 'org-structure-template-alist '("rs" . "src rust")) + (add-to-list 'org-structure-template-alist '("py" . "src python")) + (add-to-list 'org-structure-template-alist '("hs" . "src haskell")) + (add-to-list 'org-structure-template-alist '("sh" . "src shell")) + (add-to-list 'org-structure-template-alist '("cc" . "src C :includes stdio.h stdlib.h")) + (setq org-edit-src-content-indentation 0)) + (with-eval-after-load 'org (joe/org-init)) + + (setq org-blank-before-new-entry + '((heading . nil) + (plain-list-item . nil))) + (setq org-cycle-separator-lines 1) + (setq org-hide-emphasis-markers t) + (setq org-src-window-setup 'current-window) + + (defun joe/org-hook () + (local-set-key (kbd "C-. C-i") 'consult-org-heading) + (org-bullets-mode) + (org-indent-mode)) + (add-hook 'org-mode-hook 'joe/org-hook) + + (require 'org-kanban) +#+end_src +** Magit + +The best git porcelain/client I've ever used. Also kill stray magit buffers left over as explained [[https://manueluberti.eu/2018/02/17/magit-bury-buffer.html][here]] + +#+begin_src emacs-lisp +(require 'magit) + +(defun joe/magit-kill-buffers (param) + "Restore window configuration and kill all Magit buffers." + (let ((buffers (magit-mode-get-buffers))) + (magit-restore-window-configuration) + (mapc #'kill-buffer buffers))) + +(when (boundp 'evil-mode) +(add-hook 'with-editor-mode-hook 'evil-insert-state)) + +(setq magit-bury-buffer-function #'joe/magit-kill-buffers) +(setq magit-clone-set-remote.pushDefault t) +(setq magit-clone-default-directory "~/Development/") +;; (define-key magit-mode-map "h" 'backward-char) +;; (define-key magit-mode-map "l" 'backward-char) + +#+end_src +** Restclient + +#+begin_src emacs-lisp +(require 'restclient) + +(add-to-list 'auto-mode-alist '("\\.restclient\\'" . restclient-mode)) + +(with-eval-after-load 'restclient + (define-key restclient-mode-map (kbd "C-c C-c") #'restclient-http-send-current-stay-in-window) + (define-key restclient-mode-map (kbd "C-c C-v") #'restclient-http-send-current)) + +#+end_src + +** Initial Buffer + +#+begin_src emacs-lisp +(load-file "/home/joe/Dotfiles/.config/emacs/elisp/welcome.el") +#+end_src + +* COMMENT Local variables +;; Local Variables: +;; eval: (olivetti-mode t) +;; eval: (add-hook 'after-save-hook '(lambda () (org-babel-tangle)) nil t) +;; End: diff --git a/.config/fish/completions/exercism.fish b/.config/fish/completions/exercism.fish new file mode 100644 index 0000000..dc20fdc --- /dev/null +++ b/.config/fish/completions/exercism.fish @@ -0,0 +1,54 @@ +# Configure +complete -f -c exercism -n "__fish_use_subcommand" -a "configure" -d "Writes config values to a JSON file." +complete -f -c exercism -n "__fish_seen_subcommand_from configure" -s t -l token -d "Set token" +complete -f -c exercism -n "__fish_seen_subcommand_from configure" -s w -l workspace -d "Set workspace" +complete -f -c exercism -n "__fish_seen_subcommand_from configure" -s a -l api -d "set API base url" +complete -f -c exercism -n "__fish_seen_subcommand_from configure" -s s -l show -d "show settings" + +# Download +complete -f -c exercism -n "__fish_use_subcommand" -a "download" -d "Downloads and saves a specified submission into the local system" +complete -f -c exercism -n "__fish_seen_subcommand_from download" -s e -l exercise -d "the exercise slug" +complete -f -c exercism -n "__fish_seen_subcommand_from download" -s h -l help -d "help for download" +complete -f -c exercism -n "__fish_seen_subcommand_from download" -s T -l team -d "the team slug" +complete -f -c exercism -n "__fish_seen_subcommand_from download" -s t -l track -d "the track ID" +complete -f -c exercism -n "__fish_seen_subcommand_from download" -s u -l uuid -d "the solution UUID" + +# Help +complete -f -c exercism -n "__fish_use_subcommand" -a "help" -d "Shows a list of commands or help for one command" +complete -f -c exercism -n "__fish_seen_subcommand_from help" -a "configure download help open submit troubleshoot upgrade version workspace" + +# Open +complete -f -c exercism -n "__fish_use_subcommand" -a "open" -d "Opens a browser to exercism.io for the specified submission." +complete -f -c exercism -n "__fish_seen_subcommand_from open" -s h -l help -d "help for open" + +# Submit +complete -f -c exercism -n "__fish_use_subcommand" -a "submit" -d "Submits a new iteration to a problem on exercism.io." +complete -f -c exercism -n "__fish_seen_subcommand_from submit" -s h -l help -d "help for submit" + +# Troubleshoot +complete -f -c exercism -n "__fish_use_subcommand" -a "troubleshoot" -d "Outputs useful debug information." +complete -f -c exercism -n "__fish_seen_subcommand_from troubleshoot" -s f -l full-api-key -d "display full API key (censored by default)" +complete -f -c exercism -n "__fish_seen_subcommand_from troubleshoot" -s h -l help -d "help for troubleshoot" + +# Upgrade +complete -f -c exercism -n "__fish_use_subcommand" -a "upgrade" -d "Upgrades to the latest available version." +complete -f -c exercism -n "__fish_seen_subcommand_from help" -s h -l help -d "help for help" + +# Version +complete -f -c exercism -n "__fish_use_subcommand" -a "version" -d "Outputs version information." +complete -f -c exercism -n "__fish_seen_subcommand_from version" -s l -l latest -d "check latest available version" +complete -f -c exercism -n "__fish_seen_subcommand_from version" -s h -l help -d "help for version" + +# Workspace +complete -f -c exercism -n "__fish_use_subcommand" -a "workspace" -d "Outputs the root directory for Exercism exercises." +complete -f -c exercism -n "__fish_seen_subcommand_from workspace" -s h -l help -d "help for workspace" + +# Options +complete -f -c exercism -s h -l help -d "show help" +complete -f -c exercism -l timeout -a "10" -d "10 seconds" +complete -f -c exercism -l timeout -a "30" -d "30 seconds" +complete -f -c exercism -l timeout -a "60" -d "1 minute" +complete -f -c exercism -l timeout -a "300" -d "5 minutes" +complete -f -c exercism -l timeout -a "600" -d "10 minutes" +complete -f -c exercism -l timeout -a "" -d "override default HTTP timeout" +complete -f -c exercism -s v -l verbose -d "turn on verbose logging" diff --git a/.config/fish/completions/fisher.fish b/.config/fish/completions/fisher.fish new file mode 100644 index 0000000..6d23ce4 --- /dev/null +++ b/.config/fish/completions/fisher.fish @@ -0,0 +1,7 @@ +complete --command fisher --exclusive --long help --description "Print help" +complete --command fisher --exclusive --long version --description "Print version" +complete --command fisher --exclusive --condition __fish_use_subcommand --arguments install --description "Install plugins" +complete --command fisher --exclusive --condition __fish_use_subcommand --arguments update --description "Update installed plugins" +complete --command fisher --exclusive --condition __fish_use_subcommand --arguments remove --description "Remove installed plugins" +complete --command fisher --exclusive --condition __fish_use_subcommand --arguments list --description "List installed plugins matching regex" +complete --command fisher --exclusive --condition "__fish_seen_subcommand_from update remove" --arguments "(fisher list)" diff --git a/.config/fish/config.fish b/.config/fish/config.fish new file mode 100644 index 0000000..623b900 --- /dev/null +++ b/.config/fish/config.fish @@ -0,0 +1,76 @@ +if status is-interactive + # Commands to run in interactive sessions can go here +end +set -gx XDG_CONFIG_HOME /home/joe/.config +set -gx XDG_DATA_HOME /home/joe/.local/share +set -gx XDG_CACHE_HOME /home/joe/.cache + +# set -gx VISUAL emacsclient -n +# set -gx EDITOR emacsclient -n +set -gx VISUAL nvim +set -gx EDITOR nvim + +set -gx MANPAGER "sh -c 'col -bx | bat -l man -p'" +set -gx DOTNET_CLI_TELEMETRY_OPTOUT 1 + +bind \cx 'if test -z (commandline) ; fg %1 &>/dev/null; else ; clear; commandline "╰─>$ "; end' +bind \e/ accept-autosuggestion + +abbr -a -g gs "git status --untracked-files" +abbr -a -g gl "git lop -10" +abbr -a -g gll "git lol -15" +abbr -a -g gchm "git checkout master" +abbr -a -g gchb "git checkout -b" +abbr -a -g gch "git checkout" +abbr -a -g gc "git commit" +abbr -a -g gcm "git commit -m" +abbr -a -g gcau "git commit --author" +abbr -a -g gcam "git commit -am" +abbr -a -g gcamm "git commit --amend" +abbr -a -g gaa "git add -A && git status --untracked-files" +abbr -a -g gpl "git pull" +abbr -a -g gp "git push" +abbr -a -g gpd "git push -d origin" +abbr -a -g gpr "git remote prune origin" +abbr -a -g gm "git merge" +abbr -a -g gmm "git merge master" +abbr -a -g gf "git fetch" +abbr -a -g grh "git reset --hard" +abbr -a -g gcl "git clean -fd" +abbr -a -g gd "git diff" +abbr -a -g gb "git branch" +abbr -a -g gba "git branch -a" +# abbr -a -g gpu "git push -u origin" +# abbr -a -g glp "git lfs pull" +# abbr -a -g glm "gss git merge ; glp" +# abbr -a -g gdh "git diff HEAD" +# abbr -a -g gms "git merge --squash" +# abbr -a -g gr "git rebase" +# abbr -a -g gst "git stash" +# abbr -a -g gsl "git stash list" +# abbr -a -g gsp "git stash pop" +# abbr -a -g gsu "git submodule update" +# abbr -a -g glom "git lop -10 origin/master" +# abbr -a -g gmom "git merge origin/master" +# abbr -a -g gss "env GIT_LFS_SKIP_SMUDGE=1" + +# export NNN_FIFO="/tmp/nnn.fifo" # temporary buffer for the previews +# export NNN_PLUG='p:preview-tui' + +# complete -f -c dotnet -a "(dotnet complete)" + +function vterm_printf; + printf "\e]%s\e\\" "$argv" +end + +function vterm_prompt_end; + vterm_printf '51;A'(whoami)'@'(hostname)':'(pwd) +end +functions --copy fish_prompt vterm_old_fish_prompt +function fish_prompt --description 'Write out the prompt; do not replace this. Instead, put this at end of your file.' + # Remove the trailing newline from the original prompt. This is done + # using the string builtin from fish, but to make sure any escape codes + # are correctly interpreted, use %b for printf. + printf "%b" (string join " \n" (vterm_old_fish_prompt)) + vterm_prompt_end +end diff --git a/.config/fish/fish_plugins b/.config/fish/fish_plugins new file mode 100644 index 0000000..397ce3a --- /dev/null +++ b/.config/fish/fish_plugins @@ -0,0 +1,2 @@ +jorgebucaran/fisher +sei40kr/fish-ranger-cd diff --git a/.config/fish/fish_variables b/.config/fish/fish_variables new file mode 100644 index 0000000..e225511 --- /dev/null +++ b/.config/fish/fish_variables @@ -0,0 +1,43 @@ +# This file contains fish universal variable definitions. +# VERSION: 3.0 +SETUVAR --export CARGO_HOME:/home/joe/\x2elocal/share/bin/cargo/ +SETUVAR EDITOR:hx +SETUVAR --export LC_COLLATE:C +SETUVAR --export --path LD_LIBRARY_PATH:/usr/local/lib +SETUVAR --export PYTHONSTARTUP:/etc/python/pythonrc +SETUVAR --export RUSTUP_HOME:/home/joe/\x2elocal/share/rustup/ +SETUVAR XDG_CACHE_HOME:/home/joe/\x2ecache +SETUVAR XDG_CONFIG_HOME:/home/joe/\x2econfig +SETUVAR XDG_DATA_HOME:/home/joe/\x2elocal/share +SETUVAR __fish_initialized:3400 +SETUVAR fish_color_autosuggestion:969896 +SETUVAR fish_color_cancel:\x2dr +SETUVAR fish_color_command:b294bb +SETUVAR fish_color_comment:f0c674 +SETUVAR fish_color_cwd:green +SETUVAR fish_color_cwd_root:red +SETUVAR fish_color_end:b294bb +SETUVAR fish_color_error:cc6666 +SETUVAR fish_color_escape:00a6b2 +SETUVAR fish_color_history_current:\x2d\x2dbold +SETUVAR fish_color_host:normal +SETUVAR fish_color_host_remote:yellow +SETUVAR fish_color_match:\x2d\x2dbackground\x3dbrblue +SETUVAR fish_color_normal:normal +SETUVAR fish_color_operator:00a6b2 +SETUVAR fish_color_param:81a2be +SETUVAR fish_color_quote:b5bd68 +SETUVAR fish_color_redirection:8abeb7 +SETUVAR fish_color_search_match:bryellow\x1e\x2d\x2dbackground\x3dbrblack +SETUVAR fish_color_selection:white\x1e\x2d\x2dbold\x1e\x2d\x2dbackground\x3dbrblack +SETUVAR fish_color_status:red +SETUVAR fish_color_user:brgreen +SETUVAR fish_color_valid_path:\x2d\x2dunderline +SETUVAR fish_greeting: +SETUVAR fish_key_bindings:fish_default_key_bindings +SETUVAR fish_pager_color_completion:normal +SETUVAR fish_pager_color_description:B3A06D\x1eyellow +SETUVAR fish_pager_color_prefix:normal\x1e\x2d\x2dbold\x1e\x2d\x2dunderline +SETUVAR fish_pager_color_progress:brwhite\x1e\x2d\x2dbackground\x3dcyan +SETUVAR fish_pager_color_selected_background:\x2dr +SETUVAR fish_user_paths:/home/joe/\x2elocal/share/bin/cargo/bin\x1e\x1e/home/joe/\x2elocal/bin diff --git a/.config/fish/functions/e.fish b/.config/fish/functions/e.fish new file mode 100644 index 0000000..4ba3ab6 --- /dev/null +++ b/.config/fish/functions/e.fish @@ -0,0 +1,3 @@ +function e --wraps=emacsclient -n $argv + emacsclient -n $argv; +end diff --git a/.config/fish/functions/edit-dotfile.fish b/.config/fish/functions/edit-dotfile.fish new file mode 100644 index 0000000..fe9ef88 --- /dev/null +++ b/.config/fish/functions/edit-dotfile.fish @@ -0,0 +1,18 @@ +function edit-dotfile + pushd /home/joe/.dotfiles/ + + export FZF_DEFAULT_COMMAND='find . -path './.git' -prune -o -print' + + set file (fzf --height=35% --preview 'echo {}') + if test $file + set fullpath (readlink -f $file) + popd + if [ -d $fullpath ] + cd $fullpath + else + nvim $fullpath + end + end + commandline -f repaint + +end diff --git a/.config/fish/functions/fish_listpaths.fish b/.config/fish/functions/fish_listpaths.fish new file mode 100644 index 0000000..325f13f --- /dev/null +++ b/.config/fish/functions/fish_listpaths.fish @@ -0,0 +1,5 @@ +function fish_listpaths + for p in $PATH + echo $p + end +end diff --git a/.config/fish/functions/fish_prompt.fish b/.config/fish/functions/fish_prompt.fish new file mode 100644 index 0000000..a11d80c --- /dev/null +++ b/.config/fish/functions/fish_prompt.fish @@ -0,0 +1,106 @@ +function fish_prompt + # This prompt shows: + # - green lines if the last return command is OK, red otherwise + # - your user name, in red if root or yellow otherwise + # - your hostname, in cyan if ssh or blue otherwise + # - the current path (with prompt_pwd) + # - date +%X + # - the current virtual environment, if any + # - the current git status, if any, with fish_git_prompt + # - the current battery state, if any, and if your power cable is unplugged, and if you have "acpi" + # - current background jobs, if any + + # It goes from: + # ┬─[nim@Hattori:~]─[11:39:00] + # ╰─>$ echo here + + # To: + # ┬─[nim@Hattori:~/w/dashboard]─[11:37:14]─[V:django20]─[G:master↑1|●1✚1…1]─[B:85%, 05:41:42 remaining] + # │ 2 15054 0% arrêtée sleep 100000 + # │ 1 15048 0% arrêtée sleep 100000 + # ╰─>$ echo there + + set -l retc red + test $status = 0; and set retc green + + function _nim_prompt_wrapper + set retc $argv[1] + set -l field_name $argv[2] + set -l field_value $argv[3] + + set_color normal + set_color $retc + echo -n '─' + set_color -o green + echo -n '[' + set_color normal + test -n $field_name + and echo -n $field_name: + set_color $retc + echo -n $field_value + set_color -o green + echo -n ']' + end + + set_color $retc + echo -n '┬─' + set_color -o green + echo -n [ + + if functions -q fish_is_root_user; and fish_is_root_user + set_color -o red + else + set_color -o yellow + end + + echo -n $USER + set_color -o white + echo -n @ + + if [ -z "$SSH_CLIENT" ] + set_color -o blue + else + set_color -o cyan + end + + echo -n (prompt_hostname) + set_color -o white + set -g fish_prompt_pwd_dir_length 5 + echo -n :(prompt_pwd) + set_color -o green + echo -n ']' + + # Date + _nim_prompt_wrapper $retc '' (date +%X) + + # Vi-mode + # The default mode prompt would be prefixed, which ruins our alignment. + function fish_mode_prompt + end + + echo + + # Background jobs + set_color normal + + for job in (jobs) + set_color $retc + echo -n '│ ' + set_color brown + echo $job + end + + set_color normal + set_color $retc + echo -n '╰─>' + set -l user (whoami) + if test "$user" = "root" + set_color -o red + echo -n '# ' + else + set_color -o green + echo -n '$ ' + end + + set_color normal +end diff --git a/.config/fish/functions/fish_title.fish b/.config/fish/functions/fish_title.fish new file mode 100644 index 0000000..5defedb --- /dev/null +++ b/.config/fish/functions/fish_title.fish @@ -0,0 +1,6 @@ +function fish_title + hostname + echo ":" + set -g fish_prompt_pwd_dir_length 0 + echo -n (prompt_pwd) +end diff --git a/.config/fish/functions/fisher.fish b/.config/fish/functions/fisher.fish new file mode 100644 index 0000000..a1fb6cf --- /dev/null +++ b/.config/fish/functions/fisher.fish @@ -0,0 +1,209 @@ +function fisher --argument-names cmd --description "A plugin manager for Fish" + set --query fisher_path || set --local fisher_path $__fish_config_dir + set --local fisher_version 4.3.0 + set --local fish_plugins $__fish_config_dir/fish_plugins + + switch "$cmd" + case -v --version + echo "fisher, version $fisher_version" + case "" -h --help + echo "Usage: fisher install Install plugins" + echo " fisher remove Remove installed plugins" + echo " fisher update Update installed plugins" + echo " fisher update Update all installed plugins" + echo " fisher list [] List installed plugins matching regex" + echo "Options:" + echo " -v or --version Print version" + echo " -h or --help Print this help message" + case ls list + string match --entire --regex -- "$argv[2]" $_fisher_plugins + case install update remove + isatty || read --local --null --array stdin && set --append argv $stdin + + set --local install_plugins + set --local update_plugins + set --local remove_plugins + set --local arg_plugins $argv[2..-1] + set --local old_plugins $_fisher_plugins + set --local new_plugins + + if ! set --query argv[2] + if test "$cmd" != update + echo "fisher: Not enough arguments for command: \"$cmd\"" >&2 && return 1 + else if test ! -e $fish_plugins + echo "fisher: \"$fish_plugins\" file not found: \"$cmd\"" >&2 && return 1 + end + set arg_plugins (string match --regex -- '^[^\s]+$' <$fish_plugins) + end + + for plugin in $arg_plugins + test -e "$plugin" && set plugin (realpath $plugin) + contains -- "$plugin" $new_plugins || set --append new_plugins $plugin + end + + if set --query argv[2] + for plugin in $new_plugins + if contains -- "$plugin" $old_plugins + test "$cmd" = remove && + set --append remove_plugins $plugin || + set --append update_plugins $plugin + else if test "$cmd" = install + set --append install_plugins $plugin + else + echo "fisher: Plugin not installed: \"$plugin\"" >&2 && return 1 + end + end + else + for plugin in $new_plugins + contains -- "$plugin" $old_plugins && + set --append update_plugins $plugin || + set --append install_plugins $plugin + end + + for plugin in $old_plugins + contains -- "$plugin" $new_plugins || set --append remove_plugins $plugin + end + end + + set --local pid_list + set --local source_plugins + set --local fetch_plugins $update_plugins $install_plugins + echo (set_color --bold)fisher $cmd version $fisher_version(set_color normal) + + for plugin in $fetch_plugins + set --local source (command mktemp -d) + set --append source_plugins $source + + command mkdir -p $source/{completions,conf.d,functions} + + fish --command " + if test -e $plugin + command cp -Rf $plugin/* $source + else + set temp (command mktemp -d) + set name (string split \@ $plugin) || set name[2] HEAD + set url https://codeload.github.com/\$name[1]/tar.gz/\$name[2] + + echo Fetching (set_color --underline)\$url(set_color normal) + + if curl --silent \$url | tar -xzC \$temp -f - 2>/dev/null + command cp -Rf \$temp/*/* $source + else + echo fisher: Invalid plugin name or host unavailable: \\\"$plugin\\\" >&2 + command rm -rf $source + end + command rm -rf \$temp + end + + set files $source/* && string match --quiet --regex -- .+\.fish\\\$ \$files + " & + + set --append pid_list (jobs --last --pid) + end + + wait $pid_list 2>/dev/null + + for plugin in $fetch_plugins + if set --local source $source_plugins[(contains --index -- "$plugin" $fetch_plugins)] && test ! -e $source + if set --local index (contains --index -- "$plugin" $install_plugins) + set --erase install_plugins[$index] + else + set --erase update_plugins[(contains --index -- "$plugin" $update_plugins)] + end + end + end + + for plugin in $update_plugins $remove_plugins + if set --local index (contains --index -- "$plugin" $_fisher_plugins) + set --local plugin_files_var _fisher_(string escape --style=var -- $plugin)_files + + if contains -- "$plugin" $remove_plugins + for name in (string replace --filter --regex -- '.+/conf\.d/([^/]+)\.fish$' '$1' $$plugin_files_var) + emit {$name}_uninstall + end + printf "%s\n" Removing\ (set_color red --bold)$plugin(set_color normal) " "$$plugin_files_var + end + + command rm -rf $$plugin_files_var + functions --erase (string replace --filter --regex -- '.+/functions/([^/]+)\.fish$' '$1' $$plugin_files_var) + + for name in (string replace --filter --regex -- '.+/completions/([^/]+)\.fish$' '$1' $$plugin_files_var) + complete --erase --command $name + end + + set --erase _fisher_plugins[$index] + set --erase $plugin_files_var + end + end + + if set --query update_plugins[1] || set --query install_plugins[1] + command mkdir -p $fisher_path/{functions,conf.d,completions} + end + + for plugin in $update_plugins $install_plugins + set --local source $source_plugins[(contains --index -- "$plugin" $fetch_plugins)] + set --local files $source/{functions,conf.d,completions}/* + + if set --local index (contains --index -- $plugin $install_plugins) + set --local user_files $fisher_path/{functions,conf.d,completions}/* + set --local conflict_files + + for file in (string replace -- $source/ $fisher_path/ $files) + contains -- $file $user_files && set --append conflict_files $file + end + + if set --query conflict_files[1] && set --erase install_plugins[$index] + echo -s "fisher: Cannot install \"$plugin\": please remove or move conflicting files first:" \n" "$conflict_files >&2 + continue + end + end + + for file in (string replace -- $source/ "" $files) + command cp -Rf $source/$file $fisher_path/$file + end + + set --local plugin_files_var _fisher_(string escape --style=var -- $plugin)_files + set --query files[1] && set --universal $plugin_files_var (string replace -- $source $fisher_path $files) + + contains -- $plugin $_fisher_plugins || set --universal --append _fisher_plugins $plugin + contains -- $plugin $install_plugins && set --local event install || set --local event update + + printf "%s\n" Installing\ (set_color --bold)$plugin(set_color normal) " "$$plugin_files_var + + for file in (string match --regex -- '.+/[^/]+\.fish$' $$plugin_files_var) + source $file + if set --local name (string replace --regex -- '.+conf\.d/([^/]+)\.fish$' '$1' $file) + emit {$name}_$event + end + end + end + + command rm -rf $source_plugins + + set --query _fisher_plugins[1] || set --erase _fisher_plugins + set --query _fisher_plugins && + printf "%s\n" $_fisher_plugins >$fish_plugins || + command rm -f $fish_plugins + + set --local total (count $install_plugins) (count $update_plugins) (count $remove_plugins) + test "$total" != "0 0 0" && echo (string join ", " ( + test $total[1] = 0 || echo "Installed $total[1]") ( + test $total[2] = 0 || echo "Updated $total[2]") ( + test $total[3] = 0 || echo "Removed $total[3]") + ) plugin/s + case \* + echo "fisher: Unknown command: \"$cmd\"" >&2 && return 1 + end +end + +## Migrations ## +function _fisher_fish_postexec --on-event fish_postexec + if functions --query _fisher_list + fisher update >/dev/null 2>/dev/null + set --query XDG_DATA_HOME || set --local XDG_DATA_HOME ~/.local/share + test -e $XDG_DATA_HOME/fisher && command rm -rf $XDG_DATA_HOME/fisher + functions --erase _fisher_list _fisher_plugin_parse + set --erase fisher_data + end + functions --erase _fisher_fish_postexec +end diff --git a/.config/fish/functions/kitty_select_theme.fish b/.config/fish/functions/kitty_select_theme.fish new file mode 100644 index 0000000..49bdf6a --- /dev/null +++ b/.config/fish/functions/kitty_select_theme.fish @@ -0,0 +1,9 @@ +function kitty_select_theme + pushd /home/joe/.config/kitty/themes/preferred + + set theme (fzf --height=35% --preview 'echo {} && kitty @ set-colors -a -c {}') + kitty @ set-colors -a -c $theme + cat $theme > ~/.config/kitty/theme.conf + + popd +end diff --git a/.config/fish/functions/la.fish b/.config/fish/functions/la.fish new file mode 100644 index 0000000..2b549d7 --- /dev/null +++ b/.config/fish/functions/la.fish @@ -0,0 +1,6 @@ +# +# These are very common and useful +# +function la --wraps ls --description "List contents of directory, including hidden files in directory using long format" + ls -lAh --group-directories-first $argv +end diff --git a/.config/fish/functions/m.fish b/.config/fish/functions/m.fish new file mode 100644 index 0000000..c437b2d --- /dev/null +++ b/.config/fish/functions/m.fish @@ -0,0 +1,3 @@ +function m --wraps=magit --description 'alias m magit' + magit $argv; +end diff --git a/.config/fish/functions/n.fish b/.config/fish/functions/n.fish new file mode 100644 index 0000000..204d800 --- /dev/null +++ b/.config/fish/functions/n.fish @@ -0,0 +1,37 @@ +# Rename this file to match the name of the function +# e.g. ~/.config/fish/functions/n.fish +# or, add the lines to the 'config.fish' file. + +function n --wraps nnn --description 'support nnn quit and change directory' + # Block nesting of nnn in subshells + if test -n "$NNNLVL" -a "$NNNLVL" -ge 1 + echo "nnn is already running" + return + end + + # The behaviour is set to cd on quit (nnn checks if NNN_TMPFILE is set) + # If NNN_TMPFILE is set to a custom path, it must be exported for nnn to + # see. To cd on quit only on ^G, remove the "-x" from both lines below, + # without changing the paths. + if test -n "$XDG_CONFIG_HOME" + set -x NNN_TMPFILE "$XDG_CONFIG_HOME/nnn/.lastd" + else + set -x NNN_TMPFILE "$HOME/.config/nnn/.lastd" + end + + # Unmask ^Q (, ^V etc.) (if required, see `stty -a`) to Quit nnn + # stty start undef + # stty stop undef + # stty lwrap undef + # stty lnext undef + + # The command function allows one to alias this function to `nnn` without + # making an infinitely recursive alias + set -x NNN_PLUG 'p:preview-tui' + command nnn -ed -P p $argv + + if test -e $NNN_TMPFILE + source $NNN_TMPFILE + rm $NNN_TMPFILE + end +end diff --git a/.config/fish/functions/r.fish b/.config/fish/functions/r.fish new file mode 100644 index 0000000..e836113 --- /dev/null +++ b/.config/fish/functions/r.fish @@ -0,0 +1,3 @@ +function r --wraps=ranger-cd --description 'alias r ranger-cd' + ranger-cd $argv; +end diff --git a/.config/fish/functions/ranger-cd.fish b/.config/fish/functions/ranger-cd.fish new file mode 100644 index 0000000..63b2330 --- /dev/null +++ b/.config/fish/functions/ranger-cd.fish @@ -0,0 +1,13 @@ +# ranger-cd.fish +# author: Seong Yong-ju + +function ranger-cd -w 'ranger' -d 'Automatically change the directory in fish after closing ranger' + set -l tempfile (mktemp -t tmp.XXXXXX) + + ranger --choosedir=$tempfile $argv + + if [ -f $tempfile ] + cd (cat $tempfile) + end + rm -f $tempfile +end diff --git a/.config/fish/functions/restore_job.fish b/.config/fish/functions/restore_job.fish new file mode 100644 index 0000000..dfa3f0b --- /dev/null +++ b/.config/fish/functions/restore_job.fish @@ -0,0 +1,6 @@ +function restore_job + if jobs > /dev/null + fg + clear + end +end diff --git a/.config/fish/functions/rustup.fish b/.config/fish/functions/rustup.fish new file mode 100644 index 0000000..2f2a000 --- /dev/null +++ b/.config/fish/functions/rustup.fish @@ -0,0 +1,3 @@ +function rustup --wraps='RUSTUP_HOME=/home/joe/.local/share/rustup/ /home/joe/.local/share/bin/cargo/bin/rustup' --description 'alias rustup RUSTUP_HOME=/home/joe/.local/share/rustup/ /home/joe/.local/share/bin/cargo/bin/rustup' + RUSTUP_HOME=/home/joe/.local/share/rustup/ /home/joe/.local/share/bin/cargo/bin/rustup $argv +end diff --git a/.config/fish/functions/sql.fish b/.config/fish/functions/sql.fish new file mode 100644 index 0000000..81be8e2 --- /dev/null +++ b/.config/fish/functions/sql.fish @@ -0,0 +1,3 @@ +function sql + SQLITE_HISTORY="$XDG_CACHE_HOME"/sqlite_history sqlite3 -init "$XDG_CONFIG_HOME"/sqlite3/sqliterc "$argv" +end diff --git a/.config/fish/functions/v.fish b/.config/fish/functions/v.fish new file mode 100644 index 0000000..b746e5b --- /dev/null +++ b/.config/fish/functions/v.fish @@ -0,0 +1,3 @@ +function v --wraps=nvim --description 'alias v nvim' + nvim $argv; +end diff --git a/.config/fish/functions/wget.fish b/.config/fish/functions/wget.fish new file mode 100644 index 0000000..b37d516 --- /dev/null +++ b/.config/fish/functions/wget.fish @@ -0,0 +1,3 @@ +function wget --description 'alias wget wget --hsts-file="$XDG_CACHE_HOME/wget-hsts"' + command wget --hsts-file="$XDG_CACHE_HOME/wget-hsts" $argv +end diff --git a/.config/git/config b/.config/git/config new file mode 100644 index 0000000..63c6794 --- /dev/null +++ b/.config/git/config @@ -0,0 +1,18 @@ +[user] + email = joseph@ferano.io + name = Joseph Ferano +[init] + defaultBranch = master +[alias] + lop = log --pretty='%C(green)%an %C(blue)(%ad)%n %C(yellow)%h %C(white)| %C(reset)%s' --abbrev-commit --date=relative + lol = log --graph --pretty='%C(yellow)%h %C(green)%an %C(reset)%s' --abbrev-commit +[diff] + tool = kitty + guitool = kitty.gui +[difftool] + prompt = false + trustExitCode = true +[difftool "kitty"] + cmd = kitty +kitten diff $LOCAL $REMOTE +[difftool "kitty.gui"] + cmd = kitty kitty +kitten diff $LOCAL $REMOTE diff --git a/.config/kitty/kitty-convert.py b/.config/kitty/kitty-convert.py new file mode 100644 index 0000000..441e183 --- /dev/null +++ b/.config/kitty/kitty-convert.py @@ -0,0 +1,61 @@ +import json +import sys + +def env_to_str(env): + """Convert an env list to a series of '--env key=value' parameters and return as a string.""" + # FIXME: running launch with --env params doesn't seem to work - I get this error: + # Failed to launch child: --env + # With error: No such file or directory + # Press Enter to exit. + # So, skip this for now. + return '' + # s = '' + # for key in env: + # s += f"--env {key}={env[key]} " + + # return s.strip() + +def cmdline_to_str(cmdline): + """Convert a cmdline list to a space separated string.""" + s = '' + for e in cmdline: + s += f"{e} " + + return s.strip() + +def fg_proc_to_str(fg): + """Convert a foreground_processes list to a space separated string.""" + s = '' + fg = fg[0] + + # s += f"--cwd {fg['cwd']} {cmdline_to_str(fg['cmdline'])}" + s += f"{cmdline_to_str(fg['cmdline'])}" + + return s + +def convert(session): + """Convert a kitty session dict, into a kitty session file and output it.""" + for os_window in session: + print('\nnew_os_window\n') + + for tab in os_window['tabs']: + print(f"new_tab {tab['title']}") + # print('enabled_layouts *) + print(f"layout {tab['layout']}") + # This is a bit of a kludge to set cwd for the tab, as + # setting it in the launch command didn't work, for some reason? + if tab['windows']: + print(f"cd {tab['windows'][0]['cwd']}") + + for w in tab['windows']: + print(f"title {w['title']}") + print(f"launch {env_to_str(w['env'])} {fg_proc_to_str(w['foreground_processes'])}") + if w['is_focused']: + print('focus') + + +if __name__ == "__main__": + stdin = sys.stdin.readlines() + session = json.loads(''.join(stdin)) + convert(session) + diff --git a/.config/kitty/kitty.conf b/.config/kitty/kitty.conf new file mode 100644 index 0000000..d834c7f --- /dev/null +++ b/.config/kitty/kitty.conf @@ -0,0 +1,86 @@ +include /home/joe/.config/kitty/theme.conf + +font_size 13.0 + +adjust_line_height 4 +adjust_column_width 0 + +window_resize_step_cells 3 +window_resize_step_lines 3 + +window_border_width 1.5 +draw_minimal_borders yes +window_margin_width 0.0 +active_border_color #bbb +inactive_border_color #555 +bell_border_color #ff5a00 +inactive_text_alpha 1 +hide_window_decorations yes + +cursor_shape block + +allow_remote_control yes +#: single_instance yes +listen_on unix:/tmp/kitty + +window_padding_width 4 +window_margin_width 2 + +tab_bar_style powerline +tab_powerline_style round +tab_bar_align left + +sync_to_monitor yes +input_delay 3 + +scrollback_pager bash -c "exec nvim 63<&0 0 q :qa!' -c 'set shell=bash scrollback=100000 termguicolors laststatus=0 clipboard+=unnamedplus' -c 'autocmd TermEnter * stopinsert' -c 'autocmd TermClose * call cursor(max([0,INPUT_LINE_NUMBER-1])+CURSOR_LINE, CURSOR_COLUMN)' -c 'terminal sed n new_tab +map alt+t>r set_tab_title + +map kitty_mod+1 goto_tab 1 +map kitty_mod+2 goto_tab 2 +map kitty_mod+3 goto_tab 3 +map kitty_mod+4 goto_tab 4 +map kitty_mod+5 goto_tab 5 +map kitty_mod+6 goto_tab 6 +map kitty_mod+7 goto_tab 7 +map kitty_mod+8 goto_tab 8 +map kitty_mod+9 goto_tab 9 + +map kitty_mod+e show_scrollback + +map kitty_mod+shift+k move_window up +map kitty_mod+shift+h move_window left +map kitty_mod+shift+l move_window right +map kitty_mod+shift+j move_window down + +#: map f1 launch --type overlay --stdin-add-formatting --stdin-source=@screen_scrollback ~/.config/kitty/pager.sh diff --git a/.config/kitty/theme.conf b/.config/kitty/theme.conf new file mode 100644 index 0000000..19d2e40 --- /dev/null +++ b/.config/kitty/theme.conf @@ -0,0 +1,21 @@ +background #212733 +foreground #d9d7ce +cursor #ffcc66 +selection_background #343f4c +color0 #191e2a +color8 #686868 +color1 #ed8274 +color9 #f28779 +color2 #a6cc70 +color10 #bae67e +color3 #fad07b +color11 #ffd580 +color4 #6dcbfa +color12 #73d0ff +color5 #cfbafa +color13 #d4bfff +color6 #90e1c6 +color14 #95e6cb +color7 #c7c7c7 +color15 #ffffff +selection_foreground #212733 diff --git a/.config/kitty/themes/Afterglow.conf b/.config/kitty/themes/Afterglow.conf new file mode 100644 index 0000000..2df3efd --- /dev/null +++ b/.config/kitty/themes/Afterglow.conf @@ -0,0 +1,21 @@ +background #202020 +foreground #d0d0d0 +cursor #d0d0d0 +selection_background #303030 +color0 #151515 +color8 #505050 +color1 #ac4142 +color9 #ac4142 +color2 #7e8d50 +color10 #7e8d50 +color3 #e5b566 +color11 #e5b566 +color4 #6c99ba +color12 #6c99ba +color5 #9e4e85 +color13 #9e4e85 +color6 #7dd5cf +color14 #7dd5cf +color7 #d0d0d0 +color15 #f5f5f5 +selection_foreground #202020 diff --git a/.config/kitty/themes/Atom.conf b/.config/kitty/themes/Atom.conf new file mode 100644 index 0000000..091c683 --- /dev/null +++ b/.config/kitty/themes/Atom.conf @@ -0,0 +1,21 @@ +background #161718 +foreground #c4c8c5 +cursor #d0d0d0 +selection_background #444444 +color0 #000000 +color8 #000000 +color1 #fc5ef0 +color9 #fc5ef0 +color2 #86c38a +color10 #94f936 +color3 #ffd6b1 +color11 #f5ffa7 +color4 #85befd +color12 #95cbfe +color5 #b9b5fc +color13 #b9b5fc +color6 #85befd +color14 #85befd +color7 #dfdfdf +color15 #dfdfdf +selection_foreground #161718 diff --git a/.config/kitty/themes/CLRS.conf b/.config/kitty/themes/CLRS.conf new file mode 100644 index 0000000..ddcb324 --- /dev/null +++ b/.config/kitty/themes/CLRS.conf @@ -0,0 +1,21 @@ +background #ffffff +foreground #262626 +cursor #6fd2fc +selection_background #6fd2fc +color0 #000000 +color8 #545753 +color1 #f72729 +color9 #fb0416 +color2 #32895c +color10 #2cc631 +color3 #f96f1c +color11 #fcd627 +color4 #125ccf +color12 #156ffe +color5 #9f00bc +color13 #e800b0 +color6 #32c2c0 +color14 #39d5ce +color7 #b2b2b2 +color15 #ededec +selection_foreground #ffffff diff --git a/.config/kitty/themes/Darkside.conf b/.config/kitty/themes/Darkside.conf new file mode 100644 index 0000000..10238d1 --- /dev/null +++ b/.config/kitty/themes/Darkside.conf @@ -0,0 +1,21 @@ +background #212324 +foreground #b9b9b9 +cursor #bbbbbb +selection_background #2f3333 +color0 #000000 +color8 #000000 +color1 #e8331c +color9 #df5a4f +color2 #68c156 +color10 #76b768 +color3 #f1d32b +color11 #eed64a +color4 #1c98e8 +color12 #387bd2 +color5 #8e69c8 +color13 #957bbd +color6 #1c98e8 +color14 #3d96e2 +color7 #b9b9b9 +color15 #b9b9b9 +selection_foreground #212324 diff --git a/.config/kitty/themes/Flatland.conf b/.config/kitty/themes/Flatland.conf new file mode 100644 index 0000000..637b72d --- /dev/null +++ b/.config/kitty/themes/Flatland.conf @@ -0,0 +1,21 @@ +background #1c1e20 +foreground #b8daee +cursor #708183 +selection_background #2a2a24 +color0 #1c1d19 +color8 #1c1d19 +color1 #f18238 +color9 #d12a24 +color2 #9ed264 +color10 #a7d32c +color3 #f3ef6d +color11 #ff8948 +color4 #4f96be +color12 #61b8d0 +color5 #695abb +color13 #695abb +color6 #d53864 +color14 #d53864 +color7 #fefffe +color15 #fefffe +selection_foreground #1c1e20 diff --git a/.config/kitty/themes/Monokai_Classic.conf b/.config/kitty/themes/Monokai_Classic.conf new file mode 100644 index 0000000..9c74f40 --- /dev/null +++ b/.config/kitty/themes/Monokai_Classic.conf @@ -0,0 +1,47 @@ +background #3b3c35 +foreground #fdfff1 + +cursor #fdfff1 +cursor_text_color #000000 +selection_foreground #3b3c35 +selection_background #fdfff1 + +# dull black +color0 #3b3c35 +# light black +color8 #6e7066 + +# dull red +color1 #f82570 +# light red +color9 #f82570 + +# dull green +color2 #a6e12d +# light green +color10 #a6e12d + +# yellow +color3 #e4db73 +# light yellow +color11 #e4db73 + +# blue +color4 #fc961f +# light blue +color12 #fc961f + +# magenta +color5 #ae81ff +# light magenta +color13 #ae81ff + +# cyan +color6 #66d9ee +# light cyan +color14 #66d9ee + +# dull white +color7 #fdfff1 +# bright white +color15 #fdfff1 diff --git a/.config/kitty/themes/Monokai_Pro.conf b/.config/kitty/themes/Monokai_Pro.conf new file mode 100644 index 0000000..f5a2e8c --- /dev/null +++ b/.config/kitty/themes/Monokai_Pro.conf @@ -0,0 +1,47 @@ +background #403e41 +foreground #fcfcfa + +cursor #fcfcfa +cursor_text_color #000000 +selection_foreground #403e41 +selection_background #fcfcfa + +# dull black +color0 #403e41 +# light black +color8 #727072 + +# dull red +color1 #ff6188 +# light red +color9 #ff6188 + +# dull green +color2 #a9dc76 +# light green +color10 #a9dc76 + +# yellow +color3 #ffd866 +# light yellow +color11 #ffd866 + +# blue +color4 #fc9867 +# light blue +color12 #fc9867 + +# magenta +color5 #ab9df2 +# light magenta +color13 #ab9df2 + +# cyan +color6 #78dce8 +# light cyan +color14 #78dce8 + +# dull white +color7 #fcfcfa +# bright white +color15 #fcfcfa diff --git a/.config/kitty/themes/Monokai_Pro_(Filter_Machine).conf b/.config/kitty/themes/Monokai_Pro_(Filter_Machine).conf new file mode 100644 index 0000000..b46e1d3 --- /dev/null +++ b/.config/kitty/themes/Monokai_Pro_(Filter_Machine).conf @@ -0,0 +1,47 @@ +background #3a4449 +foreground #f2fffc + +cursor #f2fffc +cursor_text_color #000000 +selection_foreground #3a4449 +selection_background #f2fffc + +# dull black +color0 #3a4449 +# light black +color8 #6b7678 + +# dull red +color1 #ff6d7e +# light red +color9 #ff6d7e + +# dull green +color2 #a2e57b +# light green +color10 #a2e57b + +# yellow +color3 #ffed72 +# light yellow +color11 #ffed72 + +# blue +color4 #ffb270 +# light blue +color12 #ffb270 + +# magenta +color5 #baa0f8 +# light magenta +color13 #baa0f8 + +# cyan +color6 #7cd5f1 +# light cyan +color14 #7cd5f1 + +# dull white +color7 #f2fffc +# bright white +color15 #f2fffc diff --git a/.config/kitty/themes/Monokai_Pro_(Filter_Octagon).conf b/.config/kitty/themes/Monokai_Pro_(Filter_Octagon).conf new file mode 100644 index 0000000..3aee34a --- /dev/null +++ b/.config/kitty/themes/Monokai_Pro_(Filter_Octagon).conf @@ -0,0 +1,47 @@ +background #3a3d4b +foreground #eaf2f1 + +cursor #eaf2f1 +cursor_text_color #000000 +selection_foreground #3a3d4b +selection_background #eaf2f1 + +# dull black +color0 #3a3d4b +# light black +color8 #696d77 + +# dull red +color1 #ff657a +# light red +color9 #ff657a + +# dull green +color2 #bad761 +# light green +color10 #bad761 + +# yellow +color3 #ffd76d +# light yellow +color11 #ffd76d + +# blue +color4 #ff9b5e +# light blue +color12 #ff9b5e + +# magenta +color5 #c39ac9 +# light magenta +color13 #c39ac9 + +# cyan +color6 #9cd1bb +# light cyan +color14 #9cd1bb + +# dull white +color7 #eaf2f1 +# bright white +color15 #eaf2f1 diff --git a/.config/kitty/themes/Monokai_Pro_(Filter_Ristretto).conf b/.config/kitty/themes/Monokai_Pro_(Filter_Ristretto).conf new file mode 100644 index 0000000..599b0e1 --- /dev/null +++ b/.config/kitty/themes/Monokai_Pro_(Filter_Ristretto).conf @@ -0,0 +1,47 @@ +background #403838 +foreground #fff1f3 + +cursor #fff1f3 +cursor_text_color #000000 +selection_foreground #403838 +selection_background #fff1f3 + +# dull black +color0 #403838 +# light black +color8 #72696a + +# dull red +color1 #fd6883 +# light red +color9 #fd6883 + +# dull green +color2 #adda78 +# light green +color10 #adda78 + +# yellow +color3 #f9cc6c +# light yellow +color11 #f9cc6c + +# blue +color4 #f38d70 +# light blue +color12 #f38d70 + +# magenta +color5 #a8a9eb +# light magenta +color13 #a8a9eb + +# cyan +color6 #85dacc +# light cyan +color14 #85dacc + +# dull white +color7 #fff1f3 +# bright white +color15 #fff1f3 diff --git a/.config/kitty/themes/Monokai_Pro_(Filter_Spectrum).conf b/.config/kitty/themes/Monokai_Pro_(Filter_Spectrum).conf new file mode 100644 index 0000000..5617a6d --- /dev/null +++ b/.config/kitty/themes/Monokai_Pro_(Filter_Spectrum).conf @@ -0,0 +1,47 @@ +background #363537 +foreground #f7f1ff + +cursor #f7f1ff +cursor_text_color #000000 +selection_foreground #363537 +selection_background #f7f1ff + +# dull black +color0 #363537 +# light black +color8 #69676c + +# dull red +color1 #fc618d +# light red +color9 #fc618d + +# dull green +color2 #7bd88f +# light green +color10 #7bd88f + +# yellow +color3 #fce566 +# light yellow +color11 #fce566 + +# blue +color4 #fd9353 +# light blue +color12 #fd9353 + +# magenta +color5 #948ae3 +# light magenta +color13 #948ae3 + +# cyan +color6 #5ad4e6 +# light cyan +color14 #5ad4e6 + +# dull white +color7 #f7f1ff +# bright white +color15 #f7f1ff diff --git a/.config/kitty/themes/Monokai_Soda.conf b/.config/kitty/themes/Monokai_Soda.conf new file mode 100644 index 0000000..eb7a24d --- /dev/null +++ b/.config/kitty/themes/Monokai_Soda.conf @@ -0,0 +1,21 @@ +background #191919 +foreground #c4c4b5 +cursor #f6f6ec +selection_background #343434 +color0 #191919 +color8 #615e4b +color1 #f3005f +color9 #f3005f +color2 #97e023 +color10 #97e023 +color3 #fa8419 +color11 #dfd561 +color4 #9c64fe +color12 #9c64fe +color5 #f3005f +color13 #f3005f +color6 #57d1ea +color14 #57d1ea +color7 #c4c4b5 +color15 #f6f6ee +selection_foreground #191919 diff --git a/.config/kitty/themes/OneDark.conf b/.config/kitty/themes/OneDark.conf new file mode 100644 index 0000000..ad6cb4e --- /dev/null +++ b/.config/kitty/themes/OneDark.conf @@ -0,0 +1,25 @@ +# One Dark by Giuseppe Cesarano, https://github.com/GiuseppeCesarano +# This work is licensed under the terms of the GPL-2.0 license. +# For a copy, see https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + +foreground #979eab +background #282c34 +cursor #cccccc +color0 #282c34 +color1 #e06c75 +color2 #98c379 +color3 #e5c07b +color4 #61afef +color5 #be5046 +color6 #56b6c2 +color7 #979eab +color8 #393e48 +color9 #d19a66 +color10 #56b6c2 +color11 #e5c07b +color12 #61afef +color13 #be5046 +color14 #56b6c2 +color15 #abb2bf +selection_foreground #282c34 +selection_background #979eab diff --git a/.config/kitty/themes/Relaxed_Afterglow.conf b/.config/kitty/themes/Relaxed_Afterglow.conf new file mode 100644 index 0000000..5988777 --- /dev/null +++ b/.config/kitty/themes/Relaxed_Afterglow.conf @@ -0,0 +1,25 @@ +# Relaxed Afterglow by Michael Kühnel , https://github.com/Relaxed-Theme/relaxed-terminal-themes +# This work is licensed under the terms of the MIT license. +# For a copy, see https://opensource.org/licenses/MIT. + +background #353a44 +foreground #d9d9d9 +cursor #d9d9d9 +selection_foreground #d8d8d8 +selection_background #6a7984 +color0 #151515 +color1 #bc5653 +color2 #909d63 +color3 #ebc17a +color4 #6a8799 +color5 #b06698 +color6 #c9dfff +color7 #d9d9d9 +color8 #636363 +color9 #bc5653 +color10 #a0ac77 +color11 #ebc17a +color12 #7eaac7 +color13 #b06698 +color14 #acbbd0 +color15 #f7f7f7 diff --git a/.config/kitty/themes/Solarized_Light.conf b/.config/kitty/themes/Solarized_Light.conf new file mode 100644 index 0000000..36e101b --- /dev/null +++ b/.config/kitty/themes/Solarized_Light.conf @@ -0,0 +1,21 @@ +background #fdf6e3 +foreground #52676f +cursor #52676f +selection_background #e9e2cb +color0 #e4e4e4 +color8 #ffffd7 +color1 #d70000 +color9 #d75f00 +color2 #5f8700 +color10 #585858 +color3 #af8700 +color11 #626262 +color4 #0087ff +color12 #808080 +color5 #af005f +color13 #5f5faf +color6 #00afaf +color14 #8a8a8a +color7 #262626 +color15 #1c1c1c +selection_foreground #fcf4dc diff --git a/.config/kitty/themes/Teerb.conf b/.config/kitty/themes/Teerb.conf new file mode 100644 index 0000000..9e9cab7 --- /dev/null +++ b/.config/kitty/themes/Teerb.conf @@ -0,0 +1,21 @@ +background #262626 +foreground #d0d0d0 +cursor #e3c8ae +selection_background #4d4d4d +color0 #1c1c1c +color8 #1c1c1c +color1 #d68686 +color9 #d68686 +color2 #aed686 +color10 #aed686 +color3 #d7af87 +color11 #e4c9af +color4 #86aed6 +color12 #86aed6 +color5 #d6aed6 +color13 #d6aed6 +color6 #8adbb4 +color14 #b1e7dd +color7 #d0d0d0 +color15 #efefef +selection_foreground #262626 diff --git a/.config/kitty/themes/Tomorrow_Night_Eighties.conf b/.config/kitty/themes/Tomorrow_Night_Eighties.conf new file mode 100644 index 0000000..404efc7 --- /dev/null +++ b/.config/kitty/themes/Tomorrow_Night_Eighties.conf @@ -0,0 +1,21 @@ +background #2c2c2c +foreground #cccccc +cursor #cccccc +selection_background #505050 +color0 #000000 +color8 #000000 +color1 #f17779 +color9 #f17779 +color2 #99cc99 +color10 #99cc99 +color3 #ffcc66 +color11 #ffcc66 +color4 #6699cc +color12 #6699cc +color5 #cc99cc +color13 #cc99cc +color6 #66cccc +color14 #66cccc +color7 #fffefe +color15 #fffefe +selection_foreground #2c2c2c diff --git a/.config/kitty/themes/Wombat.conf b/.config/kitty/themes/Wombat.conf new file mode 100644 index 0000000..d4616fc --- /dev/null +++ b/.config/kitty/themes/Wombat.conf @@ -0,0 +1,21 @@ +background #171717 +foreground #ded9ce +cursor #bbbbbb +selection_background #453a39 +color0 #000000 +color8 #313131 +color1 #ff605a +color9 #f58b7f +color2 #b1e869 +color10 #dcf88f +color3 #ead89c +color11 #eee5b2 +color4 #5da9f6 +color12 #a5c7ff +color5 #e86aff +color13 #ddaaff +color6 #82fff6 +color14 #b6fff9 +color7 #ded9ce +color15 #fefffe +selection_foreground #171717 diff --git a/.config/kitty/themes/ayu_mirage.conf b/.config/kitty/themes/ayu_mirage.conf new file mode 100644 index 0000000..19d2e40 --- /dev/null +++ b/.config/kitty/themes/ayu_mirage.conf @@ -0,0 +1,21 @@ +background #212733 +foreground #d9d7ce +cursor #ffcc66 +selection_background #343f4c +color0 #191e2a +color8 #686868 +color1 #ed8274 +color9 #f28779 +color2 #a6cc70 +color10 #bae67e +color3 #fad07b +color11 #ffd580 +color4 #6dcbfa +color12 #73d0ff +color5 #cfbafa +color13 #d4bfff +color6 #90e1c6 +color14 #95e6cb +color7 #c7c7c7 +color15 #ffffff +selection_foreground #212733 diff --git a/.config/kitty/themes/gruvbox_dark.conf b/.config/kitty/themes/gruvbox_dark.conf new file mode 100644 index 0000000..369da8d --- /dev/null +++ b/.config/kitty/themes/gruvbox_dark.conf @@ -0,0 +1,49 @@ +# gruvbox dark by morhetz, https://github.com/morhetz/gruvbox +# This work is licensed under the terms of the MIT license. +# For a copy, see https://opensource.org/licenses/MIT. + +background #282828 +foreground #ebdbb2 + +cursor #928374 + +selection_foreground #928374 +selection_background #3c3836 + +color0 #282828 +color8 #928374 + +# red +color1 #cc241d +# light red +color9 #fb4934 + +# green +color2 #98971a +# light green +color10 #b8bb26 + +# yellow +color3 #d79921 +# light yellow +color11 #fabd2d + +# blue +color4 #458588 +# light blue +color12 #83a598 + +# magenta +color5 #b16286 +# light magenta +color13 #d3869b + +# cyan +color6 #689d6a +# lighy cyan +color14 #8ec07c + +# light gray +color7 #a89984 +# dark gray +color15 #928374 diff --git a/.config/mbsync/config b/.config/mbsync/config new file mode 100644 index 0000000..a403b92 --- /dev/null +++ b/.config/mbsync/config @@ -0,0 +1,86 @@ +IMAPAccount ferano.io +Host mail.gandi.net +UserCmd "age --decrypt -i ~/.local/credentials/personal ~/.local/credentials/authinfo.age | awk -F ' ' '/mail.gandi.net/ { print $(NF-2);exit; }'" +PassCmd "age --decrypt -i ~/.local/credentials/personal ~/.local/credentials/authinfo.age | awk -F ' ' '/mail.gandi.net/ { print $(NF);exit; }'" +SSLType IMAPS + +IMAPStore ferano.io.remote +Account ferano.io + +MaildirStore ferano.io.local +Subfolders Verbatim +# The trailing "/" is important +Path ~/.mail/ferano.io/ +Inbox ~/.mail/ferano.io/Inbox + +Channel ferano.io +Far :ferano.io.remote: +Near :ferano.io.local: +# Include everything +Patterns * +Sync All +Create Both +Remove Both +Expunge Both +SyncState * + +Channel ferano.io.inbox +Far :ferano.io.remote: +Near :ferano.io.local: +Patterns INBOX +Sync All +Create Both +Remove Both +Expunge Both +SyncState * + +IMAPAccount gmail +Host imap.gmail.com +UserCmd "age --decrypt -i ~/.local/credentials/personal ~/.local/credentials/authinfo.age | awk -F ' ' '/mail.gmail.com/ { print $(NF-2);exit; }'" +PassCmd "age --decrypt -i ~/.local/credentials/personal ~/.local/credentials/authinfo.age | awk -F ' ' '/mail.gmail.com/ { print $(NF);exit; }'" +SSLType IMAPS + +IMAPStore gmail.remote +Account gmail + +MaildirStore gmail.local +Subfolders Verbatim +# The trailing "/" is important +Path ~/.mail/gmail/ +Inbox ~/.mail/gmail/Inbox + +Channel gmail +Far :gmail.remote: +Near :gmail.local: +# Include everything +Patterns * +Sync All +Create Both +Remove Both +Expunge Both +SyncState * + +Channel gmail.inbox +Far :gmail.remote: +Near :gmail.local: +Patterns INBOX +Sync All +Create Both +Remove Both +Expunge Both +SyncState * + +Channel gmail.allmail +Far :gmail.remote: +Near :gmail.local: +Patterns *All* +Sync All +Create Both +Remove Both +Expunge Both +SyncState * + + +Group all +Channel ferano.io +Channel gmail diff --git a/.config/qutebrowser/autoconfig.yml b/.config/qutebrowser/autoconfig.yml new file mode 100644 index 0000000..747496b --- /dev/null +++ b/.config/qutebrowser/autoconfig.yml @@ -0,0 +1,10 @@ +# If a config.py file exists, this file is ignored unless it's explicitly loaded +# via config.load_autoconfig(). For more information, see: +# https://github.com/qutebrowser/qutebrowser/blob/master/doc/help/configuring.asciidoc#loading-autoconfigyml +# DO NOT edit this file by hand, qutebrowser will overwrite it. +# Instead, create a config.py - see :help for details. + +config_version: 2 +settings: + content.notifications.enabled: + https://www.reddit.com: false diff --git a/.config/qutebrowser/bookmarks/urls b/.config/qutebrowser/bookmarks/urls new file mode 100644 index 0000000..e69de29 diff --git a/.config/qutebrowser/config.py b/.config/qutebrowser/config.py new file mode 100644 index 0000000..600dcf8 --- /dev/null +++ b/.config/qutebrowser/config.py @@ -0,0 +1,2443 @@ +## Autogenerated config.py +## +## NOTE: config.py is intended for advanced users who are comfortable +## with manually migrating the config file on qutebrowser upgrades. If +## you prefer, you can also configure qutebrowser using the +## :set/:bind/:config-* commands without having to write a config.py +## file. +## +## Documentation: +## qute://help/configuring.html +## qute://help/settings.html + +## This is here so configs done via the GUI are still loaded. +## Remove it to not load settings done via the GUI. +config.load_autoconfig(False) + +## Aliases for commands. The keys of the given dictionary are the +## aliases, while the values are the commands they map to. +## Type: Dict +# c.aliases = {'w': 'session-save', 'q': 'close', 'qa': 'quit', 'wq': 'quit --save', 'wqa': 'quit --save'} + +## Time interval (in milliseconds) between auto-saves of +## config/cookies/etc. +## Type: Int +# c.auto_save.interval = 15000 + +## Always restore open sites when qutebrowser is reopened. Without this +## option set, `:wq` (`:quit --save`) needs to be used to save open tabs +## (and restore them), while quitting qutebrowser in any other way will +## not save/restore the session. By default, this will save to the +## session which was last loaded. This behavior can be customized via the +## `session.default_name` setting. +## Type: Bool +# c.auto_save.session = False + +## Backend to use to display websites. qutebrowser supports two different +## web rendering engines / backends, QtWebEngine and QtWebKit (not +## recommended). QtWebEngine is Qt's official successor to QtWebKit, and +## both the default/recommended backend. It's based on a stripped-down +## Chromium and regularly updated with security fixes and new features by +## the Qt project: https://wiki.qt.io/QtWebEngine QtWebKit was +## qutebrowser's original backend when the project was started. However, +## support for QtWebKit was discontinued by the Qt project with Qt 5.6 in +## 2016. The development of QtWebKit was picked up in an official fork: +## https://github.com/qtwebkit/qtwebkit - however, the project seems to +## have stalled again. The latest release (5.212.0 Alpha 4) from March +## 2020 is based on a WebKit version from 2016, with many known security +## vulnerabilities. Additionally, there is no process isolation and +## sandboxing. Due to all those issues, while support for QtWebKit is +## still available in qutebrowser for now, using it is strongly +## discouraged. +## Type: String +## Valid values: +## - webengine: Use QtWebEngine (based on Chromium - recommended). +## - webkit: Use QtWebKit (based on WebKit, similar to Safari - many known security issues!). +# c.backend = 'webengine' + +## Map keys to other keys, so that they are equivalent in all modes. When +## the key used as dictionary-key is pressed, the binding for the key +## used as dictionary-value is invoked instead. This is useful for global +## remappings of keys, for example to map to . NOTE: +## This should only be used if two keys should always be equivalent, i.e. +## for things like (keypad) and (non-keypad). For normal +## command bindings, qutebrowser works differently to vim: You always +## bind keys to commands, usually via `:bind` or `config.bind()`. Instead +## of using this setting, consider finding the command a key is bound to +## (e.g. via `:bind gg`) and then binding the same command to the desired +## key. Note that when a key is bound (via `bindings.default` or +## `bindings.commands`), the mapping is ignored. +## Type: Dict +# c.bindings.key_mappings = {'': '', '': '', '': '', '': '', '': '', '': '', '': '', '': '', '': ''} + +## When to show a changelog after qutebrowser was upgraded. +## Type: String +## Valid values: +## - major: Show changelog for major upgrades (e.g. v2.0.0 -> v3.0.0). +## - minor: Show changelog for major and minor upgrades (e.g. v2.0.0 -> v2.1.0). +## - patch: Show changelog for major, minor and patch upgrades (e.g. v2.0.0 -> v2.0.1). +## - never: Never show changelog after upgrades. +# c.changelog_after_upgrade = 'minor' + +## Background color of the completion widget category headers. +## Type: QssColor +# c.colors.completion.category.bg = 'qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #888888, stop:1 #505050)' + +## Bottom border color of the completion widget category headers. +## Type: QssColor +# c.colors.completion.category.border.bottom = 'black' + +## Top border color of the completion widget category headers. +## Type: QssColor +# c.colors.completion.category.border.top = 'black' + +## Foreground color of completion widget category headers. +## Type: QtColor +# c.colors.completion.category.fg = 'white' + +## Background color of the completion widget for even rows. +## Type: QssColor +# c.colors.completion.even.bg = '#333333' + +## Text color of the completion widget. May be a single color to use for +## all columns or a list of three colors, one for each column. +## Type: List of QtColor, or QtColor +# c.colors.completion.fg = ['white', 'white', 'white'] + +## Background color of the selected completion item. +## Type: QssColor +# c.colors.completion.item.selected.bg = '#e8c000' + +## Bottom border color of the selected completion item. +## Type: QssColor +# c.colors.completion.item.selected.border.bottom = '#bbbb00' + +## Top border color of the selected completion item. +## Type: QssColor +# c.colors.completion.item.selected.border.top = '#bbbb00' + +## Foreground color of the selected completion item. +## Type: QtColor +# c.colors.completion.item.selected.fg = 'black' + +## Foreground color of the matched text in the selected completion item. +## Type: QtColor +# c.colors.completion.item.selected.match.fg = '#ff4444' + +## Foreground color of the matched text in the completion. +## Type: QtColor +# c.colors.completion.match.fg = '#ff4444' + +## Background color of the completion widget for odd rows. +## Type: QssColor +# c.colors.completion.odd.bg = '#444444' + +## Color of the scrollbar in the completion view. +## Type: QssColor +# c.colors.completion.scrollbar.bg = '#333333' + +## Color of the scrollbar handle in the completion view. +## Type: QssColor +# c.colors.completion.scrollbar.fg = 'white' + +## Background color of disabled items in the context menu. If set to +## null, the Qt default is used. +## Type: QssColor +# c.colors.contextmenu.disabled.bg = None + +## Foreground color of disabled items in the context menu. If set to +## null, the Qt default is used. +## Type: QssColor +# c.colors.contextmenu.disabled.fg = None + +## Background color of the context menu. If set to null, the Qt default +## is used. +## Type: QssColor +# c.colors.contextmenu.menu.bg = None + +## Foreground color of the context menu. If set to null, the Qt default +## is used. +## Type: QssColor +# c.colors.contextmenu.menu.fg = None + +## Background color of the context menu's selected item. If set to null, +## the Qt default is used. +## Type: QssColor +# c.colors.contextmenu.selected.bg = None + +## Foreground color of the context menu's selected item. If set to null, +## the Qt default is used. +## Type: QssColor +# c.colors.contextmenu.selected.fg = None + +## Background color for the download bar. +## Type: QssColor +# c.colors.downloads.bar.bg = 'black' + +## Background color for downloads with errors. +## Type: QtColor +# c.colors.downloads.error.bg = 'red' + +## Foreground color for downloads with errors. +## Type: QtColor +# c.colors.downloads.error.fg = 'white' + +## Color gradient start for download backgrounds. +## Type: QtColor +# c.colors.downloads.start.bg = '#0000aa' + +## Color gradient start for download text. +## Type: QtColor +# c.colors.downloads.start.fg = 'white' + +## Color gradient stop for download backgrounds. +## Type: QtColor +# c.colors.downloads.stop.bg = '#00aa00' + +## Color gradient end for download text. +## Type: QtColor +# c.colors.downloads.stop.fg = 'white' + +## Color gradient interpolation system for download backgrounds. +## Type: ColorSystem +## Valid values: +## - rgb: Interpolate in the RGB color system. +## - hsv: Interpolate in the HSV color system. +## - hsl: Interpolate in the HSL color system. +## - none: Don't show a gradient. +# c.colors.downloads.system.bg = 'rgb' + +## Color gradient interpolation system for download text. +## Type: ColorSystem +## Valid values: +## - rgb: Interpolate in the RGB color system. +## - hsv: Interpolate in the HSV color system. +## - hsl: Interpolate in the HSL color system. +## - none: Don't show a gradient. +# c.colors.downloads.system.fg = 'rgb' + +## Background color for hints. Note that you can use a `rgba(...)` value +## for transparency. +## Type: QssColor +# c.colors.hints.bg = 'qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 247, 133, 0.8), stop:1 rgba(255, 197, 66, 0.8))' + +## Font color for hints. +## Type: QssColor +# c.colors.hints.fg = 'black' + +## Font color for the matched part of hints. +## Type: QtColor +# c.colors.hints.match.fg = 'green' + +## Background color of the keyhint widget. +## Type: QssColor +# c.colors.keyhint.bg = 'rgba(0, 0, 0, 80%)' + +## Text color for the keyhint widget. +## Type: QssColor +# c.colors.keyhint.fg = '#FFFFFF' + +## Highlight color for keys to complete the current keychain. +## Type: QssColor +# c.colors.keyhint.suffix.fg = '#FFFF00' + +## Background color of an error message. +## Type: QssColor +# c.colors.messages.error.bg = 'red' + +## Border color of an error message. +## Type: QssColor +# c.colors.messages.error.border = '#bb0000' + +## Foreground color of an error message. +## Type: QssColor +# c.colors.messages.error.fg = 'white' + +## Background color of an info message. +## Type: QssColor +# c.colors.messages.info.bg = 'black' + +## Border color of an info message. +## Type: QssColor +# c.colors.messages.info.border = '#333333' + +## Foreground color of an info message. +## Type: QssColor +# c.colors.messages.info.fg = 'white' + +## Background color of a warning message. +## Type: QssColor +# c.colors.messages.warning.bg = 'darkorange' + +## Border color of a warning message. +## Type: QssColor +# c.colors.messages.warning.border = '#d47300' + +## Foreground color of a warning message. +## Type: QssColor +# c.colors.messages.warning.fg = 'black' + +## Background color for prompts. +## Type: QssColor +# c.colors.prompts.bg = '#444444' + +## Border used around UI elements in prompts. +## Type: String +# c.colors.prompts.border = '1px solid gray' + +## Foreground color for prompts. +## Type: QssColor +# c.colors.prompts.fg = 'white' + +## Background color for the selected item in filename prompts. +## Type: QssColor +# c.colors.prompts.selected.bg = 'grey' + +## Foreground color for the selected item in filename prompts. +## Type: QssColor +# c.colors.prompts.selected.fg = 'white' + +## Background color of the statusbar in caret mode. +## Type: QssColor +# c.colors.statusbar.caret.bg = 'purple' + +## Foreground color of the statusbar in caret mode. +## Type: QssColor +# c.colors.statusbar.caret.fg = 'white' + +## Background color of the statusbar in caret mode with a selection. +## Type: QssColor +# c.colors.statusbar.caret.selection.bg = '#a12dff' + +## Foreground color of the statusbar in caret mode with a selection. +## Type: QssColor +# c.colors.statusbar.caret.selection.fg = 'white' + +## Background color of the statusbar in command mode. +## Type: QssColor +# c.colors.statusbar.command.bg = 'black' + +## Foreground color of the statusbar in command mode. +## Type: QssColor +# c.colors.statusbar.command.fg = 'white' + +## Background color of the statusbar in private browsing + command mode. +## Type: QssColor +# c.colors.statusbar.command.private.bg = 'darkslategray' + +## Foreground color of the statusbar in private browsing + command mode. +## Type: QssColor +# c.colors.statusbar.command.private.fg = 'white' + +## Background color of the statusbar in insert mode. +## Type: QssColor +# c.colors.statusbar.insert.bg = 'darkgreen' + +## Foreground color of the statusbar in insert mode. +## Type: QssColor +# c.colors.statusbar.insert.fg = 'white' + +## Background color of the statusbar. +## Type: QssColor +# c.colors.statusbar.normal.bg = 'black' + +## Foreground color of the statusbar. +## Type: QssColor +# c.colors.statusbar.normal.fg = 'white' + +## Background color of the statusbar in passthrough mode. +## Type: QssColor +# c.colors.statusbar.passthrough.bg = 'darkblue' + +## Foreground color of the statusbar in passthrough mode. +## Type: QssColor +# c.colors.statusbar.passthrough.fg = 'white' + +## Background color of the statusbar in private browsing mode. +## Type: QssColor +# c.colors.statusbar.private.bg = '#666666' + +## Foreground color of the statusbar in private browsing mode. +## Type: QssColor +# c.colors.statusbar.private.fg = 'white' + +## Background color of the progress bar. +## Type: QssColor +# c.colors.statusbar.progress.bg = 'white' + +## Foreground color of the URL in the statusbar on error. +## Type: QssColor +# c.colors.statusbar.url.error.fg = 'orange' + +## Default foreground color of the URL in the statusbar. +## Type: QssColor +# c.colors.statusbar.url.fg = 'white' + +## Foreground color of the URL in the statusbar for hovered links. +## Type: QssColor +# c.colors.statusbar.url.hover.fg = 'aqua' + +## Foreground color of the URL in the statusbar on successful load +## (http). +## Type: QssColor +# c.colors.statusbar.url.success.http.fg = 'white' + +## Foreground color of the URL in the statusbar on successful load +## (https). +## Type: QssColor +# c.colors.statusbar.url.success.https.fg = 'lime' + +## Foreground color of the URL in the statusbar when there's a warning. +## Type: QssColor +# c.colors.statusbar.url.warn.fg = 'yellow' + +## Background color of the tab bar. +## Type: QssColor +# c.colors.tabs.bar.bg = '#555555' + +## Background color of unselected even tabs. +## Type: QtColor +# c.colors.tabs.even.bg = 'darkgrey' + +## Foreground color of unselected even tabs. +## Type: QtColor +# c.colors.tabs.even.fg = 'white' + +## Color for the tab indicator on errors. +## Type: QtColor +# c.colors.tabs.indicator.error = '#ff0000' + +## Color gradient start for the tab indicator. +## Type: QtColor +# c.colors.tabs.indicator.start = '#0000aa' + +## Color gradient end for the tab indicator. +## Type: QtColor +# c.colors.tabs.indicator.stop = '#00aa00' + +## Color gradient interpolation system for the tab indicator. +## Type: ColorSystem +## Valid values: +## - rgb: Interpolate in the RGB color system. +## - hsv: Interpolate in the HSV color system. +## - hsl: Interpolate in the HSL color system. +## - none: Don't show a gradient. +# c.colors.tabs.indicator.system = 'rgb' + +## Background color of unselected odd tabs. +## Type: QtColor +# c.colors.tabs.odd.bg = 'grey' + +## Foreground color of unselected odd tabs. +## Type: QtColor +# c.colors.tabs.odd.fg = 'white' + +## Background color of pinned unselected even tabs. +## Type: QtColor +# c.colors.tabs.pinned.even.bg = 'darkseagreen' + +## Foreground color of pinned unselected even tabs. +## Type: QtColor +# c.colors.tabs.pinned.even.fg = 'white' + +## Background color of pinned unselected odd tabs. +## Type: QtColor +# c.colors.tabs.pinned.odd.bg = 'seagreen' + +## Foreground color of pinned unselected odd tabs. +## Type: QtColor +# c.colors.tabs.pinned.odd.fg = 'white' + +## Background color of pinned selected even tabs. +## Type: QtColor +# c.colors.tabs.pinned.selected.even.bg = 'black' + +## Foreground color of pinned selected even tabs. +## Type: QtColor +# c.colors.tabs.pinned.selected.even.fg = 'white' + +## Background color of pinned selected odd tabs. +## Type: QtColor +# c.colors.tabs.pinned.selected.odd.bg = 'black' + +## Foreground color of pinned selected odd tabs. +## Type: QtColor +# c.colors.tabs.pinned.selected.odd.fg = 'white' + +## Background color of selected even tabs. +## Type: QtColor +# c.colors.tabs.selected.even.bg = 'black' + +## Foreground color of selected even tabs. +## Type: QtColor +# c.colors.tabs.selected.even.fg = 'white' + +## Background color of selected odd tabs. +## Type: QtColor +# c.colors.tabs.selected.odd.bg = 'black' + +## Foreground color of selected odd tabs. +## Type: QtColor +# c.colors.tabs.selected.odd.fg = 'white' + +## Background color for webpages if unset (or empty to use the theme's +## color). +## Type: QtColor +# c.colors.webpage.bg = 'white' + +## Which algorithm to use for modifying how colors are rendered with +## darkmode. The `lightness-cielab` value was added with QtWebEngine 5.14 +## and is treated like `lightness-hsl` with older QtWebEngine versions. +## Type: String +## Valid values: +## - lightness-cielab: Modify colors by converting them to CIELAB color space and inverting the L value. Not available with Qt < 5.14. +## - lightness-hsl: Modify colors by converting them to the HSL color space and inverting the lightness (i.e. the "L" in HSL). +## - brightness-rgb: Modify colors by subtracting each of r, g, and b from their maximum value. +# c.colors.webpage.darkmode.algorithm = 'lightness-cielab' + +## Contrast for dark mode. This only has an effect when +## `colors.webpage.darkmode.algorithm` is set to `lightness-hsl` or +## `brightness-rgb`. +## Type: Float +# c.colors.webpage.darkmode.contrast = 0.0 + +## Render all web contents using a dark theme. Example configurations +## from Chromium's `chrome://flags`: - "With simple HSL/CIELAB/RGB-based +## inversion": Set `colors.webpage.darkmode.algorithm` accordingly. - +## "With selective image inversion": Set +## `colors.webpage.darkmode.policy.images` to `smart`. - "With selective +## inversion of non-image elements": Set +## `colors.webpage.darkmode.threshold.text` to 150 and +## `colors.webpage.darkmode.threshold.background` to 205. - "With +## selective inversion of everything": Combines the two variants above. +## Type: Bool +# c.colors.webpage.darkmode.enabled = False + +## Render all colors as grayscale. This only has an effect when +## `colors.webpage.darkmode.algorithm` is set to `lightness-hsl` or +## `brightness-rgb`. +## Type: Bool +# c.colors.webpage.darkmode.grayscale.all = False + +## Desaturation factor for images in dark mode. If set to 0, images are +## left as-is. If set to 1, images are completely grayscale. Values +## between 0 and 1 desaturate the colors accordingly. +## Type: Float +# c.colors.webpage.darkmode.grayscale.images = 0.0 + +## Which images to apply dark mode to. With QtWebEngine 5.15.0, this +## setting can cause frequent renderer process crashes due to a +## https://codereview.qt-project.org/c/qt/qtwebengine- +## chromium/+/304211[bug in Qt]. +## Type: String +## Valid values: +## - always: Apply dark mode filter to all images. +## - never: Never apply dark mode filter to any images. +## - smart: Apply dark mode based on image content. Not available with Qt 5.15.0. +# c.colors.webpage.darkmode.policy.images = 'smart' + +## Which pages to apply dark mode to. The underlying Chromium setting has +## been removed in QtWebEngine 5.15.3, thus this setting is ignored +## there. Instead, every element is now classified individually. +## Type: String +## Valid values: +## - always: Apply dark mode filter to all frames, regardless of content. +## - smart: Apply dark mode filter to frames based on background color. +# c.colors.webpage.darkmode.policy.page = 'smart' + +## Threshold for inverting background elements with dark mode. Background +## elements with brightness above this threshold will be inverted, and +## below it will be left as in the original, non-dark-mode page. Set to +## 256 to never invert the color or to 0 to always invert it. Note: This +## behavior is the opposite of `colors.webpage.darkmode.threshold.text`! +## Type: Int +# c.colors.webpage.darkmode.threshold.background = 0 + +## Threshold for inverting text with dark mode. Text colors with +## brightness below this threshold will be inverted, and above it will be +## left as in the original, non-dark-mode page. Set to 256 to always +## invert text color or to 0 to never invert text color. +## Type: Int +# c.colors.webpage.darkmode.threshold.text = 256 + +## Value to use for `prefers-color-scheme:` for websites. The "light" +## value is only available with QtWebEngine 5.15.2+. On older versions, +## it is the same as "auto". The "auto" value is broken on QtWebEngine +## 5.15.2 due to a Qt bug. There, it will fall back to "light" +## unconditionally. +## Type: String +## Valid values: +## - auto: Use the system-wide color scheme setting. +## - light: Force a light theme. +## - dark: Force a dark theme. +# c.colors.webpage.preferred_color_scheme = 'auto' + +## Number of commands to save in the command history. 0: no history / -1: +## unlimited +## Type: Int +# c.completion.cmd_history_max_items = 100 + +## Delay (in milliseconds) before updating completions after typing a +## character. +## Type: Int +# c.completion.delay = 0 + +## Default filesystem autocomplete suggestions for :open. The elements of +## this list show up in the completion window under the Filesystem +## category when the command line contains `:open` but no argument. +## Type: List of String +# c.completion.favorite_paths = [] + +## Height (in pixels or as percentage of the window) of the completion. +## Type: PercOrInt +# c.completion.height = '50%' + +## Minimum amount of characters needed to update completions. +## Type: Int +# c.completion.min_chars = 1 + +## Which categories to show (in which order) in the :open completion. +## Type: FlagList +## Valid values: +## - searchengines +## - quickmarks +## - bookmarks +## - history +## - filesystem +# c.completion.open_categories = ['searchengines', 'quickmarks', 'bookmarks', 'history', 'filesystem'] + +## Move on to the next part when there's only one possible completion +## left. +## Type: Bool +# c.completion.quick = True + +## Padding (in pixels) of the scrollbar handle in the completion window. +## Type: Int +# c.completion.scrollbar.padding = 2 + +## Width (in pixels) of the scrollbar in the completion window. +## Type: Int +# c.completion.scrollbar.width = 12 + +## When to show the autocompletion window. +## Type: String +## Valid values: +## - always: Whenever a completion is available. +## - auto: Whenever a completion is requested. +## - never: Never. +# c.completion.show = 'always' + +## Shrink the completion to be smaller than the configured size if there +## are no scrollbars. +## Type: Bool +# c.completion.shrink = False + +## Format of timestamps (e.g. for the history completion). See +## https://sqlite.org/lang_datefunc.html and +## https://docs.python.org/3/library/datetime.html#strftime-strptime- +## behavior for allowed substitutions, qutebrowser uses both sqlite and +## Python to format its timestamps. +## Type: String +# c.completion.timestamp_format = '%Y-%m-%d %H:%M' + +## Execute the best-matching command on a partial match. +## Type: Bool +# c.completion.use_best_match = False + +## A list of patterns which should not be shown in the history. This only +## affects the completion. Matching URLs are still saved in the history +## (and visible on the `:history` page), but hidden in the completion. +## Changing this setting will cause the completion history to be +## regenerated on the next start, which will take a short while. +## Type: List of UrlPattern +# c.completion.web_history.exclude = [] + +## Number of URLs to show in the web history. 0: no history / -1: +## unlimited +## Type: Int +# c.completion.web_history.max_items = -1 + +## Require a confirmation before quitting the application. +## Type: ConfirmQuit +## Valid values: +## - always: Always show a confirmation. +## - multiple-tabs: Show a confirmation if multiple tabs are opened. +## - downloads: Show a confirmation if downloads are running +## - never: Never show a confirmation. +# c.confirm_quit = ['never'] + +## Automatically start playing `