summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcashmere <cashmere@autistici.org>2025-11-30 23:42:52 +0100
committercashmere <cashmere@autistici.org>2025-11-30 23:42:52 +0100
commitc2b797fd4b8133cc1cb4cec06579978a7a95893d (patch)
tree06f43da8eb92f18da516b1cde9d3704b86871ed8
parentabce1d8310509524f7a04e9ef95b6f8afdf653b8 (diff)
parentfe6454921434991977fffd3458a49efb6b737ed4 (diff)
downloademacs-c2b797fd4b8133cc1cb4cec06579978a7a95893d.tar.gz
Merge remote-tracking branch 'origin/master'
-rw-r--r--config.el11
-rw-r--r--config.org19
-rw-r--r--flycheck_config.el2595
3 files changed, 2621 insertions, 4 deletions
diff --git a/config.el b/config.el
index 5b4d274..232c997 100644
--- a/config.el
+++ b/config.el
@@ -1894,11 +1894,11 @@ completion-category-overrides '((file (styles partial-completion))))) ;; Customi
(defvar cashmere/font-height 140)
(set-face-attribute 'default nil :family "JetBrainsMono Nerd Font" :weight 'regular :height cashmere/font-height)
-(set-face-attribute 'fixed-pitch nil :family "Poppins" :weight 'regular)
+(set-face-attribute 'fixed-pitch nil :family "RobotoMono Nerd Font" :weight 'regular)
(set-face-attribute 'variable-pitch nil :family "Poppins" :weight 'regular :height 1.1)
(use-package mixed-pitch
- :straight t
+ :ensure t
:defer t
:hook ((org-mode . mixed-pitch-mode)
(LaTeX-mode . mixed-pitch-mode)))
@@ -2081,6 +2081,13 @@ completion-category-overrides '((file (styles partial-completion))))) ;; Customi
(setq delete-by-moving-to-trash t)
(setq dired-mouse-drag-files t))
+(use-package dired-rsync
+ :ensure t)
+
+(use-package dired-rsync-transient
+ :ensure t
+ :after (dired-rsync transient))
+
(setq-default olivetti-body-width 130)
(define-globalized-minor-mode my/global-olivetti-mode olivetti-mode
(lambda () (olivetti-mode 1)))
diff --git a/config.org b/config.org
index 54bb21f..5e951ce 100644
--- a/config.org
+++ b/config.org
@@ -2396,11 +2396,11 @@ ily <3.
(defvar cashmere/font-height 140)
(set-face-attribute 'default nil :family "JetBrainsMono Nerd Font" :weight 'regular :height cashmere/font-height)
-(set-face-attribute 'fixed-pitch nil :family "Poppins" :weight 'regular)
+(set-face-attribute 'fixed-pitch nil :family "RobotoMono Nerd Font" :weight 'regular)
(set-face-attribute 'variable-pitch nil :family "Poppins" :weight 'regular :height 1.1)
(use-package mixed-pitch
- :straight t
+ :ensure t
:defer t
:hook ((org-mode . mixed-pitch-mode)
(LaTeX-mode . mixed-pitch-mode)))
@@ -2608,6 +2608,21 @@ ily <3.
(setq dired-mouse-drag-files t))
#+end_src
+* rsync
+
+#+begin_src emacs-lisp
+(use-package dired-rsync
+ :ensure t)
+#+end_src
+
+** rsync-transient
+
+#+begin_src emacs-lisp
+(use-package dired-rsync-transient
+ :ensure t
+ :after (dired-rsync transient))
+#+end_src
+
* my/fns
#+begin_src emacs-lisp
diff --git a/flycheck_config.el b/flycheck_config.el
new file mode 100644
index 0000000..232c997
--- /dev/null
+++ b/flycheck_config.el
@@ -0,0 +1,2595 @@
+;;; config.el --- Emacs-Kick --- A feature rich Emacs config for (neo)vi(m)mers -*- lexical-binding: t; -*-
+;; (setenv "LSP_USE_PLISTS" "true")
+;; (setq debug-on-error '(wrong-type-argument))
+;; (setq gc-cons-threshold #x40000000)
+;; (setq gc-cons-threshold 50000000)
+;; (setenv "LSP_USE_PLISTS" "true")
+(setq lsp-use-plists t)
+(setq default-frame-alist '((undecorated . t)))
+(setq gc-cons-threshold 100000000)
+
+(add-hook 'emacs-startup-hook
+ (lambda () (setq gc-cons-threshold (* 50 1024 1024))))
+(setq create-lockfiles nil)
+(setq make-backup-files nil)
+
+(setq backup-directory-alist
+ `(("." . ,(expand-file-name "backup" user-emacs-directory))))
+(setq tramp-backup-directory-alist backup-directory-alist)
+
+(setq backup-by-copying-when-linked t)
+(setq backup-by-copying t) ; Backup by copying rather renaming
+(setq delete-old-versions t) ; Delete excess backup versions silently
+(setq version-control t) ; Use version numbers for backup files
+(setq kept-new-versions 5)
+(setq kept-old-versions 5)
+
+(defvar yy/cache-2 nil)
+
+(defun yy/load-cache ()
+ (setq yy/cache-2
+ (condition-case e
+ (car (read-from-string
+ (with-temp-buffer
+ (insert-file-contents
+ (file-name-concat user-emacs-directory "ycache.eld"))
+ (buffer-substring (point-min) (point-max)))))
+ (error nil))))
+ ;;(make-hash-table :test #'equal))))
+(yy/load-cache)
+
+(defun yy/load-path-filter (path file suffixes)
+ (if-let* ((ls (with-memoization (alist-get file yy/cache-2 nil nil #'equal)
+ (let ((res (load-path-filter-cache-directory-files path file suffixes)))
+ (if (eq res path) nil res)))))
+ ls path))
+
+(defun yy/write-cache ()
+ (interactive)
+ (when yy/cache-2
+ (with-temp-file (file-name-concat user-emacs-directory "ycache.eld")
+ (pp yy/cache-2 (current-buffer)))))
+
+(yy/load-cache)
+
+(setq load-path-filter-function #'yy/load-path-filter)
+
+(use-package emacs
+ :straight nil
+ :ensure nil
+ :custom ;; Set custom variables to configure Emacs behavior.
+ (setq modify-coding-system-alist 'file "" 'utf-8)
+ (column-number-mode t) ;; Display the column number in the mode line.
+ (auto-save-default nil) ;; Disable automatic saving of buffers.
+ (create-lockfiles nil) ;; Prevent the creation of lock files when editing.
+ (delete-by-moving-to-trash t) ;; Move deleted files to the trash instead of permanently deleting them.
+ (delete-selection-mode 1) ;; Enable replacing selected text with typed text.
+ (display-line-numbers-type 'relative) ;; Use relative line numbering in programming modes.
+ (global-auto-revert-non-file-buffers t) ;; Automatically refresh non-file buffers.
+ (history-length 25) ;; Set the length of the command history.
+ (inhibit-startup-message t) ;; Disable the startup message when Emacs launches.
+ (initial-scratch-message "") ;; Clear the initial message in the *scratch* buffer.
+ (ispell-dictionary "en_US") ;; Set the default dictionary for spell checking.
+ (make-backup-files nil) ;; Disable creation of backup files.
+ ;; (pixel-scroll-precision-mode t) ;; Enable precise pixel scrolling.
+ (pixel-scroll-precision-use-momentum nil) ;; Disable momentum scrolling for pixel precision.
+ (ring-bell-function 'ignore) ;; Disable the audible bell.
+ (split-width-threshold 300) ;; Prevent automatic window splitting if the window width exceeds 300 pixels.
+ (switch-to-buffer-obey-display-actions t) ;; Make buffer switching respect display actions.
+ (tab-always-indent 'complete) ;; Make the TAB key complete text instead of just indenting.
+ (tab-width 4) ;; Set the tab width to 4 spaces.
+ (treesit-font-lock-level 4) ;; Use advanced font locking for Treesit mode.
+ (truncate-lines t) ;; Enable line truncation to avoid wrapping long lines.
+ (use-dialog-box nil) ;; Disable dialog boxes in favor of minibuffer prompts.
+ (use-short-answers t) ;; Use short answers in prompts for quicker responses (y instead of yes)
+ (warning-minimum-level :emergency) ;; Set the minimum level of warnings to display.
+
+ :hook ;; Add hooks to enable specific features in certain modes.
+ (prog-mode . display-line-numbers-mode)
+ (org-mode . display-line-numbers-mode)
+
+ :config
+ (add-to-list 'custom-theme-load-path user-emacs-directory)
+ ;; (load-theme 'rose-pine t)
+
+ ;; By default emacs gives you access to a lot of *special* buffers, while navigating with [b and ]b,
+ ;; this might be confusing for newcomers. This settings make sure ]b and [b will always load a
+ ;; file buffer. To see all buffers use <leader> SPC, <leader> b l, or <leader> b i.
+ (defun skip-these-buffers (_window buffer _bury-or-kill)
+ "Function for `switch-to-prev-buffer-skip'."
+ (string-match "\\*[^*]+\\*" (buffer-name buffer)))
+ (setq switch-to-prev-buffer-skip 'skip-these-buffers)
+
+(setq switch-to-prev-buffer-skip-regexp
+ '("\\*[^*]+\\*" "^magit" "^\\*magit"))
+
+ ;; Configure font settings based on the operating system.
+ ;; Ok, this kickstart is meant to be used on the terminal, not on GUI.
+ ;; But without this, I fear you could start Graphical Emacs and be sad :(
+ ;; (set-face-attribute 'default nil :family "Maple Mono NF" :height 150)
+ ;; (when (eq system-type 'darwin) ;; Check if the system is macOS.
+ ;; (setq mac-command-modifier 'meta) ;; Set the Command key to act as the Meta key.
+ ;; (set-face-attribute 'default nil :family "Fragment Mono" :height 130))
+
+ ;; Save manual customizations to a separate file instead of cluttering `init.el'.
+ ;; You can M-x customize, M-x customize-group, or M-x customize-themes, etc.
+ ;; The saves you do manually using the Emacs interface would overwrite this file.
+ ;; The following makes sure those customizations are in a separate file.
+ (setq custom-file (locate-user-emacs-file "custom-vars.el")) ;; Specify the custom file path.
+ (load custom-file 'noerror 'nomessage) ;; Load the custom file quietly, ignoring errors.
+
+ ;; Makes Emacs vertical divisor the symbol │ instead of |.
+ (set-display-table-slot standard-display-table 'vertical-border (make-glyph-code ?│))
+
+ :init ;; Initialization settings that apply before the package is loaded.
+ (tool-bar-mode -1)
+
+ (menu-bar-mode -1)
+ (scroll-bar-mode -1)
+ (add-to-list 'default-frame-alist '(vertical-scroll-bars . nil))
+ (add-to-list 'default-frame-alist '(horizontal-scroll-bars . nil))
+ (set-frame-parameter (selected-frame) 'alpha-background 80)
+ (add-to-list 'default-frame-alist '(alpha-background . 80))
+ (global-hl-line-mode -1) ;; Disable highlight of the current line
+ (global-auto-revert-mode 1) ;; Enable global auto-revert mode to keep buffers up to date with their corresponding files.
+ (indent-tabs-mode -1) ;; Disable the use of tabs for indentation (use spaces instead).
+ (recentf-mode 1) ;; Enable tracking of recently opened files.
+ (savehist-mode 1) ;; Enable saving of command history.
+ (save-place-mode 1) ;; Enable saving the place in files for easier return.
+ (winner-mode 1) ;; Enable winner mode to easily undo window configuration changes.
+ (xterm-mouse-mode 1) ;; Enable mouse support in terminal mode.
+ (file-name-shadow-mode 1) ;; Enable shadowing of filenames for clarity.
+
+ ;;oding system for files to UTF-8.
+ (modify-coding-system-alist 'file "" 'utf-8)
+
+ ;; Add a hook to run code after Emacs has fully initialized.
+ (add-hook 'after-init-hook
+ (lambda ()
+ (message "Emacs has fully loaded. This code runs after startup.")
+
+ ;; Insert a welcome message in the *scratch* buffer displaying loading time and activated packages.
+ (with-current-buffer (get-buffer-create "*scratch*")
+ (insert (format
+ " ;; Welcome to Emacs!
+ ;;
+ ;; Loading time : %s
+ ;; Packages : %s
+ "
+ (emacs-init-time)
+ (length (hash-table-keys straight--recipe-cache))))))))
+
+(defcustom ek-use-nerd-fonts t
+ "Configuration for using Nerd Fonts Symbols."
+ :type 'boolean
+ :group 'appearance)
+
+;; (setq wl-copy-process nil)
+;; (defun wl-copy (text)
+;; (setq wl-copy-process (make-process :name "wl-copy"
+;; :buffer nil
+;; :command '("wl-copy" "-f" "-n")
+;; :connection-type 'pipe
+;; :noquery t))
+;; (process-send-string wl-copy-process text)
+;; (process-send-eof wl-copy-process))
+;; (defun wl-paste ()
+;; (if (and wl-copy-process (process-live-p wl-copy-process))
+;; nil ; should return nil if we're the current paste owner
+;; (shell-command-to-string "wl-paste -n | tr -d \r")))
+;; (setq interprogram-cut-function 'wl-copy)
+;; (setq interprogram-paste-function 'wl-paste)
+
+(use-package window
+ :straight nil
+ :ensure nil
+ :custom
+ (display-buffer-alist
+ '(
+ ("\\*\\(Backtrace\\|Warnings\\|Compile-Log\\|[Hh]elp\\|Messages\\|Bookmark List\\|Occur\\)\\*"
+ (display-buffer-in-side-window)
+ (window-height . 0.25)
+ (side . bottom)
+ (slot . 0))
+
+ ("\\*\\(eldoc\\)\\*"
+ (display-buffer-in-side-window)
+ (window-height . 0.25)
+ (side . bottom)
+ (slot . 1)
+ (window-parameters . ((no-delete-other-windows . t)))
+ (body-function . (lambda (window)
+ (select-window window))))
+
+ ("\\*\\(Flymake diagnostics\\|xref\\|ivy\\|Swiper\\|Completions\\)"
+ (display-buffer-in-side-window)
+ (window-height . 0.25)
+ (side . bottom)
+ (slot . 1)))))
+
+(use-package dired
+ :straight nil
+ :ensure nil
+ :custom
+ (dired-listing-switches "-lah --group-directories-first")
+ (dired-dwim-target t)
+ (dired-guess-shell-alist-user
+ '(("\\.\\(png\\|jpe?g\\|tiff\\)" "feh" "xdg-open" "open")
+ ("\\.\\(mp[34]\\|m4a\\|ogg\\|flac\\|webm\\|mkv\\)" "mpv" "xdg-open" "open")
+ (".*" "open" "xdg-open")))
+ (dired-kill-when-opening-new-dired-buffer t)
+ :config
+ ;; (dired-async-mode 1)
+ (when (eq system-type 'darwin)
+ (let ((gls (executable-find "gls")))
+ (when gls
+ (setq insert-directory-program gls)))))
+
+(use-package erc
+ :straight nil
+ :defer t ;; Load ERC when needed rather than at startup. (Load it with `M-x erc RET')
+ :custom
+ (erc-join-buffer 'window) ;; Open a new window for joining channels.
+ (erc-hide-list '("JOIN" "PART" "QUIT")) ;; Hide messages for joins, parts, and quits to reduce clutter.
+ (erc-timestamp-format "[%H:%M]") ;; Format for timestamps in messages.
+ (erc-autojoin-channels-alist '((".*\\.libera\\.chat" "#emacs"))));; Automatically join the #emacs channel on Libera.Chat.
+
+(defvar my/centered-cursor-enabled nil)
+
+(defun my/centered-cursor ()
+ (interactive)
+ (if my/centered-cursor-enabled
+ (progn
+ (setq scroll-preserve-screen-position nil
+ scroll-conservatively 0
+ maximum-scroll-margin 0.0
+ scroll-margin 0)
+ (setq my/centered-cursor-enabled nil)
+ (message "centered-cursor off"))
+ (progn
+ (setq scroll-preserve-screen-position t
+ scroll-conservatively 0
+ maximum-scroll-margin 0.5
+ scroll-margin 99999)
+ (setq my/centered-cursor-enabled t)
+ (message "centered-cursor on"))))
+
+(use-package cursory
+ :ensure t
+ :demand t
+ :if (display-graphic-p)
+ :config
+ (setq cursory-presets
+ '((box
+ :cursor-color success ; will typically be green
+ :blink-cursor-interval 1.2)
+ (box-no-blink
+ :inherit box
+ :blink-cursor-mode -1)
+ (bar
+ :cursor-type (bar . 2)
+ :cursor-color error ; will typically be red
+ :blink-cursor-interval 0.8)
+ (bar-no-other-window
+ :inherit bar
+ :cursor-in-non-selected-windows nil)
+ (bar-no-blink
+ :inherit bar
+ :blink-cursor-mode -1)
+ (underscore
+ :cursor-color warning ; will typically be yellow
+ :cursor-type (hbar . 3)
+ :blink-cursor-interval 0.3
+ :blink-cursor-blinks 50)
+ (underscore-no-other-window
+ :inherit underscore
+ :cursor-in-non-selected-windows nil)
+ (underscore-thick
+ :inherit underscore
+ :cursor-type (hbar . 8)
+ :cursor-in-non-selected-windows (hbar . 3))
+ (t ; the default values
+ :cursor-color unspecified ; use the theme's original
+ :cursor-type box
+ :cursor-in-non-selected-windows hollow
+ :blink-cursor-mode 1
+ :blink-cursor-blinks 10
+ :blink-cursor-interval 0.2
+ :blink-cursor-delay 0.2)))
+
+ ;; I am using the default value of `cursory-latest-state-file'.
+
+ ;; Set last preset or fall back to desired style from
+ ;; `cursory-presets'. Alternatively, use the function
+ ;; `cursory-set-last-or-fallback' (can be added to the
+ ;; `after-init-hook'.
+ (cursory-set-preset (or (cursory-restore-latest-preset) 'box))
+
+ ;; Persist configurations between Emacs sessions. Also apply the
+ ;; :cursor-color again when swithcing to another theme.
+ (cursory-mode 1)
+ :bind
+ ;; We have to use the "point" mnemonic, because C-c c is often the
+ ;; suggested binding for `org-capture' and is the one I use as well.
+ ("C-c p" . cursory-set-preset))
+
+(use-package clipetty
+ :ensure t
+ :hook (after-init . global-clipetty-mode))
+
+(use-package isearch
+ :straight nil
+ :ensure nil ;; This is built-in, no need to fetch it.
+ :config
+ (setq isearch-lazy-count t) ;; Enable lazy counting to show current match information.
+ (setq lazy-count-prefix-format "(%s/%s) ") ;; Format for displaying current match count.
+ (setq lazy-count-suffix-format nil) ;; Disable suffix formatting for match count.
+ (setq search-whitespace-regexp ".*?") ;; Allow searching across whitespace.
+ :bind (("C-s" . isearch-forward) ;; Bind C-s to forward isearch.
+ ("C-r" . isearch-backward))) ;; Bind C-r to backward isearch.
+
+(use-package vc
+ :straight nil
+ :ensure nil ;; This is built-in, no need to fetch it.
+ :defer t
+ :bind
+ (("C-x v d" . vc-dir) ;; Open VC directory for version control status.
+ ("C-x v =" . vc-diff) ;; Show differences for the current file.
+ ("C-x v D" . vc-root-diff) ;; Show differences for the entire repository.
+ ("C-x v v" . vc-next-action)) ;; Perform the next version control action.
+ :config
+ ;; Better colors for <leader> g b (blame file)
+ (setq vc-annotate-color-map
+ '((20 . "#f5e0dc")
+ (40 . "#f2cdcd")
+ (60 . "#f5c2e7")
+ (80 . "#cba6f7")
+ (100 . "#f38ba8")
+ (120 . "#eba0ac")
+ (140 . "#fab387")
+ (160 . "#f9e2af")
+ (180 . "#a6e3a1")
+ (200 . "#94e2d5")
+ (220 . "#89dceb")
+ (240 . "#74c7ec")
+ (260 . "#89b4fa")
+ (280 . "#b4befe"))))
+
+(use-package ibuffer
+ :straight nil
+ :config
+ (setq ibuffer-expert t)
+ (setq ibuffer-display-summary nil)
+ (setq ibuffer-use-other-window nil)
+ (setq ibuffer-show-empty-filter-groups nil)
+ (setq ibuffer-default-sorting-mode 'filename/process)
+ (setq ibuffer-title-face 'font-lock-doc-face)
+ (setq ibuffer-use-header-line t)
+ (setq ibuffer-default-shrink-to-minimum-size nil)
+ (setq ibuffer-formats
+ '((mark modified read-only locked " "
+ (name 30 30 :left :elide)
+ " "
+ (size 9 -1 :right)
+ " "
+ (mode 16 16 :left :elide)
+ " " filename-and-process)
+ (mark " "
+ (name 16 -1)
+ " " filename)))
+ (setq ibuffer-saved-filter-groups
+ '(("Main"
+ ("Directories" (mode . dired-mode))
+ ("Rust" (or
+ (mode . rust-mode)
+ (mode . rust-ts-mode)))
+ ("Python" (or
+ (mode . python-ts-mode)
+ (mode . c-mode)
+ (mode . python-mode)))
+ ("Nix" (or
+ (mode . nix-mode)
+ (mode . nix-ts-mode)))
+ ("Scripts" (or
+ (mode . shell-script-mode)
+ (mode . shell-mode)
+ (mode . sh-mode)
+ (mode . lua-mode)
+ (mode . bat-mode)))
+ ("Config" (or
+ (mode . conf-mode)
+ (mode . conf-toml-mode)
+ (mode . toml-ts-mode)
+ (mode . conf-windows-mode)
+ (name . "^\\.clangd$")
+ (name . "^\\.gitignore$")
+ (name . "^Doxyfile$")
+ (name . "^config\\.toml$")
+ (mode . yaml-mode)))
+ ("Web" (or
+ (mode . mhtml-mode)
+ (mode . html-mode)
+ (mode . web-mode)
+ (mode . nxml-mode)))
+ ("CSS" (or
+ (mode . css-mode)
+ (mode . sass-mode)))
+ ("JS" (or
+ (mode . js-mode)
+ (mode . rjsx-mode)))
+ ("Markup" (or
+ (mode . markdown-mode)
+ (mode . adoc-mode)))
+ ("Org" (mode . org-mode))
+ ("Terminal" (mode . vterm-mode))
+ ("LaTeX" (name . "\.tex$"))
+ ("Magit" (or
+ (mode . magit-blame-mode)
+ (mode . magit-cherry-mode)
+ (mode . magit-diff-mode)
+ (mode . magit-log-mode)
+ (mode . magit-process-mode)
+ (mode . magit-status-mode)))
+ ("Elfeed" (or
+ (mode . elfeed-search-mode)
+ (mode . elfeed-show-mode)))
+ ("Fundamental" (or
+ (mode . fundamental-mode)
+ (mode . text-mode)))
+ ("Emacs" (or
+ (mode . emacs-lisp-mode)
+ (name . "^\\*Help\\*$")
+ (name . "^\\*Custom.*")
+ (name . "^\\*Org Agenda\\*$")
+ (name . "^\\*info\\*$")
+ (name . "^\\*scratch\\*$")
+ (name . "^\\*Backtrace\\*$")
+ (name . "^\\*Messages\\*$"))))))
+ :hook
+ (ibuffer-mode . (lambda ()
+ (ibuffer-switch-to-saved-filter-groups "Main"))))
+
+(use-package nerd-icons-ibuffer
+ :ensure t
+ :hook (ibuffer-mode . nerd-icons-ibuffer-mode))
+
+(use-package smerge-mode
+ :straight nil
+ :ensure nil ;; This is built-in, no need to fetch it.
+ :defer t
+ :bind (:map smerge-mode-map
+ ("C-c ^ u" . smerge-keep-upper) ;; Keep the changes from the upper version.
+ ("C-c ^ l" . smerge-keep-lower) ;; Keep the changes from the lower version.
+ ("C-c ^ n" . smerge-next) ;; Move to the next conflict.
+ ("C-c ^ p" . smerge-previous))) ;; Move to the previous conflict.
+
+(use-package gptel
+ :ensure t ;; Install from MELPA if not present.
+ :defer t
+ :config
+ (setq my/openrouter-backend
+ (gptel-make-openai
+ "OpenRouter" ; Any name you want
+ :host "openrouter.ai"
+ :endpoint "/api/v1/chat/completions"
+ :stream t
+ :key (lambda () (auth-source-pass-get 'secret "openrouter-api")) ; Retrieves from pass entry
+ :models '(anthropic/claude-haiku-4.5)))
+
+ ;; Set backend, default mode, and list of backends.
+ (setq gptel-backend my/openrouter-backend)
+ (setq gptel-default-mode 'org-mode)
+ (setq gptel-backends (list my/openrouter-backend)))
+
+(use-package eldoc
+ :straight nil
+ :ensure t
+ :config
+ (setq eldoc-idle-delay 0) ;; Automatically fetch doc help
+ (setq eldoc-echo-area-use-multiline-p nil) ;; We use the "K" floating help instead
+ ;; set to t if you want docs on the echo area
+ (setq eldoc-echo-area-display-truncation-message nil)
+ :init
+ (global-eldoc-mode))
+
+(use-package eldoc-box
+ :ensure t
+ :config
+ :defer t)
+
+(use-package flymake
+ :straight nil
+ :ensure nil ;; This is built-in, no need to fetch it.
+ :defer t
+ ;; :hook (prog-mode . flymake-mode)
+ :custom
+ (flymake-margin-indicators-string
+ '((error "!»" compilation-error) (warning "»" compilation-warning)
+ (note "»" compilation-info))))
+
+(setq trusted-content
+ '("~/.emacs.d/config.el"
+ "~/.emacs.d/init.el"))
+
+(use-package flycheck
+ :ensure t
+ :config
+ (add-hook 'after-init-hook #'global-flycheck-mode))
+
+(use-package flycheck-rust
+ :ensure t
+ :config
+ (setq flycheck-rust-check-tests nil)
+ (add-hook 'flycheck-mode-hook #'flycheck-rust-setup))
+
+;; (use-package flyover
+;; :ensure t
+;; :hook (flycheck-mode-hook . flyover-mode))
+
+(use-package xref
+ :straight nil
+ :ensure nil)
+
+(use-package project
+ :straight nil
+ :ensure nil)
+
+(setq org-directory "~/org/")
+(use-package org
+ :straight nil
+ :ensure nil
+ :config
+ (require 'org-tempo)
+
+ (custom-set-faces
+ '(org-document-title ((t (:height 1.6))))
+ '(outline-1 ((t (:height 1.25))))
+ '(outline-2 ((t (:height 1.2))))
+ '(outline-3 ((t (:height 1.2))))
+ '(outline-4 ((t (:height 1.2))))
+ '(outline-5 ((t (:height 1.2))))
+ '(outline-6 ((t (:height 1.2))))
+ '(outline-7 ((t (:height 1.2))))
+ '(outline-8 ((t (:height 1.2))))
+ '(outline-9 ((t (:height 1.2)))))
+
+ (setq org-startup-folded 'nil)
+ (setq org-adapt-indentation t
+ org-hide-leading-stars t
+ org-pretty-entities t
+ org-startup-truncated t
+ org-ellipsis " ")
+ (setq org-src-fontify-natively t
+ org-src-tab-acts-natively t
+ org-edit-src-content-indentation 0)
+ (setq org-log-done t
+ org-auto-align-tags t
+ org-tags-column -80
+ org-fold-catch-invisible-edits 'show-and-error
+ org-special-ctrl-a/e t
+ org-insert-heading-respect-content t)
+
+ (add-hook 'org-mode-hook 'variable-pitch-mode)
+ (add-hook 'org-mode-hook 'org-indent-mode)
+ (add-hook 'org-mode-hook 'visual-line-mode)
+ (add-hook 'org-mode-hook (lambda () (electric-indent-local-mode -1)))
+
+
+ (add-to-list 'font-lock-extra-managed-props 'display)
+ (font-lock-add-keywords 'org-mode
+ `(("^.*?\( \)\(:[[:alnum:]_@#%:]+:\)$"
+ (1 `(face nil
+ display (space :align-to (- right ,(org-string-width (match-string 2)) 3)))
+ prepend))) t))
+
+(use-package org-appear
+ :commands (org-appear-mode)
+ :hook (org-mode . org-appear-mode)
+ :config
+ (setq org-hide-emphasis-markers t) ;; Must be activated for org-appear to work
+ (setq org-appear-autoemphasis t ;; Show bold, italics, verbatim, etc.
+ org-appear-autolinks t ;; Show links
+ org-appear-autosubmarkers t)) ;; Show sub- and superscripts
+
+(setq org-agenda-inhibit-startup t
+ org-agenda-use-tag-inheritance nil
+ org-agenda-dim-blocked-tasks nil
+ org-startup-indented nil
+ org-startup-folded 'overview)
+
+(use-package org-modern
+ :ensure t)
+
+(with-eval-after-load 'org (global-org-modern-mode))
+
+(setq org-modern-star 'fold)
+(setq org-modern-fold-stars '(("◉" . "○")))
+(setq org-modern-star 'replace)
+(setq org-modern-replace-stars "◉○◉○◉")
+
+;; (setq org-agenda-start-on-weekday nil
+;; org-agenda-block-separator nil
+;; org-agenda-remove-tags t)
+
+;; (setq org-agenda-skip-scheduled-if-done t
+;; org-agenda-skip-deadline-if-done t
+;; org-agenda-include-deadlines t
+;; org-agenda-block-separator nil
+;; org-agenda-compact-blocks t
+;; org-agenda-start-day nil
+;; org-agenda-span 1
+;; org-agenda-start-on-weekday nil
+;; org-agenda-hide-tags-regexp "task"
+;; org-agenda-prefix-format
+;; '((agenda . " %i %?-12t% s")
+;; (todo . " %i ")
+;; (tags . " %i ")
+;; (search . " %i ")))
+
+(with-eval-after-load 'org-contrib
+ (org-babel-do-load-languages
+ 'org-babel-load-languages
+ '((emacs-lisp . t)
+ ;; ...
+ (nushell . t)
+ (shell . t))))
+
+(use-package org-noter
+ :ensure t
+ :defer t)
+
+(use-package nov
+ :ensure t
+ :mode ("\\.epub\\'" . nov-mode))
+
+(use-package yequake
+ :custom
+ (yequake-frames
+ '(("org-capture"
+ (buffer-fns . (yequake-org-capture))
+ (width . 0.75)
+ (height . 0.5)
+ ;; (alpha . 0.95)
+ (frame-parameters . ((undecorated . t)
+ (skip-taskbar . t)
+ (sticky . t)))))))
+
+(defun my/org-capture-denote-deadline ()
+ (let* ((context (read-string "Task with deadline: "))
+ (deadline (org-read-date t nil nil "Deadline: "))
+ (file-name (denote nil '("task"))))
+ (find-file file-name)
+ (goto-char (point-min))
+ (forward-line 4)
+ (insert (format "* %s\nDEADLINE: <%s>\n\n" context deadline))
+ (current-buffer)))
+
+(defun my/org-capture-denote-scheduled ()
+ (let* ((context (read-string "Scheduled task: "))
+ (schedule (org-read-date t nil nil "Schedule: "))
+ (file-name (denote nil '("task"))))
+ (find-file file-name)
+ (goto-char (point-min))
+ (forward-line 4)
+ (insert (format "* %s\nSCHEDULED: <%s>\n\n" context schedule))
+ (current-buffer)))
+
+(defun my/org-capture-denote-task ()
+ (let* ((context (read-string "Task: "))
+ (todo-state (completing-read "TODO state: "
+ '("ACTIVE" "NEXT" "TODO" "WAIT" "PLAN" "FUN")))
+ (file-name (denote nil '("task"))))
+ (find-file file-name)
+ (goto-char (point-min))
+ (forward-line 4)
+ (insert (format "\n* %s %s\n\n" todo-state context))
+ (point)))
+
+(with-eval-after-load 'org
+ (setq org-capture-templates
+ '(("t" "Task" plain
+ (function my/org-capture-denote-task)
+ "" :immediate-finish t :jump-to-captured t)
+ ("d" "Deadline" plain
+ (function my/org-capture-denote-deadline)
+ "" :immediate-finish t :jump-to-captured t)
+ ("s" "Scheduled" plain
+ (function my/org-capture-denote-scheduled)
+ "" :immediate-finish t :jump-to-captured t))))
+
+(setq org-agenda-span 'day)
+
+(use-package org-super-agenda
+ :after org-agenda
+ :init
+ :config
+ (org-super-agenda-mode))
+
+(use-package org-ql
+ :ensure t
+ :after org-super-agenda
+ :config
+ (setq org-agenda-custom-commands
+ '(("t" "Task Overview"
+ ((alltodo "" ((org-agenda-overriding-header "")
+ (org-super-agenda-groups
+ '((:discard (:todo "FUN"))
+ (:log t)
+ (:name "ACTIVE"
+ :todo "ACTIVE")
+ (:name "NEXT"
+ :todo "NEXT")
+ (:name "TODO"
+ :todo "TODO")
+ (:name "WAIT"
+ :todo "WAIT")))))))
+ ("w" "Weekly Overview"
+ ((org-ql-block '(and (or (deadline auto)
+ (scheduled :to 7))
+ (not (done))
+ (not (habit)))
+ ((org-ql-block-header "Weekly Tasks")
+ (org-super-agenda-groups
+ '((:name "Deadlines"
+ :deadline t
+ :order 1)
+ (:name "Schedule"
+ :scheduled t
+ :order 2)
+ (:discard (:anything t))))))
+ (org-ql-block '(and (ts-active :from today :to 7 :with-time t)
+ (not (done))
+ (not (habit)))
+ ((org-ql-block-header "Appointments")
+ (org-super-agenda-groups
+ '((:name "This Week"
+ :anything t
+ :order 1)))))
+ (org-ql-block '(and (habit)
+ (not (done)))
+ ((org-ql-block-header "Habits")
+ (org-super-agenda-groups
+ '((:name "Daily Habits"
+ :habit t
+ :order 1)
+ (:discard (:anything t)))))))))))
+
+(setq org-todo-keywords
+ '((sequence "WAIT(w@/!)" "HABIT(h)" "TODO(t)" "NEXT(n)" "|" "DONE(d!)")
+ (sequence "BACKLOG(b)" "PLAN(p)" "READY(r)" "ACTIVE(a)" "REVIEW(v)"
+ "FUN(f)" "|" "COMPLETED(c)" "CANC(k@)")))
+
+(use-package ox-typst
+ :straight (:host github :repo "jmpunkt/ox-typst")
+ :after org)
+
+(use-package org-cliplink
+ :ensure t
+ :defer t)
+
+(use-package org-download
+ :ensure t
+ :hook (org-mode . org-download-enable)
+ :config
+ (setq-default org-download-image-dir "~/org/attachments/")
+ (setq org-download-method 'directory)
+ (setq org-download-timestamp "%Y%m%d-%H%M%S_")
+ (setq org-download-heading-lvl nil))
+
+;; (setq org-publish-project-alist
+;; '(("wiki"
+;; :author "cashmere"
+;; :email "cashmere@cashmere.rs"
+;; :preserve-breaks t
+;; :preserve-indent t
+;; :with-title t
+;; :base-directory "/home/cashmere/wiki/"
+;; :base-extension "org"
+;; :publishing-directory "/home/cashmere/wiki/html/"
+;; :recursive t
+;; :publishing-function org-html-publish-to-html
+;; :with-toc nil
+;; :section-numbers nil
+;; :html-head "<link rel=\"stylesheet\" href=\"/style.css\" type=\"text/css\"/>"
+;; :preparation-function (lambda (_)
+;; (require 'denote-org)
+;; (dolist (file (directory-files-recursively
+;; "/home/cashmere/wiki/" "\\.org$"))
+;; (with-current-buffer (find-file-noselect file)
+;; (ignore-errors
+;; (denote-org-extras-convert-links-to-file-type))
+;; (save-buffer)))))))
+
+(setq org-publish-project-alist
+ '(("wiki"
+ :base-directory "~/wiki"
+ :publishing-directory "~/blog/content/wiki"
+ :publishing-function denote-publish-to-md
+ :recursive nil
+ :exclude-tags ("noexport" "draft")
+ :section-numbers nil
+ :with-creator nil
+ :with-toc nil)))
+
+(setq org-export-with-broken-links t)
+
+(use-package ox-pandoc
+ :ensure t
+ :after org
+ )
+
+(use-package denote
+ :ensure t
+ :hook (dired-mode . denote-dired-mode)
+ :config
+ (setq denote-rename-buffer-format "%t"
+ denote-buffer-name-prefix ""
+ denote-directory (expand-file-name "~/org/"))
+ (denote-rename-buffer-mode 1))
+
+(use-package denote-agenda
+ :ensure t
+ :after org
+ :config
+ (setq denote-agenda-include-regexp "task")
+ (denote-agenda-insinuate))
+
+(defcustom my/denote-task-filename-component-regexp
+ "\\(?:[-_.]\\|:\\)task\\(?:[-_.]\\|:\\|$\\)"
+ "Regexp matching a filename component that denotes the 'task' tag.
+Works on the base filename (without extension), e.g. matches \"-task\", \":task:\", \"_task_\"."
+ :type 'string)
+
+(defun my/denote--make-unique-filename (dir base ext)
+ "Return a unique filepath in DIR for BASE+EXT by adding -1, -2... if needed."
+ (let* ((extstr (if (and ext (not (string-empty-p ext))) (concat "." ext) ""))
+ (candidate (expand-file-name (concat base extstr) dir))
+ (count 1))
+ (while (file-exists-p candidate)
+ (setq candidate (expand-file-name (format "%s-%d%s" base count extstr) dir))
+ (setq count (1+ count)))
+ candidate))
+
+(defun my/denote-remove-task-filetag-and-silent-rename ()
+ "If current headline became DONE in a Denote note, remove :task: filetag and remove 'task' from filename silently.
+- Only acts if there are no other non-DONE TODOs in the same file.
+- Does not call Denote's interactive rename command (no buffers opened)."
+ (when (and (derived-mode-p 'org-mode)
+ (string= (org-get-todo-state) "DONE")
+ (buffer-file-name)
+ ;; detect Denote note by presence of #+identifier:
+ (save-excursion
+ (goto-char (point-min))
+ (re-search-forward "^#\\+identifier:" nil t)))
+ ;; only proceed if no other active TODOs remain in the file
+ (let ((has-other
+ (catch 'has
+ (org-map-entries
+ (lambda ()
+ (let ((s (org-get-todo-state)))
+ (when (and s (not (string= s "DONE")))
+ (throw 'has t))))
+ nil 'file)
+ nil)))
+ (unless has-other
+ ;; 1) Remove :task: from #+filetags:
+ (save-excursion
+ (goto-char (point-min))
+ (when (re-search-forward "^#\\+filetags:\\s-*\\(.*\\)$" nil t)
+ (let* ((tags (match-string 1))
+ (clean (replace-regexp-in-string ":task:" "" tags))
+ (clean (replace-regexp-in-string "::+" ":" clean))
+ (clean (replace-regexp-in-string "^:\\|:$" "" clean)))
+ (if (string-empty-p clean)
+ (delete-region (line-beginning-position) (1+ (line-end-position)))
+ (beginning-of-line)
+ (kill-line)
+ (insert (concat "#+filetags: :" clean ":"))))))
+ ;; 2) Compute new filename (silent, non-interactive)
+ (let* ((file (buffer-file-name))
+ (dir (file-name-directory file))
+ (name (file-name-nondirectory file))
+ (ext (file-name-extension name)) ;; "org"
+ (base (file-name-sans-extension name))
+ ;; remove the task component from the base
+ (new-base (replace-regexp-in-string my/denote-task-filename-component-regexp
+ ""
+ base)))
+ (when (and new-base (not (string= new-base base)))
+ ;; cleanup repeated separators: convert multiple '-'/'_'/'..' to single '-'
+ (setq new-base (replace-regexp-in-string "[-_.:]+"
+ "-"
+ new-base))
+ ;; strip leading/trailing separators
+ (setq new-base (replace-regexp-in-string "\\`[-_.:-]+" "" new-base))
+ (setq new-base (replace-regexp-in-string "[-_.:-]+\\'" "" new-base))
+ ;; ensure unique filename to avoid overwrite without prompt
+ (let ((target (my/denote--make-unique-filename dir new-base ext)))
+ (condition-case err
+ (progn
+ (rename-file file target 1) ;; 1 = ok to overwrite, but we avoid collisions by uniqueness
+ ;; update current buffer to visit the new filename silently
+ (set-visited-file-name target t t)
+ ;; save changes (filetags update + new filename)
+ (save-buffer)
+ (message "Denote: removed 'task' component from filename -> %s" (file-name-nondirectory target)))
+ (error
+ (message "Denote rename failed: %s" (error-message-string err)))))))))))
+
+(add-hook 'org-after-todo-state-change-hook #'my/denote-remove-task-filetag-and-silent-rename)
+
+
+
+(use-package denote-menu
+ :ensure t
+ :defer t
+ :config
+ (setq denote-menu-title-column-width 40
+ denote-menu-show-file-type nil))
+
+(use-package denote-org
+ :ensure t)
+
+(use-package consult-denote
+ :straight (:host github :repo "protesilaos/consult-denote")
+ :ensure t
+ :defer t)
+
+(defun my/convert-all-denote-links-in-directory (directory)
+ "Converts all denote: links to file: links in a specific directory."
+ (interactive "DDirectory: ")
+ (let ((org-files (directory-files directory t "\\.org$")))
+ (dolist (file org-files)
+ (with-current-buffer (find-file-noselect file)
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "\\[\\[denote:\\([0-9T]+\\)\\]\\(?:\\[\\([^]]*\\)\\]\\)?\\]" nil t)
+ (let* ((id (match-string 1))
+ (description (match-string 2))
+ (target-file (seq-find
+ (lambda (f)
+ (string-match-p (regexp-quote id) (file-name-nondirectory f)))
+ org-files)))
+ (when target-file
+ (let* ((target-filename (file-name-nondirectory target-file))
+ (new-link (if description
+ (format "[[file:./%s][%s]]" target-filename description)
+ (format "[[file:./%s]]" target-filename))))
+ (replace-match new-link t t))))))
+ (save-buffer)
+ (kill-buffer)))))
+
+(defvar my-org-export-output-directory-prefix "./export_")
+
+(defun my-org-export-create-directory (fn extension &rest args)
+ (let ((export-dir (format "%s%s" my-org-export-output-directory-prefix extension)))
+ (unless (file-directory-p export-dir)
+ (make-directory export-dir)))
+ (apply fn extension args))
+
+(advice-add #'org-export-output-file-name :around #'my-org-export-create-directory)
+(setq denote-excluded-directories-regexp "export_.*")
+
+(use-package ox-json
+ :ensure t
+ )
+
+(use-package denote-explore
+ :ensure t
+ )
+
+(use-package denote-publish
+ :ensure t
+ :straight ( denote-publish :type git :host nil :repo "https://github.com/vedang/denote-publish"))
+
+(setq denote-publish-default-base-dir "~/wiki")
+(setq denote-publish-default-output-dir "~/blog/wiki")
+
+(setq denote-publish-link-class "internal-link")
+
+(setq denote-publish-front-matter-fields
+ '(title subtitle identifier date last_updated_at
+ aliases tags category skip_archive has_code
+ og_image og_description og_video_id))
+
+(use-package which-key
+ :ensure t
+ :defer t
+ :hook
+ (after-init . which-key-mode)
+ :custom
+ (which-key-idle-delay 0.3))
+
+(use-package vertico
+ :ensure t
+ :straight t
+ :hook
+ (after-init . vertico-mode)
+ :custom
+ (vertico-count 10)
+ (vertico-resize nil)
+ (vertico-cycle nil)
+ :bind (:map vertico-map
+ ("C-j" . vertico-next)
+ ("C-k" . vertico-previous))
+ :config
+ (advice-add #'vertico--format-candidate :around
+ (lambda (orig cand prefix suffix index _start)
+ (setq cand (funcall orig cand prefix suffix index _start))
+ (concat
+ (if (= vertico--index index)
+ (propertize "» " 'face '(:foreground "#80adf0" :weight bold))
+ " ")
+ cand))))
+
+(use-package vertico-posframe
+ :init
+ (setq vertico-posframe-parameters '((left-fringe . 12) ;; Fringes
+ (right-fringe . 12)
+ (accept-focus . t)))
+ ;; (undecorated . nil) ;; Rounded frame
+
+ :config
+ (vertico-posframe-mode 1)
+ (setq vertico-posframe-width 96 ;; Narrow frame
+ vertico-posframe-height vertico-count ;; Default height
+ ;; Don't create posframe for these commands
+ vertico-multiform-commands '((consult-line (:not posframe))
+ (consult-ripgrep (:not posframe)))))
+
+(use-package corfu
+ :ensure t
+ :custom
+ ;; Optional customizations
+ ;; :custom
+ ;; (corfu-cycle t) ;; Enable cycling for `corfu-next/previous'
+ ;; (corfu-quit-at-boundary nil) ;; Never quit at completion boundary
+ ;; (corfu-quit-no-match nil) ;; Never quit, even if there is no match
+ ;; (corfu-preview-current nil) ;; Disable current candidate preview
+ ;; (corfu-preselect 'prompt) ;; Preselect the prompt
+ ;; (corfu-on-exact-match 'insert) ;; Configure handling of exact matches
+
+ ;; Enable Corfu only for certain modes. See also `global-corfu-modes'.
+ ;; :hook ((prog-mode . corfu-mode)
+ ;; (shell-mode . corfu-mode)
+ ;; (eshell-mode . corfu-mode))
+ (corfu-auto t)
+ (corfu-auto-delay 0.2)
+ (corfu-auto-prefix 2)
+ :init
+
+ ;; Recommended: Enable Corfu globally. Recommended since many modes provide
+ ;; Capfs and Dabbrev can be used globally (M-/). See also the customization
+ ;; variable `global-corfu-modes' to exclude certain modes.
+ ;; Enable optional extension modes:
+ ;; (corfu-history-mode)
+ ;; (corfu-popupinfo-mode)
+ (global-corfu-mode))
+
+(use-package consult
+ :ensure t
+ :straight t
+ :defer t
+ :init
+ (advice-add #'register-preview :override #'consult-register-window)
+
+ (setq xref-show-xrefs-function #'consult-xref
+ xref-show-definitions-function #'consult-xref)
+
+ :config
+ (setq consult-buffer-filter
+ '("\\` "
+ "\\`\\*Messages\\*\\'"
+ "\\`\\*Warnings\\*\\'"
+ "\\`\\*Compile-Log\\*\\'"
+ "\\`\\*Backtrace\\*\\'"
+ "\\`\\*Help\\*\\'"
+ "\\`\\*scratch\\*\\'"
+ "\\`\\*Completions\\*\\'"
+ "\\`\\*Flymake"
+ "\\`\\*lsp-help\\*\\'"
+ "\\`\\*eldoc"
+ "\\`\\*straight-process\\*\\'"
+ "\\`\\*Native-compile-Log\\*\\'"
+ "\\`\\*Async-native-compile-log\\*\\'")))
+
+(use-package markdown-mode
+ :defer t
+ :ensure t
+ :mode ("README\\.md\\'" . gfm-mode)
+ :init
+ (setq markdown-command "multimarkdown"))
+
+;; (use-package treesit-auto
+;; :ensure t
+;; :straight t
+;; :defer t
+;; :custom
+;; (treesit-auto-install 'prompt)
+;; :init
+;; (delete 'org treesit-auto-langs)
+;; :config
+;; (treesit-auto-add-to-auto-mode-alist 'all)
+;; (global-treesit-auto-mode t))
+
+(use-package embark
+ :ensure t
+ :straight t
+ :defer t)
+
+(use-package embark-consult
+ :ensure t
+ :straight t
+ :hook
+ (embark-collect-mode . consult-preview-at-point-mode)) ;; Enable preview in Embark collect mode.
+
+(use-package orderless
+ :ensure t
+ :straight t
+ :defer t ;; Load Orderless on demand.
+ :after vertico ;; Ensure Vertico is loaded before Orderless.
+ :init
+ (setq completion-styles '(orderless basic) ;; Set the completion styles.
+completion-category-defaults nil ;; Clear default category settings.
+completion-category-overrides '((file (styles partial-completion))))) ;; Customize file completion styles.
+
+(use-package marginalia
+ :ensure t
+ :straight t
+ :hook
+ (after-init . marginalia-mode))
+
+(use-package eglot
+ :straight nil
+ :ensure nil
+ :config
+ (setq eglot-autoshutdown t)
+ (setq eglot-sync-connect 1)
+ (setq eglot-send-changes-idle-time 0.1)
+ (setq eglot-sync-connect nil)
+ (setq eglot-connect-timeout nil)
+ (setq eglot-events-buffer-size 0)
+ (setq eglot-report-progress nil)
+
+ (add-hook 'eglot-managed-mode-hook
+ (lambda ()
+ (eglot-inlay-hints-mode -1)))
+
+ (setq eglot-ignored-server-capabilities
+ '(:inlayhintprovider :documenthighlightprovider)))
+
+
+
+;; (use-package eglot-booster
+;; :ensure t
+;; :straight ( eglot-booster :type git :host nil :repo "https://github.com/jdtsmith/eglot-booster")
+;; :after eglot
+;; :config (eglot-booster-mode))
+
+(use-package typst-ts-mode
+ :ensure t
+ :mode "\\.typ\\'"
+ :hook (typst-ts-mode . eglot-ensure)
+ :config
+ (with-eval-after-load 'eglot
+ (add-to-list 'eglot-server-programs
+ typst-ts-mode . ,(eglot-alternatives '("tinymist" "lsp")))))
+
+(use-package yasnippet
+ :ensure t
+ :config
+ (yas-global-mode 1))
+
+(use-package yasnippet-snippets
+ :ensure t
+ :after yasnippet)
+
+;; (use-package company
+;; :straight t
+;; :hook (after-init . global-company-mode)
+;; :bind (:map company-active-map
+;; ("C-n" . company-select-next)
+;; ("C-p" . company-select-previous)
+;; ("C-j" . company-select-next-or-abort)
+;; ("C-k" . company-select-previous-or-abort)
+;; ("M-j" . company-select-next)
+;; ("M-k" . company-select-previous)
+;; ("<tab>" . company-complete-selection)
+;; ("TAB" . company-complete-selection))
+;; :config
+;; (setq company-minimum-prefix-length 1)
+;; (setq company-idle-delay 0.1)
+;; (setq company-show-numbers t)
+;; (setq company-tooltip-align-annotations t)
+;; (setq company-require-match nil)
+;; (setq company-backends '((company-capf :with company-yasnippet)
+;; company-files
+;; company-dabbrev-code
+;; ))
+;; (setq company-dabbrev-code-everywhere t)
+;; (setq company-dabbrev-code-ignore-case t))
+
+(use-package nix-mode
+ :ensure t
+ :mode "\\.nix\\'"
+ :hook (nix-mode . eglot-ensure)
+ :config
+ (with-eval-after-load 'eglot
+ (add-to-list 'eglot-server-programs
+ '(nix-mode . ("nixd")))))
+
+(defun lspce-nixd-initializationOptions ()
+ (let ((flake-path "/home/cashmere/nix")
+ (config-name "x12"))
+ `(:nixpkgs (:expr ,(format "import (builtins.getFlake \"%s\").inputs.nixpkgs { }" flake-path))
+ :formatting (:command ["nixfmt"])
+ :options (:nixos (:expr ,(format "(builtins.getFlake \"%s\").nixosConfigurations.%s.options" flake-path config-name))
+ :home-manager (:expr ,(format "(builtins.getFlake \"%s\").nixosConfigurations.%s.config.home-manager.users.cashmere.options" flake-path config-name))))))
+
+(use-package envrc
+ :ensure t
+ :config
+ (envrc-global-mode))
+
+(use-package python-mode
+ :ensure t
+ :mode "\\.py\\'"
+ :hook (python-mode . eglot-ensure)
+ :config
+ (with-eval-after-load 'eglot
+ (add-to-list 'eglot-server-programs
+ '(python-mode . ("pyright-langserver" "--stdio")))))
+
+(use-package python-black
+ :ensure t
+ :demand t
+ :after python)
+
+(use-package rust-mode
+ :ensure t
+ :mode "\\.rs\\'"
+ :hook (rust-mode . eglot-ensure)
+ :config
+ (with-eval-after-load 'eglot
+ (add-to-list 'eglot-server-programs
+ '((rust-ts-mode rust-mode) .
+ ("rust-analyzer" :initializationOptions
+ (:check (:command "clippy")))))))
+
+;; (use-package rustic
+;; :ensure t
+;; :config
+;; (setq rustic-format-on-save nil)
+;; (setq rustic-lsp-client nil)
+;; :custom
+;; (rustic-cargo-use-last-stored-arguments t))
+
+(use-package nushell-mode
+ :ensure t
+ :mode "\\.nu\\'")
+
+(use-package nushell-ts-babel
+ :straight (nushell-ts-babel :type git :host github :repo "herbertjones/nushell-ts-babel")
+ :after org
+ :config
+ (org-babel-do-load-languages
+ 'org-babel-load-languages
+ (append org-babel-load-languages
+ '((nushell . t)))))
+
+(use-package go-mode
+ :ensure t
+ :mode "\\.go\\'"
+ :hook (go-mode . eglot-ensure)
+ :config
+ (with-eval-after-load 'eglot
+ (add-to-list 'eglot-server-programs
+ '(go-mode . ("gopls" :initializationOptions
+ (:staticcheck t
+ :matcher "CaseSensitive"
+ :usePlaceholders t)))))
+
+ (defun go-mode-setup ()
+ (add-hook 'before-save-hook #'eglot-format-buffer -10 t)
+ (add-hook 'before-save-hook
+ (lambda ()
+ (when (eglot-managed-p)
+ (eglot-code-action-organize-imports nil t)))
+ nil t))
+
+ (add-hook 'go-mode-hook #'go-mode-setup))
+
+(use-package json-mode
+ :ensure t
+ :mode "\\.json\\'"
+ :hook (json-mode . eglot-ensure)
+ :config
+ (with-eval-after-load 'eglot
+ (add-to-list 'eglot-server-programs
+ '(json-mode . ("vscode-json-language-server" "--stdio")))))
+
+(use-package yaml-mode
+ :ensure t
+ :mode "\\.ya?ml\\'"
+ :hook (yaml-mode . eglot-ensure))
+
+(use-package sh-mode
+ :straight nil
+ :ensure nil
+ :hook (bash-ts-mode . eglot-ensure)
+ (sh-mode . eglot-ensure)
+ :config
+ (with-eval-after-load 'eglot
+ (add-to-list 'eglot-server-programs
+ '((sh-mode bash-ts-mode) . ("bash-language-server" "start"))))
+
+ (defun sh-mode-setup ()
+ (add-hook 'before-save-hook #'eglot-format-buffer -10 t))
+
+ (add-hook 'sh-mode-hook #'sh-mode-setup)
+ (add-hook 'bash-ts-mode-hook #'sh-mode-setup))
+
+(use-package vterm
+ :ensure t
+ :defer t)
+
+(use-package multi-vterm
+ :ensure t
+ :defer t)
+
+(use-package olivetti
+ :ensure t
+ :defer t)
+
+(use-package diff-hl
+ :defer t
+ :straight t
+ :ensure t
+ :hook
+ (find-file . (lambda ()
+ (global-diff-hl-mode) ;; Enable Diff-HL mode for all files.
+ (diff-hl-flydiff-mode) ;; Automatically refresh diffs.
+ (diff-hl-margin-mode))) ;; Show diff indicators in the margin.
+ :custom
+ (diff-hl-side 'left) ;; Set the side for diff indicators.
+ (diff-hl-margin-symbols-alist '((insert . "┃") ;; Customize symbols for each change type.
+ (delete . "-")
+ (change . "┃")
+ (unknown . "┆")
+ (ignored . "i"))))
+
+(use-package magit
+ :ensure t
+ :straight t
+ :config
+ (if ek-use-nerd-fonts ;; Check if nerd fonts are being used
+ (setopt magit-format-file-function #'magit-format-file-nerd-icons)) ;; Turns on magit nerd-icons
+ :custom
+ (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1))
+(defun my/magit-kill-buffers ()
+ "kills all magit buffers"
+ (interactive)
+ (let ((buffers (magit-mode-get-buffers)))
+ (magit-restore-window-configuration)
+ (mapc #'kill-buffer buffers)))
+
+(setq switch-to-prev-buffer-skip
+ (lambda (window buffer bury-or-kill)
+ (string-match-p "\\*magit" (buffer-name buffer))))
+
+(use-package indent-guide
+ :defer t
+ :straight t
+ :ensure t
+ :hook
+ (prog-mode . indent-guide-mode) ;; Activate indent-guide in programming modes.
+ :config
+ (setq indent-guide-char "│")) ;; Set the character used for the indent guide.
+
+(use-package general
+ :straight t
+ :ensure t
+ :demand t
+ :config
+ (general-evil-setup)
+
+ (general-create-definer my-leader
+ :states '(normal visual)
+ :keymaps 'override
+ :prefix "SPC")
+
+ (general-create-definer my-local-leader
+ :states '(normal visual)
+ :keymaps 'override
+ :prefix ","))
+
+(use-package evil
+ :ensure t
+ :init
+ (setq evil-want-integration t)
+ (setq evil-want-keybinding nil)
+ (setq evil-want-C-u-delete t)
+ (setq evil-want-C-u-scroll t)
+ (setq evil-undo-system 'undo-tree)
+ (setq evil-split-window-below t)
+ (setq evil-vsplit-window-right t)
+ :config
+ (evil-mode 1)
+ (define-key evil-normal-state-map "u" 'undo-tree-undo)
+ (define-key evil-normal-state-map (kbd "C-r") 'undo-tree-redo)
+
+ (evil-set-initial-state 'help-mode 'emacs)
+ (evil-set-initial-state 'messages-buffer-mode 'normal)
+ (evil-set-initial-state 'dired-mode 'normal)
+ (evil-set-initial-state 'ibuffer-mode 'normal))
+
+(modify-syntax-entry ?_ "w")
+
+;; (setq select-enable-clipboard nil)
+;; (setq select-enable-primary nil)
+
+;; (evil-define-operator my/evil-yank-to-clipboard (beg end type register yank-handler)
+;; :move-point nil
+;; :repeat nil
+;; (interactive "<R><x><y>")
+;; (let ((select-enable-clipboard t))
+;; (evil-yank beg end type register yank-handler)))
+
+;; (defun my/evil-paste-from-clipboard ()
+;; (interactive)
+;; (let ((select-enable-clipboard t))
+;; (evil-paste-before 1 ?+)))
+
+;; (general-def '(normal visual) 'override
+;; :prefix "SPC"
+;; "yy" 'my/evil-yank-to-clipboard
+;; "yp" 'my/evil-paste-from-clipboard)
+
+(use-package smartparens
+ :ensure t
+ :init
+ (smartparens-global-mode 1)
+ :config
+ (require 'smartparens-config))
+(use-package evil-smartparens
+ :ensure t
+ :after evil-collection
+ :hook (smartparens-global-mode . evil-smartparens-mode))
+
+(use-package evil-collection
+ :after evil
+ :ensure t
+ :config
+ (evil-collection-init))
+
+(use-package evil-surround
+ :ensure t
+ :straight t
+ :after evil-collection
+ :config
+ (global-evil-surround-mode 1))
+
+(use-package evil-matchit
+ :ensure t
+ :straight t
+ :after evil-collection
+ :config
+ (global-evil-matchit-mode 1))
+
+(use-package evil-textobj-anyblock
+ :ensure t
+ :after evil
+ :config
+ (define-key evil-inner-text-objects-map "b" 'evil-textobj-anyblock-inner-block)
+ (define-key evil-outer-text-objects-map "b" 'evil-textobj-anyblock-a-block)
+
+ (setq evil-textobj-anyblock-blocks
+ '(("(" . ")")
+ ("{" . "}")
+ ("\\[" . "\\]")
+ ("<" . ">"))))
+
+(evil-define-text-object my-evil-textobj-anyblock-inner-quote
+ (count &optional beg end type)
+ "Select the closest outer quote."
+ (let ((evil-textobj-anyblock-blocks
+ '(("'" . "'")
+ ("\"" . "\"")
+ ("`" . "'")
+ ("“" . "”"))))
+ (evil-textobj-anyblock--make-textobj beg end type count nil)))
+
+(evil-define-text-object my-evil-textobj-anyblock-a-quote
+ (count &optional beg end type)
+ "Select the closest outer quote."
+ (let ((evil-textobj-anyblock-blocks
+ '(("'" . "'")
+ ("\"" . "\"")
+ ("`" . "'")
+ ("“" . "”"))))
+ (evil-textobj-anyblock--make-textobj beg end type count t)))
+
+(define-key evil-inner-text-objects-map "q" 'my-evil-textobj-anyblock-inner-quote)
+(define-key evil-outer-text-objects-map "q" 'my-evil-textobj-anyblock-a-quote)
+
+(use-package avy
+ :ensure t
+ :straight t
+ :after evil
+ :general
+ ;; (general-nmap "s" 'avy-goto-char-timer)
+ ;; (general-omap "s" 'evil-avy-goto-char-timer)
+ :config
+ (setq avy-all-windows t
+ avy-all-windows-alt t
+ avy-background t
+ avy-case-fold-search t
+ avy-timeout-seconds 0.3
+ avy-style 'at-full
+ avy-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
+
+ (evil-define-avy-motion evil-avy-goto-char-timer inclusive))
+
+(use-package undo-tree
+ :defer t
+ :ensure t
+ :straight t
+ :hook (after-init . global-undo-tree-mode)
+ :init
+ (setq undo-tree-visualizer-timestamps t
+ undo-tree-visualizer-diff t
+ undo-tree-auto-save-history t
+ undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo-tree-history/"))
+ undo-limit 800000
+ undo-strong-limit 12000000
+ undo-outer-limit 120000000)
+ :config
+ (setq undo-tree-mode-lighter ""))
+
+(use-package rainbow-delimiters
+ :defer t
+ :straight t
+ :ensure t
+ :hook
+ (prog-mode . rainbow-delimiters-mode))
+
+(use-package dotenv-mode
+ :defer t
+ :straight t
+ :ensure t
+ :config)
+
+(use-package envrc
+ :hook (after-init . envrc-global-mode))
+
+;; (use-package pulsar
+;; :defer t
+;; :straight t
+;; :ensure t
+;; :hook
+;; ;; (after-init . pulsar-global-mode)
+;; :init
+;; (setq pulsar-pulse-on-window-change nil)
+;; :config
+;; (setq pulsar-pulse t)
+;; (setq pulsar-delay 0.025)
+;; (setq pulsar-iterations 10)
+;; (setq pulsar-face 'evil-ex-lazy-highlight)
+
+;; (add-hook 'org-agenda-mode-hook
+;; (lambda () (pulsar-mode -1)))
+
+;; (setq pulsar-pulse-functions
+;; '(evil-scroll-down
+;; flymake-goto-next-error
+;; flymake-goto-prev-error
+;; evil-yank
+;; evil-yank-line
+;; evil-delete
+;; evil-delete-line
+;; evil-jump-item
+;; diff-hl-next-hunk
+;; diff-hl-previous-hunk
+;; recenter-top-bottom
+;; move-to-window-line-top-bottom
+;; reposition-window
+;; bookmark-jump
+;; other-window
+;; delete-window
+;; delete-other-windows
+;; forward-page
+;; backward-page
+;; scroll-up-command
+;; scroll-down-command
+;; windmove-right
+;; windmove-left
+;; windmove-up
+;; windmove-down
+;; tab-new
+;; tab-close
+;; tab-next)))
+
+(use-package evil-org
+ :ensure t
+ :straight t
+ :after org
+ :hook (org-mode . (lambda () evil-org-mode))
+ :config
+ (require 'evil-org-agenda)
+ (evil-org-agenda-set-keys))
+
+(use-package nerd-icons
+ :if ek-use-nerd-fonts ;; Load the package only if the user has configured to use nerd fonts.
+ :ensure t ;; Ensure the package is installed.
+ :straight t
+ :defer t) ;; Load the package only when needed to improve startup time.
+
+(use-package nerd-icons-dired
+ :if ek-use-nerd-fonts ;; Load the package only if the user has configured to use nerd fonts.
+ :ensure t ;; Ensure the package is installed.
+ :straight t
+ :defer t ;; Load the package only when needed to improve startup time.
+ :hook
+ (dired-mode . nerd-icons-dired-mode))
+
+(use-package nerd-icons-completion
+ :if ek-use-nerd-fonts ;; Load the package only if the user has configured to use nerd fonts.
+ :ensure t ;; Ensure the package is installed.
+ :straight t
+ :after (:all nerd-icons marginalia) ;; Load after `nerd-icons' and `marginalia' to ensure proper integration.
+ :config
+ (nerd-icons-completion-mode) ;; Activate nerd icons for completion interfaces.
+ (add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup)) ;; Setup icons in the marginalia mode for enhanced completion display.
+
+(defun ek/first-install ()
+ "dired"
+ (interactive) ;; Allow this function to be called interactively.
+ (switch-to-buffer "*Messages*") ;; Switch to the *Messages* buffer to display installation messages.
+ (message ">>> All required packages installed.")
+ (message ">>> Configuring Emacs-Kick...")
+ (message ">>> Configuring Tree Sitter parsers...")
+ (require 'treesit-auto)
+ (treesit-auto-install-all) ;; Install all available Tree Sitter grammars.
+ (message ">>> Configuring Nerd Fonts...")
+ (require 'nerd-icons)
+ (nerd-icons-install-fonts) ;; Install all available nerd-fonts
+ (message ">>> Emacs-Kick installed! Press any key to close the installer and open Emacs normally. First boot will compile some extra stuff :)")
+ (read-key) ;; Wait for the user to press any key.
+ (kill-emacs)) ;; Close Emacs after installation is complete.
+
+(require 'battery)
+(require 'nerd-icons)
+
+(defface my-battery-charging
+ '((t :inherit success))
+ "Face for charging battery.")
+
+(defface my-battery-full
+ '((t :inherit success))
+ "Face for full battery.")
+
+(defface my-battery-normal
+ '((t :inherit mode-line))
+ "Face for normal battery.")
+
+(defface my-battery-warning
+ '((t :inherit warning))
+ "Face for low battery.")
+
+(defface my-battery-critical
+ '((t :inherit error))
+ "Face for critical battery.")
+
+(defface my-battery-error
+ '((t :inherit error))
+ "Face for battery error.")
+
+(defvar my-battery-string nil)
+
+(defun my-update-battery ()
+ (setq my-battery-string
+ (when (bound-and-true-p display-battery-mode)
+ (let* ((data (and battery-status-function
+ (functionp battery-status-function)
+ (funcall battery-status-function)))
+ (status (cdr (assoc ?L data)))
+ (charging? (or (string-equal "AC" status)
+ (string-equal "on-line" status)))
+ (percentage (car (read-from-string (or (cdr (assq ?p data)) "ERR"))))
+ (valid? (and (numberp percentage)
+ (>= percentage 0)
+ (<= percentage battery-mode-line-limit)))
+ (face (if valid?
+ (cond (charging? 'my-battery-charging)
+ ((< percentage battery-load-critical) 'my-battery-critical)
+ ((< percentage 25) 'my-battery-warning)
+ ((< percentage 95) 'my-battery-normal)
+ (t 'my-battery-full))
+ 'my-battery-error))
+ (icon (if valid?
+ (cond
+ ((>= percentage 100)
+ (if charging?
+ (nerd-icons-mdicon "nf-md-battery_charging_100" :face face)
+ (nerd-icons-mdicon "nf-md-battery" :face face)))
+ ((>= percentage 90)
+ (if charging?
+ (nerd-icons-mdicon "nf-md-battery_charging_90" :face face)
+ (nerd-icons-mdicon "nf-md-battery_90" :face face)))
+ ((>= percentage 80)
+ (if charging?
+ (nerd-icons-mdicon "nf-md-battery_charging_80" :face face)
+ (nerd-icons-mdicon "nf-md-battery_80" :face face)))
+ ((>= percentage 70)
+ (if charging?
+ (nerd-icons-mdicon "nf-md-battery_charging_70" :face face)
+ (nerd-icons-mdicon "nf-md-battery_70" :face face)))
+ ((>= percentage 60)
+ (if charging?
+ (nerd-icons-mdicon "nf-md-battery_charging_60" :face face)
+ (nerd-icons-mdicon "nf-md-battery_60" :face face)))
+ ((>= percentage 50)
+ (if charging?
+ (nerd-icons-mdicon "nf-md-battery_charging_50" :face face)
+ (nerd-icons-mdicon "nf-md-battery_50" :face face)))
+ ((>= percentage 40)
+ (if charging?
+ (nerd-icons-mdicon "nf-md-battery_charging_40" :face face)
+ (nerd-icons-mdicon "nf-md-battery_40" :face face)))
+ ((>= percentage 30)
+ (if charging?
+ (nerd-icons-mdicon "nf-md-battery_charging_30" :face face)
+ (nerd-icons-mdicon "nf-md-battery_30" :face face)))
+ ((>= percentage 20)
+ (if charging?
+ (nerd-icons-mdicon "nf-md-battery_charging_20" :face face)
+ (nerd-icons-mdicon "nf-md-battery_20" :face face)))
+ ((>= percentage 10)
+ (if charging?
+ (nerd-icons-mdicon "nf-md-battery_charging_10" :face face)
+ (nerd-icons-mdicon "nf-md-battery_10" :face face)))
+ (t (if charging?
+ (nerd-icons-mdicon "nf-md-battery_charging_outline" :face face)
+ (nerd-icons-mdicon "nf-md-battery_outline" :face face))))
+ (nerd-icons-mdicon "nf-md-battery_alert" :face face)))
+ (text (if valid? (format " %d%%" percentage) " N/A"))
+ (help-echo (if (and battery-echo-area-format data valid?)
+ (battery-format battery-echo-area-format data)
+ "Battery status not available")))
+ (concat (propertize icon 'help-echo help-echo)
+ (propertize text 'face face 'help-echo help-echo))))))
+
+(defun my-override-battery ()
+ (when (bound-and-true-p display-battery-mode)
+ (advice-add #'battery-update :after #'my-update-battery)
+ (setq global-mode-string (delq 'battery-mode-line-string global-mode-string))
+ (my-update-battery)))
+
+(add-hook 'display-battery-mode-hook #'my-override-battery)
+
+(display-time-mode 1)
+(display-battery-mode 1)
+
+(defun my-lspce-diagnostics-string ()
+ (when (and (bound-and-true-p lspce-mode)
+ (bound-and-true-p flymake-mode))
+ (let* ((diags (flymake-diagnostics))
+ (error-count 0)
+ (warning-count 0)
+ (note-count 0))
+ (dolist (diag diags)
+ (let ((severity (flymake-diagnostic-type diag)))
+ (cond
+ ((eq severity :error) (setq error-count (1+ error-count)))
+ ((eq severity :warning) (setq warning-count (1+ warning-count)))
+ ((eq severity :note) (setq note-count (1+ note-count))))))
+ (when (or (> error-count 0) (> warning-count 0) (> note-count 0))
+ (concat
+ (when (> error-count 0)
+ (propertize (format " %d" error-count)
+ 'face 'error
+ 'help-echo (format "%d error(s)" error-count)))
+ (when (> warning-count 0)
+ (propertize (format " %d" warning-count)
+ 'face 'warning
+ 'help-echo (format "%d warning(s)" warning-count)))
+ (when (> note-count 0)
+ (propertize (format " %d" note-count)
+ 'face 'success
+ 'help-echo (format "%d note(s)" note-count))))))))
+
+(setq-default header-line-format
+ '("%e"
+ (:propertize " " display (raise +0.4))
+ (:propertize " " display (raise -0.4))
+
+ (:propertize "λ " face font-lock-comment-face)
+ mode-line-frame-identification
+ mode-line-buffer-identification
+
+ (:eval (when-let (vc vc-mode)
+ (list (propertize " " 'face 'font-lock-comment-face)
+ (propertize (truncate-string-to-width
+ (substring vc 5) 50)
+ 'face 'font-lock-comment-face))))
+
+ (:eval (my-lspce-diagnostics-string))
+
+ (:propertize " %4l:%c" face mode-line-buffer-id)
+
+ (:eval (propertize
+ " " 'display
+ `((space :align-to
+ (- (+ right right-fringe right-margin)
+ ,(+ 3
+ (string-width (or my-battery-string ""))
+ (string-width (or display-time-string ""))))))))
+
+ (:eval my-battery-string)
+ " "
+ (:eval display-time-string)))
+
+(setq-default mode-line-format nil)
+
+(defun my-lspce-diagnostics-string ()
+ (when (and (bound-and-true-p lspce-mode)
+ (bound-and-true-p flymake-mode))
+ (let* ((diags (flymake-diagnostics))
+ (error-count 0)
+ (warning-count 0)
+ (note-count 0))
+ (dolist (diag diags)
+ (let ((severity (flymake-diagnostic-type diag)))
+ (cond
+ ((eq severity :error) (setq error-count (1+ error-count)))
+ ((eq severity :warning) (setq warning-count (1+ warning-count)))
+ ((eq severity :note) (setq note-count (1+ note-count))))))
+ (when (or (> error-count 0) (> warning-count 0) (> note-count 0))
+ (concat
+ " "
+ (when (> error-count 0)
+ (concat
+ (nerd-icons-mdicon "nf-md-close_circle" :face 'error)
+ (propertize (format " %d " error-count)
+ 'face 'error
+ 'help-echo (format "%d error(s)" error-count))))
+ (when (> warning-count 0)
+ (concat
+ (nerd-icons-mdicon "nf-md-alert" :face 'warning)
+ (propertize (format " %d " warning-count)
+ 'face 'warning
+ 'help-echo (format "%d warning(s)" warning-count))))
+ (when (> note-count 0)
+ (concat
+ (nerd-icons-mdicon "nf-md-information" :face 'success)
+ (propertize (format " %d" note-count)
+ 'face 'success
+ 'help-echo (format "%d note(s)" note-count)))))))))
+
+(use-package hide-mode-line
+ :straight t
+ :defer t
+ :bind (:map custom-bindings-map ("C-c h m" . hide-mode-line-mode)))
+
+;; (use-package doom-modeline
+;; :ensure t
+;; :hook (after-init . doom-modeline-mode)
+;; :config
+;; (setq doom-modeline-buffer-file-name-style 'buffer-name))
+
+(use-package adaptive-wrap
+ :ensure t
+ :hook ((text-mode . adaptive-wrap-prefix-mode))
+ :config
+ (add-hook 'org-mode-hook
+ (lambda ()
+ (when (bound-and-true-p adaptive-wrap-prefix-mode)
+ (adaptive-wrap-prefix-mode -1)))))
+
+(setq package-gnupghome-dir "~/.gnupg")
+
+(blink-cursor-mode 0)
+(setq-default cursor-type 'bar)
+
+(defvar cashmere/font-height 140)
+
+(set-face-attribute 'default nil :family "JetBrainsMono Nerd Font" :weight 'regular :height cashmere/font-height)
+(set-face-attribute 'fixed-pitch nil :family "RobotoMono Nerd Font" :weight 'regular)
+(set-face-attribute 'variable-pitch nil :family "Poppins" :weight 'regular :height 1.1)
+
+(use-package mixed-pitch
+ :ensure t
+ :defer t
+ :hook ((org-mode . mixed-pitch-mode)
+ (LaTeX-mode . mixed-pitch-mode)))
+
+;; (use-package catppuccin-theme
+;; :ensure t
+;; :straight t
+;; :config
+;; (setq catppuccin-flavor 'mocha)
+
+;; (load-theme 'catppuccin :no-confirm)
+
+;; (custom-set-faces
+;; `(diff-hl-change ((t (:background unspecified :foreground ,(catppuccin-get-color 'blue))))))
+
+;; (custom-set-faces
+;; `(diff-hl-delete ((t (:background unspecified :foreground ,(catppuccin-get-color 'red))))))
+
+;; (custom-set-faces
+;; `(diff-hl-insert ((t (:background unspecified :foreground ,(catppuccin-get-color 'green)))))))
+
+(use-package modus-catppuccin
+ :straight (:type git
+ :repo "https://gitlab.com/magus/modus-catppuccin"
+ :branch "main")
+ :config
+ (load-theme 'catppuccin-latte :no-confirm))
+
+;; (use-package modus-themes
+;; :ensure nil
+;; :defer t
+;; :custom
+;; (modus-themes-italic-constructs t)
+;; (modus-themes-bold-constructs t)
+;; (modus-themes-mixed-fonts nil)
+;; (modus-themes-prompts '(bold intense))
+;; (modus-themes-common-palette-overrides
+;; `((accent-0 "#1e66f5")
+;; (accent-1 "#04a5e5")
+;; (bg-active bg-main)
+;; (bg-added "#d3f0d0")
+;; (bg-added-refine "#b8e6b3")
+;; (bg-changed "#dde5f5")
+;; (bg-changed-refine "#c4d4f0")
+;; (bg-completion "#ccd0da")
+;; (bg-completion-match-0 "#eff1f5")
+;; (bg-completion-match-1 "#eff1f5")
+;; (bg-completion-match-2 "#eff1f5")
+;; (bg-completion-match-3 "#eff1f5")
+;; (bg-hl-line "#e6e9ef")
+;; (bg-hover-secondary "#9ca0b0")
+;; (bg-line-number-active unspecified)
+;; (bg-line-number-inactive "#eff1f5")
+;; (bg-main "#eff1f5")
+;; (bg-mark-delete "#f5d9e0")
+;; (bg-mark-select "#dde5f5")
+;; (bg-mode-line-active "#e6e9ef")
+;; (bg-mode-line-inactive "#e6e9ef")
+;; (bg-prominent-err "#f5d9e0")
+;; (bg-prompt unspecified)
+;; (bg-prose-block-contents "#dce0e8")
+;; (bg-prose-block-delimiter bg-prose-block-contents)
+;; (bg-region "#9ca0b0")
+;; (bg-removed "#f5d9e0")
+;; (bg-removed-refine "#f0c9d1")
+;; (bg-tab-bar "#eff1f5")
+;; (bg-tab-current bg-main)
+;; (bg-tab-other "#eff1f5")
+;; (border-mode-line-active nil)
+;; (border-mode-line-inactive nil)
+;; (builtin "#1e66f5")
+;; (comment "#7c7f93")
+;; (constant "#d20f39")
+;; (cursor "#dc8a78")
+;; (date-weekday "#1e66f5")
+;; (date-weekend "#fe640b")
+;; (docstring "#5c5f77")
+;; (err "#d20f39")
+;; (fg-active fg-main)
+;; (fg-completion "#4c4f69")
+;; (fg-completion-match-0 "#1e66f5")
+;; (fg-completion-match-1 "#d20f39")
+;; (fg-completion-match-2 "#40a02b")
+;; (fg-completion-match-3 "#fe640b")
+;; (fg-heading-0 "#d20f39")
+;; (fg-heading-1 "#fe640b")
+;; (fg-heading-2 "#df8e1d")
+;; (fg-heading-3 "#40a02b")
+;; (fg-heading-4 "#04a5e5")
+;; (fg-line-number-active "#7287fd")
+;; (fg-line-number-inactive "#9ca0b0")
+;; (fg-link "#1e66f5")
+;; (fg-main "#4c4f69")
+;; (fg-mark-delete "#d20f39")
+;; (fg-mark-select "#1e66f5")
+;; (fg-mode-line-active "#4c4f69")
+;; (fg-mode-line-inactive "#9ca0b0")
+;; (fg-prominent-err "#d20f39")
+;; (fg-prompt "#8839ef")
+;; (fg-prose-block-delimiter "#7c7f93")
+;; (fg-prose-verbatim "#40a02b")
+;; (fg-region "#4c4f69")
+;; (fnname "#1e66f5")
+;; (fringe "#eff1f5")
+;; (identifier "#8839ef")
+;; (info "#179299")
+;; (keyword "#8839ef")
+;; (keyword "#8839ef")
+;; (name "#1e66f5")
+;; (number "#fe640b")
+;; (property "#1e66f5")
+;; (string "#40a02b")
+;; (type "#df8e1d")
+;; (variable "#fe640b")
+;; (warning "#df8e1d")))
+;; :config
+;; (modus-themes-with-colors
+;; (custom-set-faces
+;; `(change-log-acknowledgment ((,c :foreground "#7287fd")))
+;; `(change-log-date ((,c :foreground "#40a02b")))
+;; `(change-log-name ((,c :foreground "#fe640b")))
+;; `(diff-context ((,c :foreground "#1e66f5")))
+;; `(diff-file-header ((,c :foreground "#ea76cb")))
+;; `(diff-header ((,c :foreground "#1e66f5")))
+;; `(diff-hunk-header ((,c :foreground "#fe640b")))
+;; `(gnus-button ((,c :foreground "#1e66f5")))
+;; `(gnus-group-mail-3 ((,c :foreground "#1e66f5")))
+;; `(gnus-group-mail-3-empty ((,c :foreground "#1e66f5")))
+;; `(gnus-header-content ((,c :foreground "#04a5e5")))
+;; `(gnus-header-from ((,c :foreground "#8839ef")))
+;; `(gnus-header-name ((,c :foreground "#40a02b")))
+;; `(gnus-header-subject ((,c :foreground "#1e66f5")))
+;; `(log-view-message ((,c :foreground "#7287fd")))
+;; `(match ((,c :background "#c4d4f0" :foreground "#4c4f69")))
+;; `(modus-themes-search-current ((,c :background "#d20f39" :foreground "#eff1f5")))
+;; `(modus-themes-search-lazy ((,c :background "#c4d4f0" :foreground "#4c4f69")))
+;; `(newsticker-extra-face ((,c :foreground "#7c7f93" :height 0.8 :slant italic)))
+;; `(newsticker-feed-face ((,c :foreground "#d20f39" :height 1.2 :weight bold)))
+;; `(newsticker-treeview-face ((,c :foreground "#4c4f69")))
+;; `(newsticker-treeview-selection-face ((,c :background "#c4d4f0" :foreground "#4c4f69")))
+;; `(tab-bar ((,c :background "#eff1f5" :foreground "#4c4f69")))
+;; `(tab-bar-tab ((,c :background "#eff1f5" :underline t)))
+;; `(tab-bar-tab-group-current ((,c :background "#eff1f5" :foreground "#4c4f69" :underline t)))
+;; `(tab-bar-tab-group-inactive ((,c :background "#eff1f5" :foreground "#7c7f93")))
+;; `(tab-bar-tab-inactive ((,c :background "#eff1f5" :foreground "#5c5f77")))
+;; `(vc-dir-file ((,c :foreground "#1e66f5")))
+;; `(vc-dir-header-value ((,c :foreground "#7287fd")))))
+;; :init
+;; (load-theme 'modus-operandi t))
+
+;; (use-package kanagawa-themes
+;; :ensure t
+;; :config
+;; (load-theme 'kanagawa-wave t))
+
+(use-package dirvish
+ :straight t
+ :init
+ (dirvish-override-dired-mode)
+
+ :custom
+ (dirvish-quick-access-entries
+ '(("h" "~/" "Home")
+ ("d" "~/Downloads/" "Downloads")
+ ("p" "~/projects/" "Projects")))
+
+ (dirvish-reuse-session 'open)
+ (dirvish-attributes '(file-size))
+ (dirvish-mode-line-format
+ '(:left (sort file-time symlink) :right (omit yank index)))
+
+ (dirvish-hide-details '(dirvish dirvish-side))
+ (dirvish-hide-cursor '(dirvish dirvish-side))
+
+ (dired-listing-switches
+ "-l --almost-all --human-readable --group-directories-first --no-group")
+
+ :config
+ (setq dired-dwim-target t)
+ (setq delete-by-moving-to-trash t)
+ (setq dired-mouse-drag-files t))
+
+(use-package dired-rsync
+ :ensure t)
+
+(use-package dired-rsync-transient
+ :ensure t
+ :after (dired-rsync transient))
+
+(setq-default olivetti-body-width 130)
+(define-globalized-minor-mode my/global-olivetti-mode olivetti-mode
+ (lambda () (olivetti-mode 1)))
+(my/centered-cursor)
+(my/global-olivetti-mode)
+
+(use-package org-modern-indent
+ :straight (:host github :repo "jdtsmith/org-modern-indent")
+ :hook (org-mode . org-modern-indent-mode))
+
+(setq ibuffer-never-show-predicates
+ '(;; System buffers
+ "^\\*Messages\\*$"
+ "^\\*scratch\\*$"
+ "^\\*Completions\\*$"
+ "^\\*Help\\*$"
+ "^\\*Apropos\\*$"
+ "^\\*info\\*$"
+ "^\\*Async-native-compile-log\\*$"
+
+ ;; LSP Buffers
+ "^\\*lsp-log\\*$"
+ "^\\*clojure-lsp\\*$"
+ "^\\*clojure-lsp::stderr\\*$"
+ "^\\*ts-ls\\*$"
+ "^\\*ts-ls::stderr\\*$"))
+
+(use-package projectile
+ :ensure t
+ :demand t
+ :config
+ (projectile-mode +1)
+ (setq projectile-completion-system 'default
+ projectile-enable-caching t
+ projectile-indexing-method 'alien
+ projectile-sort-order 'recentf
+ projectile-require-project-root nil
+ projectile-globally-ignored-buffers '("\\*magit.*")))
+
+(use-package consult-projectile
+ :ensure t
+ :straight t
+ :after (consult projectile)
+ :defer t
+ :config
+ (setq consult-project-function #'projectile-project-root))
+
+(use-package hidepw
+ :ensure t
+ :custom
+ (hidepw-hide-first-line t)
+ :hook (pass-view-mode . hidepw-mode))
+
+(use-package pass
+ :ensure t
+ :defer t
+ :mode ("\\.gpg\\'" . pass-mode)
+ :config
+ (add-to-list 'display-buffer-alist
+ '("\\*Pass.*\\*"
+ (display-buffer-full-frame))))
+
+(use-package auth-source
+ :straight nil
+ :ensure nil ;; This is built-in, no need to fetch it.
+ :defer t
+ :config
+ ;; Enable password-store integration for secure API key retrieval.
+ (when (require 'auth-source-pass nil t)
+ (auth-source-pass-enable)
+ ;; Add password-store explicitly to auth-sources for compatibility.
+ (add-to-list 'auth-sources 'password-store)
+ ;; Optional: Cache expires after 5 minutes for security.
+ (setq auth-source-cache-expiry 300)))
+
+(use-package zoom
+ :ensure t)
+(custom-set-variables
+ '(zoom-size '(0.618 . 0.618)))
+
+(use-package pdf-tools
+ :straight (:type built-in)
+ :magic ("%PDF" . pdf-view-mode)
+ :config
+ (pdf-loader-install)
+ :hook (pdf-view-mode . (lambda () (display-line-numbers-mode -1))))
+
+(defun ek/lsp-describe-and-jump ()
+ (interactive)
+ (lspce-help-at-point)
+ (let ((help-buffer "*lsp-help*"))
+ (when (get-buffer help-buffer)
+ (switch-to-buffer-other-window help-buffer))))
+
+
+(defun my/eldoc-and-jump ()
+ "Zeige Eldoc-Dokumentation manuell an."
+ (interactive)
+ (if (>= emacs-major-version 31)
+ (eldoc-box-help-at-point)
+ (progn
+ (eldoc-doc-buffer)
+ (when-let ((eldoc-win (get-buffer-window "*eldoc*")))
+ (select-window eldoc-win)))))
+
+(evil-define-key 'normal 'global (kbd "K") #'my/eldoc-and-jump)
+
+;; (defun my/setup-eldoc-hover-keys ()
+;; (when (string-match-p "\\*eldoc\\*" (buffer-name))
+;; (evil-normalize-keymaps)
+;; (evil-local-set-key 'normal (kbd "q") 'quit-window)))
+
+;; (add-hook 'buffer-list-update-hook #'my/setup-eldoc-hover-keys)
+
+;; (evil-define-key 'normal 'global (kbd "K") #'my/eldoc-and-jump)
+
+(defun my/format-buffer ()
+ (interactive)
+ (cond
+ ((eq major-mode 'rust-mode) (eglot-format-buffer))
+ ((eq major-mode 'nix-mode) (eglot-format-buffer))
+ ((or (eq major-mode 'python-mode)
+ (eq major-mode 'python-ts-mode)) (eglot-format-buffer))
+ ((eq major-mode 'c-mode) (eglot-format-buffer))
+ ((bound-and-func-p eglot--managed-mode) (eglot-format-buffer))
+ (t (message "No formatter for %s" major-mode))))
+
+(my-leader
+ "SPC" '((lambda ()
+ (interactive)
+ (if (projectile-project-p)
+ (consult-projectile-find-file)
+ (projectile-switch-project)))
+ :wk "find file/switch project")
+ "sp" '(consult-projectile :wk "search project")
+ "ss" '(consult-line :wk "search project")
+ "/" '(consult-ripgrep :wk "search project")
+ "." '(find-file :wk "find file")
+ "," '(consult-buffer :wk "switch buffer")
+ ":" (lambda () (interactive) (execute-extended-command nil))
+
+ "d" '(:ignore t :wk "denote")
+ "dd" '(denote-menu-list-notes t :wk "List all notes")
+ "dg" '(denote-grep t :wk "Search")
+ "dn" '(denote t :wk "Create a new note")
+ "dr" '(denote-rename-file t :wk "Rename Note")
+
+ "f" '(:ignore t :wk "files")
+ "fd" '(dired :wk "dired")
+ "fD" '(dired-jump :wk "dired jump")
+ "fr" '(consult-recent-file :wk "recent files")
+ "ff" '(find-file :wk "find file")
+ "fs" '(save-buffer :wk "save file")
+
+ "b" '(:ignore t :wk "buffers")
+ "bb" '(consult-buffer :wk "switch buffer")
+ "bi" '(ibuffer :wk "ibuffer")
+ "bd" '(kill-current-buffer :wk "kill buffer")
+ "bk" '(kill-current-buffer :wk "kill buffer")
+ "bs" '(save-buffer :wk "save buffer")
+
+ "p" '(:ignore t :wk "project")
+ "pp" '(projectile-switch-project :wk "switch project")
+ "pf" '(projectile-find-file :wk "find file")
+ "ps" '(consult-ripgrep :wk "search")
+ "pb" '(consult-projectile-buffer :wk "buffers")
+ "pk" '(projectile-kill-buffers :wk "kill buffers")
+ ;; "pd" '(projectile-dired :wk "root dir")
+ "pd" '(projectile-remove-known-project :wk "delete project")
+ "pr" '(projectile-recentf :wk "recent files")
+ "pa" '(projectile-add-known-project :wk "add project")
+ ;; "pc" '(projectile-compile-project :wk "compile")
+ ;; "pt" '(projectile-test-project :wk "test")
+ "pi" '(projectile-invalidate-cache :wk "invalidate cache")
+
+ "g" '(:ignore t :wk "git/goto")
+ "gc" '(magit-clone :wk "clone")
+ "gg" '(magit-status :wk "status")
+ "gl" '(magit-log-current :wk "log")
+ "gd" '(xref-find-definitions :wk "go to definition")
+ "gD" '((lambda () (interactive)
+ (let ((current-prefix-arg 4))
+ (call-interactively #'xref-find-definitions)))
+ :wk "definition other window")
+ "gi" '(eglot-find-implementation :wk "go to implementation")
+ "gI" '((lambda () (interactive)
+ (let ((current-prefix-arg 4))
+ (call-interactively #'eglot-find-implementation)))
+ :wk "implementation other window")
+ "gt" '(eglot-find-typeDefinition :wk "go to type definition")
+ "gr" '(xref-find-references :wk "find references")
+ "gs" '(magit-file-stage :wk "stage file")
+ "gb" '(vc-annotate :wk "blame")
+
+ "o" '(:ignore t :wk "open")
+
+ "h" '(:ignore t :wk "help")
+ "hm" '(describe-mode :wk "mode")
+ "hf" '(describe-function :wk "function")
+ "hv" '(describe-variable :wk "variable")
+ "hk" '(describe-key :wk "key")
+
+ "w w" '(evil-window-next :wk "Close window")
+ "w c" '(evil-window-delete :wk "Close window")
+ "w n" '(evil-window-new :wk "New window")
+ "w s" '(evil-window-split :wk "Horizontal split window")
+ "w v" '(evil-window-vsplit :wk "Vertical split window")
+ "w h" '(evil-window-left :wk "Window left")
+ "w j" '(evil-window-down :wk "Window down")
+ "w k" '(evil-window-up :wk "Window up")
+ "w l" '(evil-window-right :wk "Window right")
+ "w w" '(evil-window-next :wk "Goto next window")
+ "w H" '(buf-move-left :wk "Buffer move left")
+ "w J" '(buf-move-down :wk "Buffer move down")
+ "w K" '(buf-move-up :wk "Buffer move up")
+ "w L" '(buf-move-right :wk "Buffer move right")
+
+ "c" '(:ignore t :wk "code")
+ "ca" '(eglot-code-actions :wk "code actions")
+ "cr" '(eglot-rename :wk "lsp rename")
+ "cf" '(eglot-format :wk "format buffer")
+
+ "q" '(:ignore t :wk "quit")
+ "qq" '(save-buffers-kill-terminal :wk "quit emacs")
+ "qr" '(restart-emacs :wk "restart")
+
+ "x" '(org-capture :wk "capture")
+
+ "a" '(embark-act :wk "embark")
+ "u" '(undo-tree-visualize :wk "undo tree")
+ "P" '(consult-yank-from-kill-ring :wk "paste history"))
+
+
+(defun my/avy-enabled-p ()
+ (and (not (derived-mode-p 'magit-mode 'dired-mode 'ibuffer-mode))
+ (not (eq major-mode 'dirvish-mode))))
+
+(general-def '(normal visual) 'override
+ "s" (lambda ()
+ (interactive)
+ (if (derived-mode-p 'magit-mode)
+ (call-interactively 'magit-stage)
+ (when (my/avy-enabled-p)
+ (let ((scroll-margin 0)
+ (maximum-scroll-margin 0))
+ (call-interactively 'evil-avy-goto-char-2))))))
+
+
+(general-def 'normal 'override
+ "]d" 'flymake-goto-next-error
+ "[d" 'flymake-goto-prev-error
+ "]c" 'diff-hl-next-hunk
+ "[c" 'diff-hl-previous-hunk
+ "]b" 'switch-to-next-buffer
+ "[b" 'switch-to-prev-buffer
+ "]t" 'tab-next
+ "[t" 'tab-previous
+ "P" 'consult-yank-from-kill-ring
+ "gcc" (lambda ()
+ (interactive)
+ (unless (use-region-p)
+ (comment-or-uncomment-region
+ (line-beginning-position)
+ (line-end-position)))))
+
+(general-def 'visual 'override
+ "gc" (lambda ()
+ (interactive)
+ (when (use-region-p)
+ (comment-or-uncomment-region
+ (region-beginning)
+ (region-end)))))
+
+(my-local-leader
+ :keymaps 'org-mode-map
+ "h" '(consult-org-heading :wk "search headings")
+ "n" '(my-toggle-org-tree-indirect-buffer :wk "toggle narrow"))
+
+(my-leader
+ :keymaps 'org-mode-map
+ "c" '(:wk "Clock" :ignore)
+
+ "cs" '(org-schedule :wk "Schedule")
+ "cd" '(org-deadline :wk "Deadline")
+
+ "l" '(:wk "Link" :ignore)
+ "lc" '(org-cliplink :wk "Cliplink")
+ "li" '(org-download-clipboard :wk "Image")
+ "ll" '(org-insert-link :wk "Link various things")
+
+ "t" '(org-todo :wk "TODO")
+
+ "RET" '(org-open-at-point))
+
+(with-eval-after-load 'denote-menu
+ (general-def 'normal denote-menu-mode-map
+ "r" 'denote-menu-filter
+ "c" 'denote-menu-clear-filters
+ "e" 'denote-menu-export-to-dired
+ "o" 'denote-menu-filter-out-keyword))
+
+(general-def 'normal dirvish-mode-map
+ "?" 'dirvish-dispatch
+ "q" 'dirvish-quit
+ "b" 'dirvish-quick-access
+ "f" 'dirvish-file-info-menu
+ "p" 'dirvish-yank
+ "S" 'dirvish-quicksort
+ "F" 'dirvish-layout-toggle
+ "z" 'dirvish-history-jump
+ "gh" 'dirvish-subtree-up
+ "gl" 'dirvish-subtree-toggle
+ "h" 'dired-up-directory
+ "l" 'dired-find-file
+ "TAB" 'dirvish-subtree-toggle
+ "[h" 'dirvish-history-go-backward
+ "]h" 'dirvish-history-go-forward)
+
+(general-def '(normal visual) dirvish-mode-map
+ :prefix "y"
+ "l" 'dirvish-copy-file-true-path
+ "n" 'dirvish-copy-file-name
+ "p" 'dirvish-copy-file-path
+ "y" 'dired-do-copy)
+
+(general-def 'normal dirvish-mode-map
+ :prefix "s"
+ "s" 'dirvish-symlink
+ "S" 'dirvish-relative-symlink
+ "h" 'dirvish-hardlink)
+
+(my-local-leader
+ "a" '(org-agenda :wk "org agenda")
+ "t" '(multi-vterm :wk "terminal")
+ "c" '(my/centered-cursor :wk "center cursor")
+ "d" '(dirvish :wk "dired")
+ "z" '(zoom-mode :wk "zoom/golden ratio")
+ "m" '(mu4e :wk "mail")
+ "p" '(pass :wk "pass")
+ "o" '(my/global-olivetti-mode :wk "center buffer")
+ "g" '(gptel :wk "gptel"))
+
+(global-set-key (kbd "C-=") 'text-scale-increase)
+(global-set-key (kbd "C--") 'text-scale-decrease)
+
+;; (defun my/evil-delete-to-blackhole (orig-fn beg end &optional type register &rest args)
+;; (apply orig-fn beg end type ?_ args))
+
+;; (advice-add 'evil-delete :around 'my/evil-delete-to-blackhole)
+
+;; (my-leader
+;; "y" '(my/yank-to-clipboard :wk "clipboard" :ignore t)
+;; "yy" '(my/yank-to-clipboard :wk "yank to clipboard")
+;; "yp" '(my/paste-from-clipboard :wk "paste from clipboard"))
+
+;; (defun my/yank-to-clipboard ()
+;; (interactive)
+;; (if (region-active-p)
+;; (let ((select-enable-clipboard t))
+;; (kill-ring-save (region-beginning) (region-end))
+;; (message "Yanked to clipboard"))
+;; (message "No region active")))
+
+;; (defun my/paste-from-clipboard ()
+;; (interactive)
+;; (let ((select-enable-clipboard t))
+;; (yank)))
+
+;; (defun my/delete-to-clipboard ()
+;; (interactive)
+;; (if (region-active-p)
+;; (let ((select-enable-clipboard t))
+;; (kill-region (region-beginning) (region-end))
+;; (message "Deleted to clipboard"))
+;; (message "No region active")))
+
+(use-package elfeed
+ :ensure t
+ :defer t
+ :custom
+ (elfeed-db-directory "~/.emacs.d/elfeed")
+ :config
+ (setq elfeed-search-filter "@2-weeks-ago +unread"
+ elfeed-search-title-max-width 110)
+
+ (add-hook 'elfeed-search-mode-hook #'elfeed-update)
+
+ (setq elfeed-search-sort-function
+ (lambda (a b)
+ (let* ((a-date (elfeed-entry-date a))
+ (b-date (elfeed-entry-date b))
+ (a-feed (elfeed-feed-title (elfeed-entry-feed a)))
+ (b-feed (elfeed-feed-title (elfeed-entry-feed b)))
+ (a-title (elfeed-entry-title a))
+ (b-title (elfeed-entry-title b)))
+ (cond
+ ((> a-date b-date) t)
+ ((< a-date b-date) nil)
+ ((string< a-feed b-feed) t)
+ ((string> a-feed b-feed) nil)
+ (t (string< a-title b-title)))))))
+
+(use-package elfeed-org
+ :ensure t
+ :after elfeed
+ :custom
+ (rmh-elfeed-org-files (list "~/org/rss.org"))
+ :config
+ (elfeed-org))
+
+(defun elfeed-export-from-index-to-csv (output-file)
+ (interactive "FExport CSV nach: ")
+ (require 'elfeed)
+ (require 'elfeed-db)
+
+ (elfeed-db-load)
+
+ (let ((entries (hash-table-values elfeed-db-entries)))
+ (with-temp-file output-file
+ (insert "id,title,link,date,feed,tags\n")
+ (dolist (entry entries)
+ (insert (format "\"%s\",\"%s\",\"%s\",%s,\"%s\",\"%s\"\n"
+ (elfeed-entry-id entry)
+ (replace-regexp-in-string "\"" "\"\"" (elfeed-entry-title entry))
+ (elfeed-entry-link entry)
+ (elfeed-entry-date entry)
+ (elfeed-feed-title (elfeed-entry-feed entry))
+ (mapconcat #'symbol-name (elfeed-entry-tags entry) " "))))
+ (message "Export abgeschlossen: %d Einträge" (length entries)))))
+
+(setq browse-url-browser-function 'browse-url-generic
+ browse-url-generic-program "qutebrowser")
+
+(use-package mu4e
+ :straight nil
+ :ensure nil
+ :config
+
+ (setq mu4e-mu-binary (executable-find "mu"))
+ (setq mu4e-maildir "~/Mails")
+ (setq mu4e-get-mail-command (concat (executable-find "mbsync") " -a"))
+ (setq mu4e-update-interval 300)
+ (setq mu4e-attachment-dir "~/Downloads")
+ (setq mu4e-change-filenames-when-moving t)
+
+ (setq mu4e-user-mail-address-list
+ '("cashmeresamurai@autistici.org"
+ "cashmere@cashmere.rs"))
+
+ (setq mu4e-contexts
+ `(,(make-mu4e-context
+ :name "autistici"
+ :match-func
+ (lambda (msg)
+ (when msg
+ (string-prefix-p "/autistici" (mu4e-message-field msg :maildir))))
+ :vars '((user-mail-address . "cashmeresamurai@autistici.org")
+ (user-full-name . "cashmere")
+ (mu4e-drafts-folder . "/autistici/Drafts")
+ (mu4e-sent-folder . "/autistici/Sent")
+ (mu4e-trash-folder . "/autistici/Trash")
+ (mu4e-refile-folder . "/autistici/Archive")))
+
+ ,(make-mu4e-context
+ :name "cashmere"
+ :match-func
+ (lambda (msg)
+ (when msg
+ (string-prefix-p "/cashmere/cashmere" (mu4e-message-field msg :maildir))))
+ :vars '((user-mail-address . "cashmere@cashmere.rs")
+ (user-full-name . "cashmere")
+ (mu4e-drafts-folder . "/cashmere/cashmere/Drafts")
+ (mu4e-sent-folder . "/cashmere/cashmere/Sent")
+ (mu4e-trash-folder . "/cashmere/cashmere/Trash")
+ (mu4e-refile-folder . "/cashmere/cashmere/Archive")))))
+
+ (setq mu4e-context-policy 'pick-first)
+ (setq mu4e-compose-context-policy 'ask)
+
+ (setq sendmail-program (executable-find "msmtp"))
+ (setq send-mail-function 'sendmail-send-it)
+ (setq message-send-mail-function 'sendmail-send-it)
+ (setq message-sendmail-envelope-from 'header)
+ (setq message-kill-buffer-on-exit t)
+
+ (defun mu4e-set-msmtp-account ()
+ (if (message-mail-p)
+ (save-excursion
+ (let* ((from (save-restriction
+ (message-narrow-to-headers)
+ (message-fetch-field "from")))
+ (account
+ (cond
+ ((string-match "cashmeresamurai@autistici.org" from) "autistici")
+ ((string-match "cashmere@cashmere.rs" from) "cashmere/cashmere"))))
+ (setq message-sendmail-extra-arguments (list '"-a" account))))))
+
+ (add-hook 'message-send-mail-hook 'mu4e-set-msmtp-account))
+
+;; (profiler-start 'cpu)
+;; (org-agenda nil "c")
+;; (profiler-report)
+;; (profiler-stop)
+
+(provide 'init)