My Config

My personal Emacs Config, 2021-07-05T11:00:00+02:00

Beginner

(setopt debug-on-error t)
(setq init-file-debug nil)  ; show loading messages for init.el

Emacs Configuration

Package System

The use-package macro allows you to set up package customization in your init file in a declarative way. It takes care of many things for you that would otherwise require a lot of repetitive boilerplate code. It can help with common customization, such as binding keys, setting up hooks, customizing user options and faces, autoloading, and more. It also helps you keep Emacs startup fast, even when you use many (even hundreds) of packages.

(package-initialize)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(put 'denote-mode 'safe-local-variable (lambda (_) t))

CUA Mode

Cua-mode is part of GnuEmacs versions 22.1.1 and later (at least).

Cua-mode allows one to use ‘C-v’, ‘C-c’, and ‘C-x’ to paste, copy, and cut the region. Since this conflicts with very important keybindings in Emacs, these CUA bindings are only active when the mark is active. The package does a whole lot more, too: ‘C-z’ to undo, Shift-movement to select, and it includes support for rectangular regions (‘C-RET’ and arrow keys instead of using the `C-x r …’ keys) and registers (instead of using the register commands), and it uses `<tab>’ and `S-<tab>’ to indent and outdent the region. As you can see, it is very powerful!

Note: If region is not active – no visible selection – then ‘C-x’ works as it as it does normally in Emacs (without cua-mode).

On the other hand if the region is active you can use C-S-x (or two rapid C-x C-x) instead C-x to do what C-x normally does in Emacs. The same goes for the other CUA keys.

(cua-mode)
(setopt cua-auto-tabify-rectangles nil) ;; Don't tabify after rectangle commands
(setopt transient-mark-mode 1) ;; No region when it is not highlighted
(setopt cua-keep-region-after-copy nil) ;; Standard Windows behaviour

Completion

YaSnippet

YASnippet is a template system for Emacs. It allows you to type an abbreviation and automatically expand it into function templates.

See what it looks like: http://www.youtube.com/watch?v=ZCGmZK4V7Sg.

The MELPA package comes with snippets from https://github.com/AndreaCrotti/yasnippet-snippets, language templates include: C, C++, C#, Perl, Python, Ruby, SQL, LaTeX, HTML, CSS and more. The snippet syntax is inspired from TextMate's syntax, you can even import most TextMate templates to YASnippet.

Hosted at https://github.com/joaotavora/yasnippet, manual at http://joaotavora.github.io/yasnippet/. Stable versions also available from GNU ELPA: https://elpa.gnu.org/packages/yasnippet.html

(require 'yasnippet)
(require 'yasnippet-capf)
 (yas-global-mode)
 ;; Optional: add custom snippet directories
(add-to-list 'yas-snippet-dirs "~/.config/emacs/snippets")

Cape

Cape provides Completion At Point Extensions which can be used in combination with Corfu, Company or the default completion UI. The completion backends used by completion-at-point are so called completion-at-point-functions (Capfs).

(use-package cape)
;; Add multiple CAPFs in order of priority
(setq completion-at-point-functions
              (list (cape-capf-super
             #'yasnippet-capf   ; snippets
              #'cape-keyword     ; language keywords
              #'cape-dabbrev     ; words in buffer
              #'cape-file)))      ; file paths

Corfu

Corfu is an Emacs completion frontend — a minimal, fast, and modern way to show inline completion candidates at point. It is frontend-only, meaning it doesn’t generate completions itself but relies on Emacs’ completion-at-point functions (CAPFs) or other sources like CAPE .

  • What Corfu does
    • Provides a popup menu of completions directly at the cursor (inline, not in the minibuffer).
    • Works with any backend that implements CAPF , e.g., LSP servers, keywords, buffer words, snippets.
    • Supports cycling through candidates , automatic popups, and minimal distraction.
    ;; Packages: make sure these are installed
    ;; corfu, cape, yasnippet, lsp-mode, typescript-mode (or other language modes)
    
    (use-package corfu)
    (global-corfu-mode 1)
    (setq corfu-auto t)       ; automatic popup
    (setq corfu-cycle t)      ; cycle through candidates
    (setq corfu-separator ?\s) ; separator in popup
    
    ;; Optional: enable Corfu in minibuffer for commands
    (defun corfu-enable-in-minibuffer ()
      (when (eq this-command 'eval-expression)
        (corfu-mode 1)))
    (add-hook 'minibuffer-setup-hook #'corfu-enable-in-minibuffer)
    
    
    (use-package lsp-mode)
    (use-package typescript-mode)
    
    ;; LSP setup
    (add-hook 'typescript-mode-hook #'lsp)    ; start LSP automatically
    (setq lsp-enable-snippet t)               ; LSP completions can include snippets
    
    
    
    ;; Keybindings
    ;; TAB triggers completion or snippet expansion
    (global-set-key (kbd "TAB") #'completion-at-point)
    
    ;; Optional: better TAB behavior in programming buffers
    (add-hook 'prog-mode-hook
              (lambda ()
                (local-set-key (kbd "TAB") #'completion-at-point)))
    
    (message "Corfu + CAPE + YASnippet + LSP configured!")
    

Vertico

Vertico provides a performant and minimalistic vertical completion UI based on the default completion system. The main focus of Vertico is to provide a UI which behaves correctly under all circumstances. By reusing the built-in facilities system, Vertico achieves full compatibility with built-in Emacs completion commands and completion tables. Vertico only provides the completion UI but aims to be highly flexible, extensible and modular. Additional enhancements are available as extensions or complementary packages. The code base is small and maintainable. The main vertico.el package is only about 600 lines of code without white space and comments.

  • Vertical display with arrow key navigation. See the extensions for additional display modes.
  • Prompt shows the current candidate index and the total number of candidates.
  • The current candidate is inserted with TAB and selected with RET.
  • Non-existing candidates can be submitted with M-RET or by moving the point to the prompt.
  • Configurable sorting by history position, length and alphabetically.
  • Long candidates with newlines are formatted to take up less space.
  • Deferred completion style highlighting for performance.
  • Annotations are displayed next to the candidates (annotation- and affixation-function).
  • Support for candidate grouping and group cycling commands (group-function).
            (use-package vertico)
            (vertico-mode)
          (vertico-buffer-mode)

            ;; Enable vertico-multiform
            (vertico-multiform-mode)

   ;; Configure the display per command.
  ;; Use a buffer with indices for imenu
  ;; and a flat (Ido-like) menu for M-x.
            (setq vertico-multiform-commands
                      '((consult-imenu buffer indexed)
                            (execute-extended-command grid)
                            (org-refile buffer)
                            ))

            ;; Configure the display per completion category.
            ;; Use the grid display for files and a buffer
            ;; for the consult-grep commands.
            (setq vertico-multiform-categories
                      '((file grid)
                            (consult-grep buffer)))
        (add-to-list 'vertico-multiform-categories
                     '(jinx grid (vertico-grid-annotate . 20) (vertico-count . 4)))

  ;; Add prompt indicator to `completing-read-multiple'.
  ;; Alternatively try `consult-completing-read-multiple'.
  (defun crm-indicator (args)
    (cons (concat "[CRM] " (car args)) (cdr args)))
  (advice-add #'completing-read-multiple :filter-args #'crm-indicator)

  ;; Do not allow the cursor in the minibuffer prompt
  (setq minibuffer-prompt-properties
              '(read-only t cursor-intangible t face minibuffer-prompt))
  (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)

  ;; Emacs 28: Hide commands in M-x which do not work in the current mode.
  ;; Vertico commands are hidden in normal buffers.
  ;; (setq read-extended-command-predicate
  ;;       #'command-completion-default-include-p)

  ;; Enable recursive minibuffers
(setq enable-recursive-minibuffers t)
(setq vertico-buffer-mode t)
(setq vertico-posframe-font "FreeMono")
(setq vertico-posframe-mode nil)
(vertico-multiform-mode)
(setq vertico-sort-function 'vertico-sort-history-length-alpha)

EasySession

The easysession Emacs package provides a comprehensive session management for Emacs. It is capable of persisting and restoring file-visiting buffers, indirect buffers (clones), buffer narrowing, Dired buffers, window configurations, the built-in tab-bar (including tabs, their buffers, and associated windows), as well as entire Emacs frames (frame name, size, position, etc.).

With easysession, your Emacs setup is restored automatically when you restart. All files, Dired buffers, and window layouts come back as they were, so you can continue working right where you left off. While editing, you can also switch to another session, switch back, rename sessions, or delete them, giving you full control over multiple work environments.

(require 'easysession)
;; Save every 10 minutes
(setopt easysession-save-interval (* 10 60))

;; Save the current session when using `easysession-switch-to'
(setopt easysession-switch-to-save-session t)

;; Do not exclude the current session when switching sessions
(setopt easysession-switch-to-exclude-current nil)

;; Display the active session name in the mode-line lighter.
(setq easysession-save-mode-lighter-show-session-name t)

;; Optionally, the session name can be shown in the modeline info area:
;;(setq easysession-mode-line-misc-info t)

;; non-nil: Make `easysession-setup' load the session automatically.
;; (nil: session is not loaded automatically; the user can load it manually.)
(setopt easysession-setup-load-session t)

;; The `easysession-setup' function adds hooks:
;; - To enable automatic session loading during `emacs-startup-hook', or
;;   `server-after-make-frame-hook' when running in daemon mode.
;; - To save the session at regular intervals, and when Emacs exits.
(easysession-setup)

Printing

lpr is an older command, stemming from the times when printers were often directly connected to Unix systems. However, it came to pass that the "Common Unix Printing System" (CUPS) was developed, providing modern print management on Unix systems. And a little web search revealed that it comes with its own command line command, lp.

The syntax of the two commands varies slightly. lpr usually simply accepts the filename I want to print, while lp accepts a range of options that allow me to control various aspects of the print job, such as the number of copies, the printer, the paper format, etc.

Emacs kindly provides the option to configure the command it uses under the hood. So, instead of lpr, we say we'd rather use lp:

(setq lpr-command "lp")

Since lp and lpr pass different parameters on the command line, it also doesn't make sense to continue using the lpr standard switches for lp. So, we turn them off:

(setq lpr-add-switches nil)

Other

By default, Emacs sometimes asks you to type full “yes” or “no” in confirmation prompts. To make all of these accept just “y” or “n”, you can add this line to your Emacs config:

(setopt use-short-answers t)

OpenWith

(use-package openwith)
(openwith-mode t)
;;(add-to-list  'mm-inhibit-file-name-handlers 'openwith-file-handler)
(setq openwith-associations
      (list (list (openwith-make-extension-regexp '("pdf"))
                  "evince" '(file))
            (list (openwith-make-extension-regexp '("maff" "mht" "mhtml"))
                  "firefox" '(file))
            (list (openwith-make-extension-regexp '("m4a" "flac" "mp3" "wav"))
                  "vlc" '(file))
            (list (openwith-make-extension-regexp '("avi" "flv" "mov" "mp4"
                                                    "mpeg" "mpg" "ogg" "wmv"))
                  "vlc" '(file))
            (list (openwith-make-extension-regexp '("doc" "docx" "odt"))
                  "libreoffice" '("--writer" file))
            (list (openwith-make-extension-regexp '("ods" "xls" "xlsx"))
                  "libreoffice" '("--calc" file))
            (list (openwith-make-extension-regexp '("odp" "pps" "ppt" "pptx"))
                  "libreoffice" '("--impress" file))
            ))

Use ‘read-key’

Use ‘read-key’ when reading answers to "y or n" questions by ‘y-or-n-p’. Otherwise, use the ‘read-from-minibuffer’ to read the answers.

When reading via the minibuffer, you can use the normal commands available in the minibuffer, and can, for instance, temporarily switch to another buffer, do things there, and then switch back to the minibuffer before entering the character. This is not possible when using ‘read-key’, but using ‘read-key’ may be less confusing to some users.

(setq y-or-n-p-use-read-key nil)

JSON

JSON (JavaScript Object Notation) is a subset of JavaScript useful as a format for transferring data from program to program, much like XML.

Read all about it at json.org!

You can decode and encode JSON from Emacs Lisp using json.el. It is part of GNU Emacs since 23.1 (2008).

(require 'json)

Elpy

Elpy is the Emacs Python Development Environment. It aims to provide an easy to install, fully-featured environment for Python development.

Elpy documentation: http://elpy.readthedocs.org/en/latest/index.html Elpy wiki: https://github.com/jorgenschaefer/elpy/wiki

(add-to-list 'auto-mode-alist '("\\.org.txt\\'" . org-mode))
(add-to-list 'auto-mode-alist '("\\.ino\\'" . c-mode))
(setq gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3")

Window splitting

The existing split-window-sensibly function always prefers to end up with a horizontal stack of windows (which, rather confusingly, it calls a vertical "split", though the split is horizontal …) over a side-by-side arrangement. It's easy enough to create a function which has the opposite preference, which is essentially just a copy of split-window-sensibly with the preferences reversed:

(setq split-height-threshold 20)
(setq split-width-threshold 70)
(defun split-window-really-sensibly (&optional window)
  (let ((window (or window (selected-window))))
    (or (and (window-splittable-p window t)
             ;; Split window vertically.
             (with-selected-window window
               (split-window-right))) 
        (and (window-splittable-p window)
             ;; Split window horizontally.
             (with-selected-window window
               (split-window-below)))
        (and (eq window (frame-root-window (window-frame window)))
             (not (window-minibuffer-p window))
             ;; If WINDOW is the only window on its frame and is not the
             ;; minibuffer window, try to split it vertically disregarding
             ;; the value of `split-height-threshold'.
             (let ((split-height-threshold 0))
               (when (window-splittable-p window)
                 (with-selected-window window
                   (split-window-right))))))))
(setq split-window-preferred-function 'split-window-really-sensibly)

RecentF

Recentf is a minor mode that builds a list of recently opened files. This list is automatically saved across sessions on exiting Emacs - you can then access this list through a command or the menu.

(require 'recentf)

(setopt recentf-max-saved-items 40)
(setopt recentf-max-menu-items 40)
(setopt recentf-menu-append-commands-flag t)
(setopt recentf-menu-filter 'recentf-arrange-by-dir)
(setopt recentf-exclude '("agenda" "history" "tmp" "wiki"))

(recentf-mode)

https://www.emacswiki.org/emacs/RecentFiles

This mode has been part of GNU Emacs since version 21.

Appearance

Window-Buffer handling

Read: Demystifying Emacs’s Window Manager Watch: control where buffers are displayed (the display-buffer-alist ) (2024-02-08).

The display-buffer-alist is a powerful user option and somewhat hard to get started with. The reason for its difficulty comes from the knowledge required to understand the underlying display-buffer mechanism.

Here is the gist of what we do with it:

  • The alist is a list of lists.
  • Each element of the alist (i.e. one of the lists) is of the following form:

    (BUFFER-MATCHER FUNCTIONS-TO-DISPLAY-BUFFER OTHER-PARAMETERS)

  • The BUFFER-MATCHER is either a regular expression to match the buffer by its name or a method to get the buffer whose major mode is the one specified. In the latter case, you will see the use of cons cells (like (one . two)) involving the derived-mode symbol (remember that I build Emacs from source, so derived-mode may not exist in your version of Emacs).
  • The FUNCTIONS-TO-DISPLAY-BUFFER is a list of display-buffer functions that are tried in the order they appear in until one works. The list can be of one element, as you will notice with some of my entries.
  • The OTHER-PARAMETERS are enumerated in the Emacs Lisp Reference Manual. Evaluate:
(info "(elisp) Buffer Display Action Alists")

Switching Buffers

There is a subtle but important distinction between displaying a buffer and switching to it. Switching is done with C-x b (or its sibling commands, like C-x 4 b) and it is the default user-facing key binding for switching a window’s buffer.

By default Emacs distinguishes between automatic and manual window switching. If you effect a window switch yourself with C-x b, it’s manual — and exempt from any display action rules you create yourself.

You probably don’t want that. I recommend you set this:

;; Requires Emacs 27+
(setq switch-to-buffer-obey-display-actions t)
(setq switch-to-buffer-in-dedicated-window 'pop)

Now Emacs treats manual buffer switching the same as programmatic switching.

However, it also guards against (some) misbehaving commands you may encounter: those that call out to switch-to-buffer programmatically. That is “against the rules”, as switch-to-buffer is a user-facing command.

(defun my-window-select (window &rest _)
  "Select WINDOW.

        Use this as the `body-function' in a `display-buffer-alist' entry."
  (select-window window)
  )

;; NOTE 2023-03-17: Remember that I am using development versions of
;; Emacs.  Some of my `display-buffer-alist' contents are for Emacs
;; 29+.
;;  (advice-add 'quit-window :around
;;            (lambda (orig &rest args)
;;              (apply orig t args)))
(setq display-buffer-alist
      `(;; no window
        ("\\`\\*Async Shell Command\\*\\'"
         (display-buffer-no-window))
        ("\\`\\*\\(Warnings\\|Compile-Log\\|Org Links\\)\\*\\'"
         (display-buffer-no-window)
         (allow-no-window . t))
        ;; bottom side window
        ("\\*Org \\(Select\\|Note\\)\\*" ; the `org-capture' key selection and `org-add-log-note'
         (display-buffer-in-side-window)
         (dedicated . t)
         (side . bottom)
         (slot . 0)
         (window-parameters . ((mode-line-format . none))))


        ;; bottom buffer (NOT side window)
        ((or . ((derived-mode . flymake-diagnostics-buffer-mode)
                (derived-mode . flymake-project-diagnostics-mode)
                (derived-mode . messages-buffer-mode)
                (derived-mode . backtrace-mode)))

         (display-buffer-reuse-mode-window
          display-buffer-at-bottom)

         (window-height . 0.3)
         (dedicated . t)
         (preserve-size . (t . t)))

        ("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
         nil
         (window-parameters (mode-line-format . none)))


        ("\\*Embark Actions\\*"
         (display-buffer-reuse-mode-window display-buffer-in-side-window display-buffer-below-selected)
         (window-height . fit-window-to-buffer)
         (window-parameters . ((no-other-window . t)
                               (mode-line-format . none))))

        ("\\*vterm\\*"
         (display-buffer-reuse-mode-window
          display-buffer-below-selected)
         (window-height . 0.3)
         (window-parameters . ((no-other-window . t)
                               (mode-line-format . none))))

        ("\\*\\(Output\\|Register Preview\\).*"
         (display-buffer-reuse-mode-window display-buffer-at-bottom))

        ;; below current window
        ("\\(\\*Capture\\*\\|CAPTURE-.*\\)"
         (display-buffer-reuse-mode-window display-buffer-below-selected))

        ("\\*\\vc-\\(incoming\\|outgoing\\|git : \\).*"
         (display-buffer-reuse-mode-window display-buffer-below-selected)
         (window-height . 0.1)
         (dedicated . t)
         (preserve-size . (t . t)))

        ((derived-mode . reb-mode) ; M-x re-builder
         (display-buffer-reuse-mode-window display-buffer-below-selected)
         (window-height . 4) ; note this is literal lines, not relative
         (dedicated . t)
         (preserve-size . (t . t)))
        ((or . ((derived-mode . occur-mode)
                (derived-mode . grep-mode)
                (derived-mode . Buffer-menu-mode)
                (derived-mode . log-view-mode)
                (derived-mode . help-mode) ; See the hooks for `visual-line-mode'
                "\\*\\(|Buffer List\\|Occur\\|vc-change-log\\).*"
                ))
         (display-buffer-reuse-mode-window display-buffer-pop-up-window )
         (dedicated . t)
         (body-function . my-window-select))

        ("\\*\\(Calendar\\|Bookmark Annotation\\|ert\\).*"
         (display-buffer-reuse-mode-window display-buffer-below-selected)
         (dedicated . t)
         (window-height . fit-window-to-buffer))


        ;; NOTE 2023-02-17: `man' does not fully obey the
        ;; `display-buffer-alist'.  It works for new frames and for
        ;; `display-buffer-below-selected', but otherwise is
        ;; unpredictable.  See `Man-notify-method'.
        ((or . ((derived-mode . Man-mode)
                (derived-mode . woman-mode)
                "\\*\\(Man\\|woman\\).*"))
         (display-buffer-same-window))


        ))

We match against one buffer name, Compilation; with one ACTION, display-buffer-reuse-window; and no ALIST settings, so it’s not listed.

(add-to-list 'display-buffer-alist
             '("\\*Compilation\\*"
               display-buffer-reuse-window))

I want info windows in a side bar window; it must be on the right-hand side and in slot 0; the window-width must be 80; and Emacs must set the window no-delete-other-windows window parameter to t.

(add-to-list 'display-buffer-alist
             '("\\*info\\*"
               (display-buffer-in-side-window)
               (side . right)
               (slot . 0)
               (window-width . 100)
               (window-parameters
                (no-delete-other-windows . t))))
(add-to-list 'display-buffer-alist
         '(  (major-mode . dired-mode)
           (display-buffer-reuse-window)
               (side . right)
               (slot . 0)
               (window-width . 120)
               (window-parameters
                (no-delete-other-windows . t))))

Here I insist that Help buffers reuse any existing Help window if such a window exists. And if that is not possible, it must pop up a new window. Furthermore, Emacs cannot use the same (selected) window, and it must use another.

(add-to-list 'display-buffer-alist
             '("\\*Help\\*"
               (display-buffer-reuse-window
                display-buffer-pop-up-window)
               (inhibit-same-window . t)
               )
             )

Navigation

Emacs Lisp

Dired

Writing

Denote

Org Mode

Import, Export, and Integration

Completion

Coding

Folding

Hideshow (built-in)

hs-minor-mode parses buffer syntax to accurately detect the start and end of blocks. It is the best tool for C-style languages, or anything using braces {} and explicit block structures like sh/Bash shell scripts.

(use-package hideshow
    :hook (
    ;; Systems and General Purpose
    (c-mode . hs-minor-mode)
    (c++-mode . hs-minor-mode)
    (java-mode . hs-minor-mode)
    (rust-mode . hs-minor-mode)
    (go-mode . hs-minor-mode)
    (ruby-mode . hs-minor-mode)
    (php-mode . hs-minor-mode)
    (perl-mode . hs-minor-mode)
    ;; Web and Frontend
    (js-mode . hs-minor-mode)
    (typescript-mode . hs-minor-mode)
    (css-mode . hs-minor-mode)
    ;; Scripting, Data, and Infrastructure
    (sh-mode . hs-minor-mode) ; for bash/shell scripts
    (json-mode . hs-minor-mode)
    (lua-mode . hs-minor-mode)
    (nxml-mode . hs-minor-mode)
    (html-mode . hs-minor-mode)  ;; mhtml and html
  )
    )

Outline-indent

The outline-indent package provides code folding based on indentation levels. It is recommended for Python, Haskell, and YAML because it supports an unlimited number of folding levels. For instance, it allows folding an entire function or specific nested blocks within that function, such as if statements inside while loops.

(use-package outline-indent)
(setq outline-indent-ellipsis " ▼")

(add-hook 'python-mode-hook #'outline-indent-minor-mode)
(add-hook 'python-ts-mode-hook #'outline-indent-minor-mode)

Treesit-fold

The treesit-fold package provides Intelligent code folding by using the structural understanding of the built-in tree-sitter parser. Unlike traditional folding methods that rely on regular expressions or indentation, treesit-fold uses the actual syntax tree of the code to accurately identify foldable regions such as functions, classes, comments, and documentation strings.

(use-package treesit-fold)
(setq treesit-fold-line-count-show t)
(setq treesit-fold-line-count-format " ▼")
(set-face-attribute 'treesit-fold-replacement-face nil
                    :foreground "#B0B000"
                    :box nil
                    :weight 'bold)

Kirigami

The kirigami Emacs package provides a unified method to fold and unfold text in Emacs across a diverse set of Emacs modes.

Supported modes include: outline-mode, outline-minor-mode, outline-indent-minor-mode, org-mode, markdown-mode, gfm-mode, outli-mode, embark-collect-mode, vdiff-mode, vdiff-3way-mode, hide-ifdef-mode, vimish-fold-mode, TeX-fold-mode (AUCTeX), fold-this-mode, origami-mode, yafolding-mode, folding-mode, ts-fold-mode, treesit-fold-mode, hs-minor-mode (hideshow), ibuffer-mode ( M-x ibuffer), and profiler-report-mode ( M-x profile-report ).

(use-package kirigami)
(setq kirigami-show-menu-bar t)
(setq kirigami-show-context-menu t)
(kirigami-global-mode 1)

Web

Mail, News, and Chat

Multimedia

Shells

Fun

AI

LLM

Other

General Config

Major Modes

calendar

(use-package german-holidays)
(setq calendar-holidays holiday-german-NI-holidays)

(setq calendar-date-style 'iso)
(setq calendar-day-abbrev-array ["So" "Mo" "Di" "Mi" "Do" "Fr" "Sa"])
(setq calendar-day-header-array ["So" "Mo" "Di" "Mi" "Do" "Fr" "Sa"])
(setq calendar-day-name-array
         ["Sonntag" "Montag" "Dienstag" "Mittwoch" "Donnerstag" "Freitag" "Samstag"])
(setq calendar-iso-date-display-form
         '((format "%s-%.2d-%.2d" year
                           (string-to-number month)
                           (string-to-number day))))
(setq calendar-iso-month-header
         '(propertize
           (format "%d-%s" year
                           (calendar-month-name month))
           'font-lock-face 'calendar-month-header))
(setq calendar-mark-diary-entries-flag t)
(setq calendar-month-name-array
         ["Januar" "Februar" "März" "April" "Mai" "Juni" "Juli" "August" "September" "Oktober" "November" "Dezember"])
(setq calendar-standard-time-zone-name "CEST")
(setq calendar-time-display-form
         '(24-hours ":" minutes
                                (if time-zone " (")
                                time-zone
                                (if time-zone ")")))
(setq calendar-view-diary-initially-flag t)
(setq calendar-week-start-day 1)
(setq plstore-cache-passphrase-for-symmetric-encrytion t)

Calibre

This package integrates calibre (using calibredb ) into emacs.

  1. Powerful ebook dashboard.
  2. Manage ebooks, actually not only ebooks!
  3. Fetch metadata from online sources incl. automatic detection of ISBN for pdf and djvu files (automatic detection of ISBN requires pdf-tools and djvu package for pdf and djvu files respectively)
  4. Manage Ebooks’ libraries and virtual libraries.
  5. Customized Metadata: Tag, comment, highlight, favorite, archive etc.
  6. Quick search, filter, make actions on items with ivy and helm.
  7. Org-ref support.
(use-package calibredb)
(setq calibredb-root-dir "~/data/ebooks/calibre")
(setq calibredb-db-dir (expand-file-name "metadata.db" calibredb-root-dir))
(setq calibredb-library-alist '(("~/data/ebooks/calibre")))
(setq calibredb-id-width 5)

Customize

The code block defines a function my/timer-cursor-to-row3-col1 that moves the cursor to row 3, column 1 after a 0.3-second delay when Custom-mode is activated. So, the cursor is moved into the search field at activation. This is achieved by adding the function to the Custom-mode-hook, ensuring it runs whenever Custom-mode starts.

(defun my/timer-cursor-to-row3-col1 ()
  (interactive)
    (run-at-time "0.3 sec" nil
                 (lambda ()
                     (move-to-column 0)
                     (goto-line 3)
                     )))

(add-hook 'Custom-mode-hook #'my/timer-cursor-to-row3-col1)

diary

(add-hook 'diary-list-entries-hook 'diary-sort-entries t)
(add-hook 'diary-list-entries-hook 'diary-include-other-diary-files)
(add-hook 'diary-mark-entries-hook 'diary-mark-included-diary-files)

Dired

Dired is the main mode for Emacs file-manager operations. The name “Dired” stands for “directory editor”.

A single Dired buffer can display the contents of a single directory, or it can include listings of one or more sub-directories. A Dired buffer can alternatively display an arbitrary set of files and directories, from any file systems.

A Dired buffer can display a filtered subset of directory contents, and it can show either just file names or additional file details.

All the operations you expect from a typical file-manager application are available in Dired, plus some that are specific to Emacs.

You can use ‘C-x C-q’ to make a Dired buffer editable. This enters WDired mode (writable Dired). For example, you can use this to bulk-rename files, or to change file ownerships and privileges.

You can operate on multiple files after marking them. The usual mark is ‘*’, but the mark used for deletion is ‘D’. ‘D’ marks are also called flags, and the operation of marking with ‘D’ is also called flagging .

You visit a directory in Dired mode using key bindings ‘C-x d’, ‘C-x 4 d’, and ‘C-x 5 d’ .

The menu bar is helpful for learning operations and key bindings. As always, ‘C-h m’ provides information on the mode. Consult the Emacs manual ( ‘C-h r’) for more info – choose Dired under Advanced Features. You can also read about Dired online.

(use-package wdired)
(setq dired-listing-switches "-hAl --group-directories-first --time-style=long-iso")
(setq dired-omit-files "^\\.?#\\|^\\.$\\|^\\.\\.$\\|^\\..*$")
(setq dired-use-ls-dired t)
(defun drops/dired-move-files (target-dir)
  "Move marked files in Dired to TARGET-DIR.
If no files are marked, move the file at point instead."
  (interactive "DMove file(s) to directory: ")
  (let ((full-target (expand-file-name target-dir))
        (files (dired-get-marked-files nil nil)))
    (unless files
      (setq files (list (dired-get-file-for-visit))))
    (unless (file-directory-p full-target)
      (make-directory full-target t))
    (dolist (file files)
      (let ((target (expand-file-name (file-name-nondirectory file) full-target)))
        (rename-file file target 1)
        (message "Moved: %s -> %s" file target)))
    (revert-buffer)))

Dired-dwim

💡 How it works:

  • Checks if you’re inside a Projectile project (projectile-project-p).
  • If yes → runs projectile-dired, opening Dired in the project root.
  • If no → falls back to plain dired in the current directory.

This is normally bound to F6.

(defun my/dired-dwim ()
  "Open Dired at the Projectile project root if available, otherwise in `default-directory`."
  (interactive)
  (if (and (fboundp 'projectile-project-root)
           (projectile-project-p))
      (projectile-dired)
    (dired default-directory)))
(defun my/dired-move-to (target-dir)
  "Move marked files or directories in Dired to TARGET-DIR.
Falls rename-file über Dateisystemgrenzen hinweg fehlschlägt,
wird stattdessen kopiert und das Original gelöscht."
  (let ((files (dired-get-marked-files)))
    (dolist (file files)
      (let* ((target (expand-file-name (file-name-nondirectory file) target-dir)))
        (condition-case err
            (dired-rename-file file target t)
          (file-error
           (message "rename-file fehlgeschlagen, versuche Copy/Delete: %s" (cadr err))
           (if (file-directory-p file)
               (copy-directory file target t t t)
             (copy-file file target t))
           (delete-file file t)))))
    (revert-buffer)))

Calming Mouse Interaction in Dired

Single-click on a file or directory will move the point to it, making it the implicit target for any subsequent Dired command.

Left double-click on file or directory will open it.

(add-hook
 'dired-mode-hook
 (lambda ()
   (setq-local mouse-1-click-follows-link 'double)))
(defun my/dired-mouse-toggle-mark ()
  "Toggle mark of a Dired item via mouse."
  (interactive)
  (unless (use-region-p)
    (mouse-set-point last-input-event)
    (if (char-equal (char-after (line-beginning-position)) dired-marker-char)
        (call-interactively #'dired-unmark)
      (call-interactively #'dired-mark))))

(keymap-set dired-mode-map "M-<mouse-1>" #'my/dired-mouse-toggle-mark)

eww

Eww (the Emacs Web Wowser) is a Web browser written in elisp and based on shr.el.

(use-package eww)
(setq eww-search-prefix "https://duckduckgo.com/?kae=b&kl=de-de&kad=de_DE&kp=-1&kw=w&kak=-1&kah=de-de&kn=-1&kaj=m&kam=osm&kv=-1&kao=-1&kd=-1&kc=-1&kac=-1&k1=-1&kk=-1&kz=-1&q=")

Eww is included in Emacs 24.4 and later.

ElFeed

Elfeed is an extensible web feed reader for Emacs, supporting both Atom and RSS. It requires Emacs 24.3 and is available for download from MELPA or el-get. Elfeed was inspired by notmuch.

For a longer overview,

Elpy

Elpy is an Emacs package to bring powerful Python editing to Emacs. It combines and configures a number of other packages, both written in Emacs Lisp as well as Python. Elpy is fully documented at Readthedocs.

 (add-hook 'python-mode-hook 'hs-minor-mode)

ePub

nov.el provides a major mode for reading EPUB documents.

Features:

  • Basic navigation (jump to TOC, previous/next chapter)
  • Remembering and restoring the last read position
  • Jump to next chapter when scrolling beyond end
  • Storing and following Org links to EPUB files
  • Renders EPUB2 (.ncx) and EPUB3 (<nav>) TOCs
  • Hyperlinks to internal and external targets
  • Supports textual and image documents
  • Info-style history navigation
  • View source of document files
  • Info-style incremental search
  • Metadata display
  • Image rescaling
(use-package nov)
(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))
(setq nov-text-width t)
(add-hook 'nov-mode-hook 'visual-line-mode)
(add-hook 'nov-mode-hook 'visual-fill-column-mode)

ERC

ERC is an IRC client. It is included in Emacs as of version 22.3

(setq erc-autojoin-mode t)
(setq erc-autojoin-timing 'ident)
(setq erc-button-mode t)
(setq erc-fill-mode t)
(setq erc-hide-list '("QUIT"))
(setq erc-irccontrols-mode t)
(setq erc-join-buffer 'buffer)
(setq erc-list-mode t)
(setq erc-match-mode t)
(setq erc-menu-mode t)
(setq erc-modules
 '(autojoin button completion fill irccontrols list match menu move-to-prompt netsplit networks noncommands readonly ring services stamp))
(setq erc-move-to-prompt-mode t)
(setq erc-netsplit-mode t)
(setq erc-networks-alist
   '((4-irc "4-irc.com")
         (A5KNet "a5knet.com")
         (Zurna "zurna.net")))
(setq erc-networks-mode t)
(setq erc-nick "DrOps")
(setq erc-nick-uniquifier "s")
(setq erc-noncommands-mode t)
(setq erc-pcomplete-mode t)
(setq erc-prompt-for-nickserv-password nil)
(setq erc-prompt-for-password nil)
(setq erc-readonly-mode t)
(setq erc-ring-mode t)
(setq erc-server "irc.libera.chat")
(setq erc-server-alist
   '(("4-irc: Random server" 4-irc "4-irc.com" 6667)
         ("A5KNet: Random server" A5KNet "irc.a5knet.com"
          ((6660 6669)))
         ("Zurna: Random server" Zurna "irc.zurna.net" 6667)))
(setq erc-services-mode t)
(setq erc-speedbar-sort-users-type 'alphabetical)
(setq erc-stamp-mode t)
(setq erc-system-name "plaindrops.de")
(setq erc-track-minor-mode t)
(setq erc-track-mode t)
(setq erc-user-full-name "Andy Drop")

Ledger

Ledger is a command-line accounting tool by JohnWiegley, it provides a double-entry accounting ledger. The input file is a very simple text file.

You can get it from here: https://github.com/ledger/ledger-mode

Ledger comes with a ledger-mode and a function to add new entries. Here is an alternate entry function. The accounts are in German. All accounts for my expenses start with “Ausgaben:”. All accounts for my capital start with “Vermögen:” (basically I can take money from my cash reserves, or from one of my bank accounts).

(use-package compile)
(add-to-list 'compilation-error-regexp-alist-alist '(ledger "\"\\([A-Za-z0-9\\./]+\\)\", line \\([0-9]+\\)" 1 2))
(add-to-list 'compilation-error-regexp-alist 'ledger)


  (use-package ledger-mode)
  (setq ledger-default-date-format "%Y-%m-%d")
  (setq ledger-schedule-file "~/fin/schedule.ledger")
  (setq ledger-accounts-file "~/fin/accounts.ledger")
  (setq ledger-clear-whole-transactions t)

  (setq ledger-post-account-alignment-column 2)
  (setq ledger-post-amount-alignment-at :decimal)
  (setq ledger-post-amount-alignment-column 58)

  (setq ledger-reconcile-default-date-format "%Y-%m-%d")
  (setq ledger-reconcile-default-commodity "€")

  (setq ledger-report-auto-width t)
  (setq ledger-report-use-strict t)

  (add-hook 'ledger-mode-hook
              (lambda ()
                (setq-local tab-always-indent 'complete)
                (setq-local completion-cycle-threshold t)
                (setq-local ledger-complete-in-steps t)))

  (setq ledger-schedule-look-forward 7)
  (setq ledger-schedule-week-days
          '(("Mo" 1)
            ("Di" 2)
            ("Mi" 3)
            ("Do" 4)
            ("Fr" 5)
            ("Sa" 6)
            ("So" 0)))
  (setq ledger-reports
          '(("Hauszahlungen" "ledger reg Hauszahlung")
            ("Bestand Bausparen" "ledger bal Bausparen:")
            ("Bausparkasse M07 Sparkonto" "ledger reg M07h")
            ("Benzin" "ledger reg Budget:Benzin")
            ("Bestand" "ledger bal --depth 2 Haben Soll")
            ("Bestand Bargeld" "ledger [[ledger-mode-flags]] -f %(ledger-file) bal Bargeld")
            ("Bestand Giro" "ledger bal giro")
            ("Bestand Kreditkarte" "ledger [[ledger-mode-flags]] -f %(ledger-file) bal Kreditkarte")
            ("Budget Leben M07" "ledger reg \"Budget:A:Leben M07\"")
            ("Equity Report" "ledger equity")
            ("Freies Gehalt" "ledger [[ledger-mode-flags]] -f ~/fin/drops.ledger reg Liquid and @Firma")
            ("Privatschulden" "ledger reg Privat")
            ("Steuer- Telefonrechnungen" "ledger reg -p \"last year\" Telefon:Festnetz")
            ("Steuer-Haftpflicht" "ledger reg -p \"last year\" Versicherungen:Haftpflicht")
            ("Steuer-KFZ-Haftpflicht" "ledger reg -p \"last year\" Ausgaben:Mobilität:Auto:Versicherungen")
            ("Steuer-Kaminkehrer" "ledger reg -p \"last year\" Kaminkehrer")
            ("Steuer-Lebensversicherung" "ledger reg -p \"last year\" Ausgaben:Versicherungen:Leben")
            ("Steuer-Unfallversicherung" "ledger reg -p \"last year\" Ausgaben:Versicherungen:Unfall")
            ("Steuer-Versicherungen" "ledger reg -p \"last year\" Telefon:Festnetz")
            ("Steuern-Rente" "ledger reg -p \"last year\" Einnahmen:Rente:Andy")
            ("Verlauf Barclay" "ledger reg Kreditkarte")
            ("Verlauf Bargeld" "ledger [[ledger-mode-flags]] -f %(ledger-file) reg Bargeld")
            ("Verlauf Bausparen" "ledger reg Bausparen:M0")
            ("Verlauf Gas" "ledger reg Budget:A:Gas")
            ("Verlauf Girokonto" "ledger reg Giro")
            ("Verlauf Haftpflicht" "ledger reg Budget:A:Haftpflicht")
            ("Verlauf Kreditkarte" "ledger [[ledger-mode-flags]] -f %(ledger-file) reg Kreditkarte")
            ("Verlauf M07" "ledger reg Bausparen:M07")
            ("Verlauf M07h" "ledger reg Haben:Bausparen:M07")
            ("Verlauf M08" "ledger reg Bausparen:M08")
            ("Verlauf M08h" "ledger reg Haben:Bausparen:M08")
            ("Verlauf M08s" "ledger reg Soll:Bausparen:M08")
            ("Verlauf M09" "ledger reg Bausparen:M09")
            ("Verlauf M09h" "ledger reg Haben:Bausparen:M09")
            ("Verlauf Zinsen" "ledger reg Ausgaben:Finanzen:Zinsen")
            ("Verlauf" "ledger reg Haben Soll")
            ("Verlauf-Barclaycard" "ledger [[ledger-mode-flags]] -f ~/fin/drops.ledger reg Soll:Kreditkarte")
            ("Verlauf-Bargeld" "ledger [[ledger-mode-flags]] -f %(ledger-file) reg Bargeld")
            ("account" "%(binary) -f %(ledger-file) reg %(account)")
            ("budget" "%(binary) budget -f %(ledger-file) ")
            ("payee" "%(binary) -f %(ledger-file) reg @%(payee)")
            ("reg Budget:Leben" "ledger reg Budget:Leben ")
            ("reg M07" "ledger reg M07h")
            ("reg reminder" "ledger reg reminder")))

(add-hook 'ledger-report-mode-hook 'compilation-minor-mode)

Mail

(org-link-set-parameters "cbthunderlink" :follow #'org-cbthunderlink-open)
(defun org-cbthunderlink-open (path)
(start-process "cbthunderlink" nil "/home/andy/.local/bin/cbthunderbird/cb_thunderlink"  (concat "cbthunderlink:"  path)))

Org-mode

Org-mode is an Emacs mode for note keeping, project planning, TODO lists and authoring. It is included from Emacs 22.1 onward as default.

(setq org-ellipsis " ▼")
(setq org-export-with-toc 2)
(setq org-image-actual-width 480)
(setq org-indirect-buffer-display 'current-window)
(setq org-roam-db-autosync-mode t)
(setq org-roam-directory "/home/andy/wiki")
(setq org-src-block-faces 'nil)
(setq org-support-shift-select 'always)
(setq org-tags-column -64)
(setq org-todo-keywords
      '((sequence "proj(p)" "TODO(t)" "wait(w)" "NEXT(n)" "|" "DONE(d)" "stop(s)" "forw(f)")))
(setq org-todo-repeat-to-state "NEXT")
(setq org-use-property-inheritance '("GTD"))
(setq org-use-speed-commands t)

Startup

   (setq org-startup-align-all-tables t)
   (setq org-startup-folded 'content)
   (setq org-startup-with-inline-images t)

   (setq org-stuck-projects '("Project=\"t\"" ("NEXT") nil ""))
   (setq org-support-shift-select t)
   (setq org-tags-column -64)
   (setq org-tags-exclude-from-inheritance '("crypt"))
   (setq org-todo-keywords   '((sequence "proj(p)" "TODO(t)" "wait(w)" "NEXT(n)" "|" "DONE(d)" "stop(s)" "forw(f)")))
   (setq org-todo-repeat-to-state "NEXT")
   (setq org-use-property-inheritance '("GTD"))
  (setq org-blank-before-new-entry '((heading . t) (plain-list-item . t)))
  (setq org-closed-keep-when-no-todo t)
  (setq org-confirm-babel-evaluate nil)

Special-Block-Extras

An Org mode block is a region of text surrounded by #+BEGIN_𝒳 … #+END_𝒳; they serve various purposes as summarised in the table below. However, we shall use such blocks to execute arbitrary code on their contents .

Name Description
example Format text verbatim, leaving markup as is
src Format source code
center Centre text
quote Format text as a quotation —ignore line breaks
verse Every line is appended with a line break
tiny Render text in a small font; likewise footnotesize
comment Completely omit the text from export
  • They can be folded and unfolded in Emacs by pressing TAB in the #+BEGIN line.
  • The contents of blocks can be highlighted as if they were of language ℒ such as org, html, latex, haskell, lisp, python, … by writing #+BEGIN_𝒳 ℒ on the starting line, where 𝒳 is the name of the block type.
  • Verbatim environments src and example may be followed by switch -n to display line numbers for their contents.
 ;;(use-package org-special-block-extras)

Org-Appear

Auto-toggle Org elements. Website: https://github.com/awth13/org-appear

This package enables automatic visibility toggling of various Org elements depending on cursor position. It supports automatic toggling of emphasis markers, links, subscripts and superscripts, entities, and keywords. By default, toggling is instantaneous and only affects emphasis markers. If Org mode custom variables that control visibility of elements are configured to show hidden parts, the respective `org-appear' settings do not have an effect.

(require 'org-appear)
(setopt org-appear-autokeywords t)
(setopt org-appear-autolinks t)
(setopt org-appear-autosubmarkers t)
(setopt org-appear-delay 0.5)
(setopt org-appear-trigger 'always)

Org Babel

Org Babel is a component of Emacs Org Mode that enables literate programming and reproducible workflows. It allows you to write source code blocks in multiple languages (Python, Emacs Lisp, Shell, etc.) directly inside Org documents. You can execute code, capture results, and export outputs alongside text, tables, or notes. Org Babel supports language-specific header arguments, tangling (extracting code to files), and bidirectional integration with Org properties. It’s ideal for combining documentation, analysis, and programming in a single, shareable Org file, turning notes into executable, reproducible reports.

(setq org-babel-load-languages '((emacs-lisp . t) (plantuml . t) (gnuplot . t) (python . t)))
(setq org-babel-python-command "python3")

(org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages)

Org Social

(setq org-social-file "/home/andy/blog/plaindrops/files/social.org")
(setq org-social-relay "https://relay.org-social.org/")
(setq org-social-my-public-url "https://plaindrops.de/social.org")
  • gnuplot
    ;; load gnuplot mode
    (use-package gnuplot)
    (use-package ob-gnuplot)
    

Org CalDAV

Org CalDAV is an Emacs Org Mode extension that enables synchronization between Org files and CalDAV servers (e.g., Nextcloud, Google Calendar). It allows Org Mode to push and pull events, supporting bidirectional syncing, multiple calendars, and configurable inbox files for unmatched events. Org CalDAV integrates with Org’s scheduling and todo system, making your Org files a full-featured calendar client. It supports automatic or manual synchronization, fine-grained control over which changes are applied, and exporting results quietly. This makes Org CalDAV ideal for users who want to manage calendars entirely within Emacs while staying synchronized with external CalDAV services.

(setq org-caldav-calendar-id "personal")
(setq org-caldav-calendars '((:calendar-id "personal" :inbox "~/org/calendar.org")))
(setq org-caldav-files '("~/org/calendar.org" "~/org/ops.org"))
(setq org-caldav-inbox "~/org/calendar.org")
(setq org-caldav-show-sync-results nil)
(setq org-caldav-sync-changes-to-org 'all)
(setq org-caldav-sync-direction 'twoway)
(setq org-caldav-url
      "https://nextcloud.plaindrops.de/remote.php/dav/calendars/andy")
(setq org-deadline-past-days 21)
(setq org-deadline-warning-days 1)
(setq org-directory "~/org")
(setq org-edna-mode t)
(setq org-edna-use-inheritance t)
(setq org-ellipsis nil)
(setq org-enforce-todo-dependencies t)
(setq org-export-use-babel nil)
(setq org-hide-block-startup t)
(setq org-hide-emphasis-markers t)
(setq org-hide-leading-stars t)
(setq org-html-html5-fancy t)
(setq org-html-toplevel-hlevel 3)
(setq org-icalendar-combined-agenda-file "/tmp/org-caldav-GvSoW8")
(setq org-icalendar-include-todo 'all)
(setq org-icalendar-store-UID t)
(setq org-icalendar-timezone "Europe/Berlin")
(setq org-icalendar-use-deadline '(todo-due))
(setq org-icalendar-use-scheduled '(event-if-not-todo todo-start))
(setq org-image-actual-width 640)
(setq org-journal-date-format "%Y-%m-%d (%A)")
(setq org-journal-dir "~/org/journal/")
(setq org-journal-file-format "Journal-%Y")
(setq org-link-frame-setup
      '((vm . vm-visit-folder-other-frame)
        (vm-imap . vm-visit-imap-folder-other-frame)
        (gnus . org-gnus-no-new-news)
        (file . find-file)
        (wl . wl-other-frame)))
(setq org-link-from-user-regexp "\\<andy\\>")
(setq org-log-done 'time)
(setq org-plantuml-jar-path "/usr/share/plantuml/plantuml.jar")

Org Refile

Org Refile is a feature in Emacs Org Mode that allows you to move or copy headings (entries) between Org files or within a file efficiently. It uses a completion system to quickly select target locations, supporting nested headings, tags, and priorities. Refiling helps keep your Org files organized, for example by moving tasks from an inbox file to project-specific files. It can be configured to limit targets, use caching, or follow outline paths, making it a powerful tool for managing large, structured Org documents and streamlining task organization.

(setq org-refile-allow-creating-parent-nodes 'confirm)
(setq org-refile-use-outline-path nil)
(setq org-refile-use-cache t)
(setq org-refile-targets
      '(("~/org/rezepte.org" :maxlevel . 2)
        ("~/org/links.org" :maxlevel . 4)
        ("~/org/ops.org" :level . 1)
        ("~/org/lyrics.org" :level . 1)
        ;;(ndk/org-refile-candidates :maxlevel . 3)
        ))
(setq org-src-block-faces '(("*" fixed-pitch)))

The following function is explained here

(defun drops/link-heading-with-own-id ()
  "Replace an Org mode heading at point
   with a linked version using its own ID,
   preserving the heading level
   and creating one if it does not already exist."
  (interactive)
  (org-back-to-heading)
  (let* ((heading-level (org-outline-level))
           (heading-start (point))
           (heading-end (line-end-position))
           (heading (nth 4 (org-heading-components)))
           (id (org-entry-get nil "CUSTOM_ID")))
    (if (not id)
          (progn
            (setq id (concat "id-" (md5 heading)))
            (org-set-property "CUSTOM_ID" id)))
    (delete-region heading-start heading-end)
    (insert (format "%s [[#%s][%s]]"
                      (make-string heading-level ?*)
                      id heading)))
  )
(with-eval-after-load 'org
 ;; Add a new emphasis for small text using =s=
 (add-to-list 'org-emphasis-alist
              '("s" ;; Use =s= to mark small text
                (:export-html "<small>" "</small>"
                              :export-latex "{\\small " "}"))))

Org Agenda

Org Agenda is a powerful Emacs Org Mode tool for viewing and managing tasks, schedules, and deadlines across one or multiple Org files. It provides customizable views such as daily/weekly agendas, TODO lists, and tag-based searches. Org Agenda integrates with Org’s scheduling, deadlines, and priorities, allowing quick navigation, task completion, and bulk modifications. It supports filtering, grouping, and sorting, and can display entries from multiple files in a unified interface. This makes Org Agenda ideal for time management, task tracking, and planning, giving Emacs users a comprehensive overview of their commitments and workflow.

(setq org-agenda-files
 '("~/org/ops.org" "~/org/birthday-calendar.org" "~/org/calendar.org" "~/org/Haushalt.org" ))

(setq org-agenda-category-icon-alist '(("todo" "org/icons/todo16.png" nil nil :ascent\ center)))


(setq org-agenda-span 'fortnight)
(setq org-agenda-time-grid
      '((daily today)
        (800 1000 1200 1400 1600 1800 2000)
        "......" "----------------"))
(setq org-agenda-window-setup 'reorganize-frame)

(setq org-agenda-include-diary t)
(setq org-agenda-loop-over-headlines-in-active-region nil)
(setq org-agenda-restore-windows-after-quit t)
(setq org-agenda-show-future-repeats nil)
(setq org-agenda-skip-deadline-prewarning-if-scheduled t)
(setq org-agenda-skip-scheduled-if-deadline-is-shown 'not-today)
(setq org-agenda-skip-scheduled-if-done t)
(setq org-agenda-skip-timestamp-if-deadline-is-shown t)
(setq org-agenda-skip-timestamp-if-done t)
(setq org-agenda-span 10)
(setq org-agenda-start-on-weekday nil)
(setq org-agenda-tags-todo-honor-ignore-options t)
(setq org-agenda-time-leading-zero t)
(setq org-agenda-todo-ignore-scheduled 'future)
(setq org-agenda-window-setup 'current-window)
 (setq org-agenda-custom-commands
        '(("n" "Agenda and all TODOs"
           ((tags "GTD=\"t\"+TODO=\"NEXT\""
                          ((org-agenda-overriding-header "Next Actions")))
                (stuck "" nil)
                (tags-todo "GTD<>\"t\"+CATEGORY<>\"Haushalt\""
                                   ((org-agenda-overriding-header "Sonstige ToDo")))
                (tags-todo "CATEGORY=\"Haushalt\"+SCHEDULED<=\"<+2d>\""
                                   ((org-agenda-overriding-header "Haushalt")))
                (agenda "" nil))
           nil
           ("~/org/agenda.txt" "~/org/agenda.html"))))
(setq org-icalendar-combined-agenda-file "/tmp/org-caldav-wtBkYE")
(setq org-outline-path-complete-in-steps t)

Org Capture

Capture lets you quickly store notes with little interruption of your work flow. Org’s method for capturing new items is heavily inspired by John Wiegley’s excellent Remember package.

(use-package org-protocol)

The following customization sets a default target file for notes.

(setq org-default-notes-file (concat org-directory "/ops.org"))
(setq org-capture-templates '(
                              ("g" "Gutschein" table-line (file+headline "~/org/nummern.org" "Gutscheine")
                               "| %? | Thema | Nummer | 10\342\202\254 | Mindestbestellwert | 2020-12-31 |")

                              ("Q" "Quotelink" entry (file+headline "~/wiki/20221010T232442--zitate__quotes.org" "Inbox")
                               "** %i
:PROPERTIES:
:TITLE: %:description:
:URL: %:link
:SAVED: %<%Y-%m-%d>
:END:

,,,#+BEGIN_QUOTE
%i
[[%:link][%:description]]
,,,#+END_QUOTE

" :immediate-finish t)
                              ("p" "Project" entry(file+headline "~/org/ops.org" "Projects")
                               "* [/] %?%:description :project:")

                              ("t" "ToDo" entry (file+headline "~/org/ops.org" "--- ToDo's ---")
                               "* %?" :empty-lines 1)
  • Capture's for journaling.
         ("j" "Journal")
         ("jj" "Log" plain (file+olp+datetree "~/org/journal.org" "Log")
          "     %?"
       :empty-lines 1 :time-prompt t)
    
         ("jt" "Traum Log" entry (file+olp+datetree "~/org/journal.org" "Log")
          "***** Traum
    
          %?"
        :empty-lines 1)
    
    
    ("jp" "Phasen" entry (file+headline "~/org/journal.org" "Phasen")
     ""  :empty-lines 1)
    ("jw" "Wendepunkte"  entry (file+headline "~/org/journal.org" "Wendepunkte" )
     "":empty-lines 1)
    ("jn" "The Now"  entry (file+headline "~/org/journal.org" "Now" )
     "":empty-lines 1)   
    
  • Captures for Finance
    ("b" "Barclay Buchung" plain (file "~/fin/drops.ledger")
     "%<%Y-%m-%d>   %?
      Ausgaben:Haushalt:Sonstiges                            %x
      Soll:Kreditkarte                                      -%x
      Budget:Kreditkarte                                     %x
      Giro
    
    " :empty-lines 1)
    ("f" "Finanzen in Ledger" plain (file "~/org/finanzen.ledger")
     "%(shell-command-to-string (format \"ledger xact %s %s\" (substring \"%:date\" 1 11) \"%:description\"))                                    " :immediate-finish t :empty-lines 1)
    ))
    

Crypt

If you just want to encrypt the text of an entry, but not the headline, or properties you can use org-crypt. In order to use org-crypt you need to add something like the following to your .emacs:

  (use-package org-crypt)
  ;; GPG key to use for encryption
  ;; Either the Key ID or set to nil to use symmetric encryption.
  (setq org-crypt-key "CABFD3324FD3279F63070228F58A421AE336FFBD")
  (setq epa-pinentry-mode 'loopback)

Entries with a :crypt: tag will be automatically be encrypted when you save the file.

  (org-crypt-use-before-save-magic)

Preventing tag inheritance stops you having encrypted text inside encrypted text.

  (setq org-tags-exclude-from-inheritance (quote ("crypt")))
  • Emacs Backup Files - a Warning.

    With org-crypt, if you have autosave turned on and decrypt the entries, the autosave file will contain the entries in plain text. For this reason your should disable autosave for encrypted files.

      (setq org-crypt-disable-auto-save t)
    

    Now any text below a headline that has a :crypt: tag will be automatically be encrypted when the file is saved. If you want to use a different tag just customize the org-crypt-tag-matcher setting. To decrypt the text just call M-x org-decrypt-entry and the encrypted text where the point is will be replaced with the plain text. If you use this feature a lot, you will probably want to bind M-x org-decrypt-entry to a key.

Download

https://github.com/abo-abo/org-download

  (use-package org-download)

  ;; Drag-and-drop to `dired`
  (add-hook 'dired-mode-hook 'org-download-enable)
  (add-hook 'org-mode-hook 'org-download-enable)
 (setq org-download-abbreviate-filename-function 'expand-file-name)
 (setq org-download-heading-lvl nil)
 (setq org-download-image-attr-list '(""))
 (setq org-download-method 'directory)         ;; save dragged images to a directory
 (setq org-download-image-dir "~/wiki/images") ;; directory name for saved images
 (setq org-download-image-html-width 640)
 (setq org-download-image-org-width 320)
 (setq org-download-screenshot-method "scrot -s %s")
 (setq org-download-image-dir "images")        
 (setq org-download-link-format "[[file:%s]]")  ;; how to insert the link

Linking

  • Custom GPT Links in Emacs Org Mode

    The custom links are designed to point to a hypothetical URL in the format:

    https://chatgpt.com/c/%3CGUID%3E

    where GUID is the unique identifier created for the link. This setup allows you to easily insert and manage GPT-related links directly in your Org documents, open them in your browser, and export them cleanly to HTML or other formats.

    The code below provides:

    • Functions to follow and export the links.
    • Registration of the "gpt" custom link type with Org Mode.
    (defun my/org-gpt-open (path)
      "Open a GPT custom link with PATH as GUID."
      (browse-url (format "https://chatgpt.com/c/%s" path)))
    
    (defun my/org-gpt-export (path _desc _format)
      "Export GPT links as HTML links."
      (format "<a href=\"https://chatgpt.com/c/%s\">GPT Chat</a>" path))
    
    ;; Register the custom link type
    (org-link-set-parameters
     "gpt"
     :follow #'my/org-gpt-open
     :export #'my/org-gpt-export
     :help-echo "Open GPT chat session")
    
  • GeoLink
      (load (concat user-emacs-directory "lisp/org-geolink.el"))
      (use-package org-geolink)
    
  • Youtube

    Youtube links in org-mode, see https://emacs.stackexchange.com/questions/38098/org-mode-custom-youtube-link-syntax

    After installing and loading this library in emacs you can use links with the format

    yt:<video-id>

    or

    [yt:<video-id>][description]

    in your org-mode document. If you display inline-images in org-mode the link is replaced by the image for the video downloaded from youtube. When you click on the link or on the image the video-url is opened in the browser.

     (load (concat user-emacs-directory "lisp/org-yt.el"))
     (use-package org-yt)
    

PDFview

Out of the box, org-mode doesn't know about pdf-tools. However, you can add support for opening org links to pdf files with org-pdfview, which is available as a package on MELPA. Once it's installed, you can activate it with the following code in your .emacs:

 (eval-after-load 'org '(use-package org-pdfview))

 (add-to-list 'org-file-apps 
              '("\\.pdf\\'" . (lambda (file link)
                                      (org-pdfview-open link))))

Doing this will provide a new completion target for adding links via C-c C-l, pdfview:, with support for jumping to specific pages.

Ready-Player

(use-package ready-player)
(setq ready-player-mode +1)
(setq ready-player-my-media-collection-location "/home/andy/aud/music")

Terminal

I use the Fish shell, which isn't POSIX-compatible. To avoid issues with Emacs subprocesses that expect a POSIX shell, I tell Emacs to use Bash internally when my login shell is Fish.

(when (string-match-p "fish" (or (getenv "SHELL") ""))
  (setq shell-file-name "/bin/bash"))

I want Emacs to inherit the same environment variables as my Fish shell, so I use exec-path-from-shell to import PATH and other settings.

(use-package exec-path-from-shell)
(exec-path-from-shell-initialize)

In vterm, I prefer to use Fish interactively. This way, my terminal sessions inside Emacs behave just like in my regular shell.

(setq vterm-shell "fish")

Killing the buffer makes 100% sense to me, actually it annoys me that it stays alive.

(add-hook 'vterm-exit-functions
          (lambda (_ _)
            (let* ((buffer (current-buffer))
                   (window (get-buffer-window buffer)))
              (when (not (one-window-p))
                (delete-window window))
              (kill-buffer buffer))))

Shell-Here

Open a shell buffer in (or relative to) default-directory, e.g. whatever directory the current buffer is in. If you have projectile or find-file-in-project installed, you can also move around relative to the root of the current project.

I use Emacs shell buffers for everything, and shell-here is great for getting where you need to quickly. Projectile / FFIP integration makes it very easy to manage multiple shells and maintain your path / history / scrollback when switching between projects.

(use-package cl-lib)

(defun shell-at-dir (dir)
  "Open a shell at DIR.
If a shell buffer visiting DIR already exists, show that one."
  (interactive (list default-directory))
  (let ((buf (car (cl-remove-if-not
                   (lambda (it)
                     (with-current-buffer it
                       (and (derived-mode-p 'shell-mode)
                            (equal default-directory dir))))
                   (buffer-list)))))
    (if buf
        (switch-to-buffer buf)
      (shell (generate-new-buffer-name "*shell*")))))

Treemacs

  (use-package treemacs)
       (setq treemacs-collapse-dirs 3)
       (setq treemacs-filewatch-mode t)
       (setq treemacs-follow-mode t)
       (setq treemacs-fringe-indicator-mode t)
       (setq treemacs-git-mode t)
       (setq treemacs-project-follow-cleanup t)
       (setq treemacs-select-when-already-in-treemacs 'next-or-back)
       (setq treemacs-is-never-other-window t)
       (setq treemacs-missing-project-action 'keep)

;; Treemacs beim Start von Emacs automatisch öffnen
(add-hook 'after-init-hook
          (lambda ()
            (treemacs)))

Minor Modes

(menu-bar-mode -1) 
(toggle-scroll-bar -1) 
(tool-bar-mode -1) 

Abbrev-mode

See also: DynamicAbbreviations

Emacs has a nice feature to expand abbreviations. If for example, you wanted an abbreviation for ‘Your Name’ to be ‘yn’, just type ‘yn’ and with your point after the ‘n’ do C-x a i g (mnemonic add inverse global) and enter the expansion, in this case ‘Your Name’. In the future, whenever you type ‘yn’ your name will be inserted. The abbrevs are automatically saved between sessions in a file ~/.abbrev_defs .

I find this most useful for fixing typos. Whenever you have a typo (I type ‘becasue’ almost every time) if you are religious (see alt.religion.emacs) and never correct it but instead do C-x a i g and enter the correct spelling, emacs will fix all your typos, and you can type like a reckless madman and emacs will clean up the mess behind you. See AutoCorrection.

If you don’t like an abbrev that you have set up, then do M-x edit-abbrevs. You can have different abbrevs for each mode (cperl, c++, Message); the g in C-x a i g is for global, meaning every mode.

See the Abbrevs node in the emacs info for more.

(add-hook 'text-mode-hook #'abbrev-mode)

Afterglow

(use-package afterglow)
(afterglow-mode 1)

;; Optional
(setq afterglow-default-duration 0.5)
(setq afterglow-default-face 'hl-line)

;; Example 1:
(afterglow-add-triggers
 '((evil-previous-visual-line :thing line :width 5 :duration 0.2)
   (evil-next-visual-line :thing line :width 5 :duration 0.2)
   (previous-line :thing line :duration 0.2)
   (next-line :thing line :duration 0.2)
   (eval-buffer :thing window :duration 0.2)
   (eval-defun :thing defun :duration 0.2)
   (eval-expression :thing sexp :duration 1)
   (eval-last-sexp :thing sexp :duration 1)
   (my-function :thing my-region-function :duration 0.5 
                :face 'highlight)))

Consult

Corral

Corral is a lightweight package that lets you quickly wrap parentheses and other delimiters around text, intuitively surrounding what you want it to using just two commands.

(use-package corral)

Call a command once to wrap delimiters around the sexp at point. Repeated calls of the same command, backward or forward, will shift the delimiters in the respective direction, corralling more text.

Keep point position instead of following delimiters

This is controlled by the variable corral-preserve-point, which can be set manually or through customize.

(setq corral-preserve-point t)

dame

(load (concat user-emacs-directory "lisp/dame.el"))
(load (concat user-emacs-directory "lisp/dame-org-rifle.el"))
(load (concat user-emacs-directory "lisp/dame-org-ql.el"))

edna

Extensible Dependencies ’N’ Actions (EDNA) for Org Mode tasks

Edna provides an extensible means of specifying conditions which must be fulfilled before a task can be completed and actions to take once it is.

Org Edna runs when either the BLOCKER or TRIGGER properties are set on a heading, and when it is changing from a TODO state to a DONE state.

For brevity, we use TODO state to indicate any state in org-not-done-keywords, and DONE state to indicate any state in org-done-keywords.

(use-package org-edna)
(setq orgstuck-keywords '("project" ("NEXT") nil ""))

(setq Org-todo-repeat-to-state "NEXT")

(org-edna-mode)

Embark (Emacs Mini-Buffer Actions Rooted in Keymaps)

This package provides a sort of right-click contextual menu for Emacs, accessed through the embark-act command (which you should bind to a convenient key), offering you relevant actions to use on a target determined by the context:


Flymake

(setq flymake-error-bitmap '(flymake-double-exclamation-mark modus-themes-fringe-red))
(setq flymake-note-bitmap '(exclamation-mark modus-themes-fringe-cyan))
(setq flymake-warning-bitmap '(exclamation-mark modus-themes-fringe-yellow))

Golden Ratio

When working with many windows at the same time, each window has a size that is not convenient for editing.

golden-ratio helps on this issue by resizing automatically the windows you are working on to the size specified in the "Golden Ratio". The window that has the main focus will have the perfect size for editing, while the ones that are not being actively edited will be re-sized to a smaller size that doesn't get in the way, but at the same time will be readable enough to know it's content.

(use-package golden-ratio)
(golden-ratio-mode 0)

Jinx

Jinx is a fast just-in-time spell-checker for Emacs. Jinx highlights misspelled words in the text of the visible portion of the buffer. For efficiency, Jinx highlights misspellings lazily, recognizes window boundaries and text folding, if any. For example, when unfolding or scrolling, only the newly visible part of the text is checked if it has not been checked before. Each misspelling can be corrected from a list of dictionary words presented as a completion menu.

Jinx has two modes: the command, global-jinx-mode activates globally; and the command, jinx-mode, for activating for specific modes.

(use-package jinx)
;; Alternative 1: Enable Jinx globally
(add-hook 'emacs-startup-hook #'global-jinx-mode)

;; Alternative 2: Enable Jinx per mode
;;(dolist (hook '(text-mode-hook prog-mode-hook conf-mode-hook))
;;  (add-hook hook #'jinx-mode))

Line-Wrapping

Visual Line Mode und Visual Fill Column sind beide Emacs-Funktionen, die den Umgang mit langen Zeilen verbessern, aber sie arbeiten auf unterschiedliche Weise und haben unterschiedliche Anwendungsfälle.

Visual Line Mode

  • Zweck: Bricht lange Zeilen optisch um, ohne den eigentlichen Text zu ändern.
  • Verhalten:
    • Zeilen werden am Fensterrand umgebrochen, aber die Datei bleibt unverändert.
    • Nützlich für das Lesen von Texten mit langen Zeilen (z. B. Prosa, Markdown, Org-Mode).
    • Keine Änderungen an der Datei selbst.
  • Aktivierung:
(add-hook 'text-mode-hook #'visual-line-mode)
(add-hook 'markdown-mode-hook #'visual-line-mode)
(add-hook 'org-mode-hook #'visual-line-mode)

Visual Fill Column Mode

Wird benötigt für den Writeroom-Mode.

  • Zweck: Bricht lange Zeilen tatsächlich an einer bestimmten Spaltenbreite um und fügt Zeilenumbrüche in den Text ein.
  • Verhalten:
    • Fügt tatsächliche Zeilenumbrüche in den Text ein, um die Zeilenlänge zu begrenzen.
    • Nützlich für das Bearbeiten von Texten, bei denen die Zeilenlänge begrenzt werden soll (z. B. Quellcode-Kommentare, E-Mails, LaTeX).
    • Ändert die Datei dauerhaft.
  • Aktivierung:
;; Vorausgesetzt, visual-fill-column ist installiert
(use-package visual-fill-column)

;; Gemeinsame Setup-Funktion

(setq-default  fill-column 100)
     ;; gewünschte Textbreite


;; Aktivieren in relevanten Modi
;;(add-hook 'visual-line-mode-hook #'visual-fill-column-mode)

Marginalia

This package provides marginalia-mode which adds marginalia to the minibuffer completions. Marginalia are marks or annotations placed at the margin of the page of a book or in this case helpful colorful annotations placed at the margin of the minibuffer for your completion candidates. Marginalia can only add annotations to be displayed with the completion candidates. It cannot modify the appearance of the candidates themselves, which are shown as supplied by the original commands.

The annotations are added based on the completion category. For example find-file reports the file category and M-x reports the command category. You can cycle between more or less detailed annotators or even disable the annotator with command marginalia-cycle

(use-package marginalia)
(marginalia-mode)

Consult provides practical commands based on the Emacs completion function completing-read. Completion allows you to quickly select an item from a list of candidates. Consult offers in particular an advanced buffer switching command consult-buffer to switch between buffers and recently opened files. Furthermore Consult provides multiple search commands, an asynchronous consult-grep and consult-ripgrep, and the line-based search command consult-line. Some of the Consult commands are enhanced versions of built-in Emacs commands. For example the command consult-imenu presents a flat list of the Imenu with live preview, grouping and narrowing. Please take a look at the full list of commands.

Consult is fully compatible with completion systems centered around the standard Emacs completing-read API, notably the default completion system, Vertico, Mct, and Icomplete.

This package keeps the completion system specifics to a minimum. The ability of the Consult commands to work well with arbitrary completion systems is one of the main advantages of the package. Consult fits well into existing setups and it helps you to create a full completion environment out of small and independent components.

(use-package consult)

Orderless

This package provides an orderless completion style that divides the pattern into space-separated components, and matches candidates that match all of the components in any order. Each component can match in any one of several ways: literally, as a regexp, as an initialism, in the flex style, or as multiple word prefixes. By default, regexp and literal matches are enabled.

(use-package orderless)
(setq completion-styles '(substring orderless)
      completion-category-defaults nil
      completion-category-overrides '((file (styles partial-completion))))
(setq Linum-format "%7i ")
(setq after-save-hook '(org-babel-tangle))
;;(setq ansi-color-faces-vector [default bold shadow italic underline success warning error])
;;(setq ansi-color-map '((ansi-color-make-color-map) t))
;;(setq ansi-color-names-vector ["#454545" "#d65946" "#6aaf50" "#baba36" "#598bc1" "#ab75c3" "#68a5e9" "#AAB0AB"])
(setq auto-revert-avoid-polling t)
(setq awesome-tray-mode-line-active-color "#2fafff")
(setq awesome-tray-mode-line-inactive-color "#323232")
(setq backup-directory-alist '(("." . "~/.backup")))
(setq beacon-color "#ed0547ad8099")
(setq blink-cursor-mode nil)
;;(setq bmkp-last-as-first-bookmark-file concat)
(setq browse-url-firefox-new-window-is-tab t)
(setq browse-url-firefox-program "/home/andy/.local/bin/firefox")
(setq cal-tex-which-days '(1 2 3 4 5 6 0))
(setq column-number-mode t)
(setq compilation-message-face 'default)
(setq completion-styles '(substring orderless))
(setq confirm-kill-processes nil)
(setq consult-preview-key '(:debounce 0.5 any))
(setq create-lockfiles nil)
(setq cua-auto-tabify-rectangles nil)
(setq cua-mode t)
(setq cua-normal-cursor-color "black")
(setq custom-buffer-style 'link)
(setq custom-enabled-themes '(DrOps))
(setq custom-file "~/.config/emacs/custom.el")
(setq custom-safe-themes
         '("263e3a9286c7ab0c4f57f5d537033c8a5943e69d142e747723181ab9b12a5855" "fe497072cd9ff25d187db65196b2910d78c938ed71bd3991163f3da6fda62757" "f3c9e341d20be3c006cc8bccb309ef439083d47fed664b4a23133e67b1f8cab8" "92f458ebdf4a4a84f7ff089d58d8c097f09dbf5a4870151a02d257a8574e8671" "043eacb4b2b51cdce979f24b38407e2c6a8f199bafd134e4b9002106ea96c6ad" default))
(setq default-input-method "german-postfix")
(setq diary-date-forms
 '((month "-" day "[^-0-9]")
           (year "[-/]" month "[-/]" day "[^0-9]")
           (dayname "\\W")))
(setq diary-file "~/org/diary")
(setq diary-number-of-entries 7)
(setq dictcc-destination-lang "en")
(setq dictcc-languages-alist
 '(("English" . "en")
           ("German" . "de")
           ("Swedish" . "sv")
           ("Icelandic" . "is")
           ("Russian" . "u")
           ("Romanian" . "ro")
           ("Italian" . "it")
           ("French" . "fr")
           ("Portuguese" . "pt")
           ("Hungarian" . "hu")
           ("Dutch" . "nl")
           ("Slovak" . "sk")
           ("Latin" . "la")
           ("Finnish" . "fi")
           ("Spanish" . "es")
           ("Bulgarian" . "bg")
           ("Croation" . "hr")
           ("Norwegian" . "no")
           ("Czech" . "cs")
           ("Danish" . "da")
           ("Turkish" . "tr")
           ("Polish" . "pl")
           ("Serbian" . "sr")
           ("Greek" . "el")
           ("Esperanto" . "eo")
           ("Bosnian" . "bs")
           ("Albanian" . "sq")))
(setq dictcc-source-lang "de")
(setq diff-hl-show-hunk-posframe-internal-border-color "#357535753575")
(setq dired-auto-revert-buffer t)
(setq dired-do-revert-buffer '(lambda (dir) (not (file-remote-p dir))))
(setq dired-kill-when-opening-new-dired-buffer t)
(setq display-time-use-mail-icon t)
(setq dnd-open-file-other-window t)
(setq ediff-merge-split-window-function 'split-window-horizontally)
(setq ediff-split-window-function 'split-window-horizontally)
(setq ediff-use-last-dir t)
(setq ediff-window-setup-function 'ediff-setup-windows-default)
(setq electric-pair-mode t)
(setq elfeed-goodies/entry-pane-size 0.5)
(setq elfeed-goodies/log-window-position 'right)
(setq emacsshot-with-timestamp t)
(setq eww-search-prefix
"https://duckduckgo.com/?kae=b&kl=de-de&kad=de_DE&kp=-1&kw=w&kak=-1&kah=de-de&kn=-1&kaj=m&kam=osm&kv=-1&kao=-1&kd=-1&kc=-1&kac=-1&k1=-1&kk=-1&kz=-1&q=")
(setq exwm-floating-border-color "#646464")
(setq fci-rule-character-color "#202020")
(setq fci-rule-color "#222222")
 (setq folding-mode-string " fold")
(setq font-lock-global-modes '(not speedbar-mode))
(setq frame-background-mode 'dark)
(setq fringe-mode 4 )
(setq global-auto-revert-mode t)
(global-visual-line-mode 1)
(setq gnus-group-update-tool-bar t)
(setq go-translate-local-language "de")

(setq highlight-changes-colors '("#ff8eff" "#ab7eff"))
(setq highlight-indent-guides-auto-enabled nil)
(setq highlight-symbol-colors
 '("#FFEE58" "#C5E1A5" "#80DEEA" "#64B5F6" "#E1BEE7" "#FFCC80"))
(setq highlight-symbol-foreground-color "#E0E0E0")
(setq highlight-tail-colors
 '(("#323342" . 0)
           ("#63de5d" . 20)
           ("#4BBEAE" . 30)
           ("#1DB4D0" . 50)
           ("#9A8F21" . 60)
           ("#A75B00" . 70)
           ("#F309DF" . 85)
           ("#323342" . 100)))
(setq hl-todo-keyword-faces
 '(("HOLD" . "#c0c530")
           ("TODO" . "#feacd0")
           ("NEXT" . "#b6a0ff")
           ("THEM" . "#f78fe7")
           ("PROG" . "#00d3d0")
           ("OKAY" . "#4ae2f0")
           ("DONT" . "#70b900")
           ("FAIL" . "#ff8059")
           ("BUG" . "#ff8059")
           ("DONE" . "#44bc44")
           ("NOTE" . "#d3b55f")
           ("KLUDGE" . "#d0bc00")
           ("HACK" . "#d0bc00")
           ("TEMP" . "#ffcccc")
           ("FIXME" . "#ff9077")
           ("XXX+" . "#ef8b50")
           ("REVIEW" . "#6ae4b9")
           ("DEPRECATED" . "#bfd9ff")))
(setq hydra-hint-display-type 'posframe)
(setq ibuffer-deletion-face 'diredp-deletion-file-name)
(setq ibuffer-filter-group-name-face 'modus-themes-pseudo-header)
(setq ibuffer-marked-face 'diredp-flag-mark)
(setq ibuffer-title-face 'default)
(setq inhibit-startup-screen t)
(setq keypression-mode t)
(setq keypression-use-child-frame t)
(setq ledger-default-date-format "%Y-%m-%d")
(setq ledger-reconcile-default-commodity " ")
(setq lsp-ui-imenu-colors '("#7FC1CA" "#A8CE93"))
(setq lunar-phase-names
 '("Neumond" "zunehmender Mond" "Vollmand" "abnehmender Mond"))
(setq magit-auto-revert-mode t)
(setq magit-diff-use-overlays nil)
(setq mail-user-agent 'mu4e-user-agent)
(setq main-line-color1 "#1E1E1E")
(setq main-line-color2 "#111111")
(setq main-line-separator-style 'chamfer)
(setq menu-bar-mode nil)
(setq mlscroll-in-color "#56bc56bc56bc")
(setq mlscroll-out-color "#424242")
(setq mm-inline-large-images 'resize)
(setq mml-secure-passphrase-cache-expiry 16)
(setq mode-icons-mode t)
(setq nov-text-width 80)
(setq nrepl-message-colors
 '("#CC9393" "#DFAF8F" "#F0DFAF" "#7F9F7F" "#BFEBBF" "#93E0E3" "#94BFF3" "#DC8CC3"))
(setq omnisharp-auto-complete-popup-help-delay 2000)
(setq pass-username-fallback-on-filename t)
(setq password-cache-expiry nil)
(setq password-store-password-length 16)
(setq pdf-view-midnight-colors '("#ffffff" . "#100f10"))
(setq plantuml-jar-path "/usr/share/plantuml/plantuml.jar")
(setq pos-tip-background-color "#E6DB74")
(setq pos-tip-foreground-color "#242728")
(setq powerline-color1 "#1E1E1E")
(setq powerline-color2 "#111111")
(setq require-final-newline t)
(setq revert-without-query nil)
(setq rmail-movemail-program "/usr/bin/movemail")
(setq rmh-elfeed-org-files '("~/org/feeds.org"))
(setq rmh-elfeed-org-tree-id "feeds")
(setq safe-local-variable-values
 '((org-roam-mode . t)
           (org-roam-directory . "~/org/odo/")
           (initial-major-mode . dokuwiki-mode)))
(setq same-window-buffer-names '("shell"))
(setq save-abbrevs 'silently)
(setq scroll-bar-mode nil)
(setq send-mail-function 'smtpmail-send-it)
(setq size-indication-mode t)
(setq small-temporary-file-directory "/tmp/")
(setq tab-always-indent 'complete)
(setq tab-width 4)
(setq tabbar-background-color "#357535753575")
(setq tool-bar-mode nil)
(setq tooltip-mode t)
(setq tree-widget-themes-directory "tree-widget")
(setq user-mail-address "dr.ops@mailbox.org")
(setq vc-annotate-background "#3C4C55")
(setq vc-annotate-background-mode nil)
(setq vc-annotate-color-map
 `((20 \, "#DF8C8C")
           (40 \, "#e3af97978d26")
           (60 \, "#e780a2a28dc0")
           (80 \, "#eb50adac8e5a")
           (100 \, "#ef21b8b88ef4")
           (120 \, "#F2C38F")
           (140 \, "#ee20c861905c")
           (160 \, "#e94eccff912a")
           (180 \, "#e47dd19d91f7")
           (200 \, "#dfabd63b92c5")
           (220 \, "#DADA93")
           (240 \, "#d0d0d8719393")
           (260 \, "#c6c6d6089393")
           (280 \, "#bcbcd39f9393")
           (300 \, "#b2b2d1369393")
           (320 \, "#A8CE93")
           (340 \, "#a13ac894a409")
           (360 \, "#99ccc25bb480")
           (380 \, "#925ebc21c4f7")
           (400 \, "#8af0b5e8d56e")
           (420 \, "#83AFE5")
           (440 \, "#8821aa0fe517")
           (460 \, "#8cbfa470e449")
           (480 \, "#915d9ed1e37c")
           (500 \, "#95fb9932e2ae")
           (520 \, "#9A93E1")))
(setq vc-annotate-very-old-color "#7bae760fb4b4")
(setq vc-follow-symlinks nil)
(setq vdirel-repository "~/.vdir/contacts/contacts")
;;  (setq weechat-color-list   (unspecified "#242728" "#323342" "#F70057" "#ff0066" "#86C30D" "#63de5d" "#BEB244" "#E6DB74" "#40CAE4" "#06d8ff" "#FF61FF" "#ff8eff" "#00b2ac" "#53f2dc" "#f8fbfc" "#ffffff"))
  (setq winner-mode t)
  (setq wl-message-ignored-field-list
   '(".*Received:" ".*Path:" ".*Id:" "^References:" "^Replied:" "^Errors-To:" "^Lines:" "^Sender:" ".*Host:" "^Xref:" "^Content-Type:" "^Precedence:" "^Status:" "^X-*:"))
(setq writeroom-fullscreen-effect 'maximized)
(setq writeroom-global-effects
 '(writeroom-set-alpha writeroom-set-menu-bar-lines writeroom-set-tool-bar-lines writeroom-set-vertical-scroll-bars writeroom-set-bottom-divider-width))
(setq writeroom-major-modes '(elfeed-show-mode elfeed-search-mode))
(setq writeroom-width 100)

Projectile

Projectile is a project interaction library for Emacs. Its goal is to provide a nice set of features operating on a project level without introducing external dependencies. For instance - finding project files is done in pure Emacs Lisp without the use of GNU find.

Projectile also tries to be practical - if some external tools could speed up some task substantially and the tools are available, Projectile will leverage them.

This library provides easy project management and navigation. The concept of a project is pretty basic - just a folder containing special file. Currently git, mercurial and bazaar repos are considered projects by default. If you want to mark a folder manually as a project just create an empty .projectile file in it. Some of projectile’s features:

  • jump to a file in project
  • jump to a project buffer
  • kill all project buffers
  • replace in project
  • multi-occur in project buffers
  • grep in project
  • regenerate project etags
  • visit project in dired
  • run make in a project with a single key chord

More information and installation instructions are available on GitHub.

(use-package projectile)


(define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
(projectile-mode +1)

(setq projectile-project-search-path '("~/prj/"))

(projectile-register-project-type 'nikola '("conf.py")
                  :compile "nikola build"
                  :test "nikola auto"
                  :run "nikola deploy"
                  :test-suffix ".spec")

Applications

Denote

Denote aims to be a simple-to-use, focused-in-scope, and effective note-taking tool for Emacs. It is based on the following core design principles:

Predictability
File names must follow a consistent and descriptive naming convention (The file-naming scheme). The file name alone should offer a clear indication of what the contents are, without reference to any other metadatum. This convention is not specific to note-taking, as it is pertinent to any form of file that is part of the user’s long-term storage (Renaming files).
Composability
Be a good Emacs citizen, by integrating with other packages or built-in functionality instead of re-inventing functions such as for filtering or greping. The author of Denote (Protesilaos, aka “Prot”) writes ordinary notes in plain text ( .txt ), switching on demand to an Org file only when its expanded set of functionality is required for the task at hand (Points of entry).
Portability
Notes are plain text and should remain portable. The way Denote writes file names, the front matter it includes in the note’s header, and the links it establishes must all be adequately usable with standard Unix tools. No need for a database or some specialised software. As Denote develops and this manual is fully fleshed out, there will be concrete examples on how to do the Denote-equivalent on the command-line.
Flexibility
Do not assume the user’s preference for a note-taking methodology. Denote is conceptually similar to the Zettelkasten Method, which you can learn more about in this detailed introduction: https://zettelkasten.de/introduction/. Notes are atomic (one file per note) and have a unique identifier. However, Denote does not enforce a particular methodology for knowledge management, such as a restricted vocabulary or mutually exclusive sets of keywords. Denote also does not check if the user writes thematically atomic notes. It is up to the user to apply the requisite rigor and/or creativity in pursuit of their preferred workflow (Writing metanotes).
Hackability
Denote’s code base consists of small and reusable functions. They all have documentation strings. The idea is to make it easier for users of varying levels of expertise to understand what is going on and make surgical interventions where necessary (e.g. to tweak some formatting). In this manual, we provide concrete examples on such user-level configurations (Keep a journal or diary).
      (use-package denote)

      ;; Remember to check the doc strings of those variables.
      (setq denote-directory (expand-file-name "~/wiki/"))
      (setq denote-known-keywords '("emacs" "philosophy" "politics" "economics"))
      (setq denote-infer-keywords t)
      (setq denote-sort-keywords t)
      (setq denote-file-type 'org) ; Org is the default, set others here
      (setq denote-prompts '(title keywords))


      ;; Pick dates, where relevant, with Org's advanced interface:
      (setq denote-date-prompt-use-org-read-date t)


      ;; Read this manual for how to specify `denote-templates'.  We do not
      ;; include an example here to avoid potential confusion.


      ;; We allow multi-word keywords by default.  The author's personal
      ;; preference is for single-word keywords for a more rigid workflow.
      (setq denote-allow-multi-word-keywords 0)

      (setq denote-date-format nil) ; read doc string

      ;; By default, we fontify backlinks in their bespoke buffer.
      (setq denote-link-fontify-backlinks t)

      ;; Also see `denote-link-backlinks-display-buffer-action' which is a bit
      ;; advanced.
      (setq denote-link-backlinks-display-buffer-action
            '((display-buffer-reuse-window
               display-buffer-in-side-window)
              (side . right)
              (slot . 99)
              (window-width . 0.3)))
      ;; If you use Markdown or plain text files (Org renders links as buttons
      ;; right away)
      ;; (add-hook 'find-file-hook #'denote-link-buttonize-buffer)

      ;; We use different ways to specify a path for demo purposes.
      (setq denote-dired-directories
            (list denote-directory
                  (thread-last denote-directory (expand-file-name "attachments"))
                  (expand-file-name "~/Documents/books")))

      ;; Generic (great if you rename files Denote-style in lots of places):
      ;; (add-hook 'dired-mode-hook #'denote-dired-mode)
      ;;
      ;; OR if only want it in `denote-dired-directories':
      (add-hook 'dired-mode-hook #'denote-dired-mode-in-directories)

      ;; Here is a custom, user-level command from one of the examples we
      ;; showed in this manual.  We define it here and add it to a key binding
      ;; below.
      (defun my-denote-journal ()
        "Create an entry tagged 'journal', while prompting for a title."
        (interactive)
        (denote
         (denote--title-prompt)
         '("journal")))

      ;; Denote DOES NOT define any key bindings.  This is for the user to
      ;; decide.  For example:
      (let ((map global-map))
        (define-key map (kbd "C-c n j") #'my-denote-journal) ; our custom command
        (define-key map (kbd "C-c n n") #'denote)
        (define-key map (kbd "C-c n N") #'denote-type)
        (define-key map (kbd "C-c n d") #'denote-date)
        (define-key map (kbd "C-c n s") #'denote-subdirectory)
        (define-key map (kbd "C-c n t") #'denote-template)
        ;; If you intend to use Denote with a variety of file types, it is
        ;; easier to bind the link-related commands to the `global-map', as
        ;; shown here.  Otherwise follow the same pattern for `org-mode-map',
        ;; `markdown-mode-map', and/or `text-mode-map'.
        (define-key map (kbd "C-c n i") #'denote-link) ; "insert" mnemonic
        (define-key map (kbd "C-c n I") #'denote-link-add-links)
        (define-key map (kbd "C-c n l") #'denote-link-find-file) ; "list" links
        (define-key map (kbd "C-c n b") #'denote-link-backlinks)
        ;; Note that `denote-rename-file' can work from any context, not just
        ;; Dired bufffers.  That is why we bind it here to the `global-map'.
        (define-key map (kbd "C-c n r") #'denote-rename-file)
        (define-key map (kbd "C-c n R") #'denote-rename-file-using-front-matter))

      ;; Key bindings specifically for Dired.
      (let ((map dired-mode-map))
        (define-key map (kbd "C-c C-d C-i") #'denote-link-dired-marked-notes)
        (define-key map (kbd "C-c C-d C-r") #'denote-dired-rename-marked-files)
        (define-key map (kbd "C-c C-d C-R") #'denote-dired-rename-marked-files-using-front-matter))

  ;;    (with-eval-after-load 'org-capture
   ;;   (setq denote-org-capture-specifiers "%l\n%i\n%?")
   ;;   (add-to-list 'org-capture-templates
;;                  '("n" "New note (with denote.el)" plain
 ;;                    (file denote-last-path)
  ;;                   #'denote-org-capture
   ;;                  :no-save t
   ;;                  :immediate-finish nil
   ;;                  :kill-buffer t
   ;;                  :jump-to-captured t)))

      ;; Also check the commands `denote-link-after-creating',
      ;; `denote-link-or-create'.  You may want to bind them to keys as well.
    (defvar my-denote-chordpro-front-matter
      "#!/bin/sh

    # title:      %s
    # date:       %s
    # tags:       %s
    # identifier: %s
    \n"
      "Demo shell script front matter.
    It is passed to `format' with arguments TITLE, DATE, KEYWORDS,
    ID.  Advanced users are advised to consult Info node `(denote)
    Change the front matter format'.")

      (add-to-list 'denote-file-types
             '(ChordPro
               :extension ".cho"
               :date-function denote-date-org-timestamp
               :front-matter denote-org-front-matter
               :title-key-regexp "^#\\+title\\s-*:"
               :title-value-function identity
               :title-value-reverse-function denote-trim-whitespace
               :keywords-key-regexp "^#\\+filetags\\s-*:"
               :keywords-value-function denote-format-keywords-for-org-front-matter
               :keywords-value-reverse-function denote-extract-keywords-from-front-matter
               :link denote-org-link-format
               :link-in-context-regexp denote-org-link-in-context-regexp)
              )

        (define-minor-mode denote-mode
          "Denote is a simple note-taking
          tool for Emacs. It is based on the idea that notes should follow
          a predictable and descriptive file-naming scheme. The file name
          must offer a clear indication of what the note is about, without
          reference to any other metadata. Denote basically streamlines
          the creation of such files while providing facilities to link
          between them. 

          Denote's file-naming scheme is not limited to notes. It can be used
          for all types of file, including those that are not editable in
          Emacs, such as videos. Naming files in a constistent way makes
          their filtering and retrieval considerably easier. Denote
          provides relevant facilities to rename files, regardless of file
          type."
          :lighter " Note"
          :keymap (let ((map
          (make-sparse-keymap)))
                    (define-key map (kbd "C-l") 'denote-link-or-create)
                    (define-key map (kbd "C-n") 'denote-link-after-creating)
                    (define-key map (kbd "<f6>")(lambda () (interactive) (find-file "~/wiki")))
                    map)) 

Kagi

(use-package kagi)

  ;; or use a function, e.g. with the password-store package:
   (setq kagi-api-token (lambda () (password-store-get "Kagi/API")))

  ;; Universal Summarizer settings
  (setq kagi-summarizer-engine "cecil")
  (setq kagi-summarizer-default-language "DE")
  (setq kagi-summarizer-cache t)

Selected

 (use-package selected)
(selected-global-mode)

Whisper

Speech-to-Text interface for Emacs using OpenAI’s whisper speech recognition model. For inference, it uses the C/C++ port whisper.cpp that can run on consumer grade CPU without requiring a high end GPU.

You can capture audio with your input device (microphone) or choose a media file on disk, and have the transcribed text inserted into your Emacs buffer, optionally after translating to English from your local language. This runs offline without having to use non-free cloud services (though quality varies depending on the language).

(add-to-list 'load-path "~/.config/emacs/lisp/whisper")
(use-package whisper)
(setq   whisper-language "de")

GPTel

  (use-package gptel)


(defun get-mistral-api-key ()
  "Retrieve the Mistral API key from the system's secret storage using `secret-tool`.
Assumes the key is stored under the attribute `application=mistral-api`.
Returns the API key as a string, or signals an error if not found."
  (let ((result (call-process "secret-tool" nil t nil "lookup" "service" "ai.mistral.vibe")))
    (if (zerop result)
        (buffer-substring-no-properties (point-min) (point-max))
      (error "Failed to retrieve Mistral API key or key not found in secret storage"))))


  (setq gptel-model   'mistral-small
        gptel-backend
        (gptel-make-openai "MistralLeChat"  ;Any name you want
          :host "api.mistral.ai"
          :endpoint "/v1/chat/completions"
          :protocol "https"
          :key (get-mistral-api-key)  ;can be a function that returns the key
          :models '("mistral-small")))

GPTel-Agent

(use-package gptel-agent)
(gptel-agent-update)

Theme

https://stackoverflow.com/questions/24222362/emacs-configuration-load-theme-only-partially-loads

(setq ef-themes-headings
  '((0 extrabold 2.5)
    (1 bold 2.0)
    (2 bold 1.75)
    (3 bold 1.5)
    (4 bold 1.25)
    (5 bold 1.17)
    (6 bold 1.1)
    (7 bold)
    (8 bold)))

 (if (daemonp)
               (add-hook 'after-make-frame-functions
                   (lambda (frame)
                       (select-frame frame)
                       (load-theme 'ef-dark t)))
               (load-theme 'ef-dark t))

Server

(defun deckserver-set-layout (layout)
  "Set the DeckServer layout to LAYOUT via D-Bus"
  (interactive "Layout: ")
  (let ((result (dbus-call-method
                 :session
                 "de.spacecadet.DeckServer"
                 "/de/spacecadet/DeckServer"
                 "de.spacecadet.DeckServer"
                 "SetLayout"
                 layout)))
    ))

(defun deckserver-set-layout-for-mode ()
  "Set DeckServer layout to the current major mode name."
  (interactive)
  (deckserver-set-layout (symbol-name major-mode)))

(add-hook 'window-selection-change-functions
          (lambda (_window)
            (deckserver-set-layout-for-mode)))
(server-force-delete)
(server-start)
(load (concat user-emacs-directory "medusa.el"))

(add-to-list 'load-path "~/.config/emacs/lisp")
(require 'keymacs)
(keymacs-load-org (concat user-emacs-directory "keymap.org"))

(setq custom-file (concat user-emacs-directory "custom.el"))
(load (concat user-emacs-directory "custom.el"))

(pdf-tools-install)