#-*- mode: org -*-
#+TITLE: basic setup of Emacs
#+AUTHOR: Volker Edelmann
#+EMAIL:  vedelmann@gmx.de
#+STARTUP: indent
#+OPTIONS:  toc:nil
#+OPTIONS:   ^:{}


* Preliminaries

We have to be sure to set *lexical-binding* in the file header to opt into Emacs lexical scope.

#+begin_src emacs-lisp
  ;; -*- coding: utf-8; lexical-binding: t -*-
#+end_src

#+begin_src emacs-lisp
  (provide 'emacs)
#+end_src

* Fixing defaults

Fixing Emacs's defaults is a nontrivial problem. We'll start with UI concerns.

#+begin_src emacs-lisp
  (setq
   ;; No need to see GNU agitprop.
   inhibit-startup-screen t
   ;; No need to remind me what a scratch buffer is.
   initial-scratch-message nil
   ;; Never ding at me, ever.
   ring-bell-function 'ignore
   ;; Save existing clipboard text into the kill ring before replacing it.
   save-interprogram-paste-before-kill t
   ;; Prompts should go in the minibuffer, not in a GUI.
   use-dialog-box nil
   ;; accept 'y' or 'n' instead of yes/no
   ;; the documentation advises against setting this variable
   ;; the documentation can get bent imo
   use-short-answers t
   ;; my source directory
   default-directory "~/"
   ;; prefer newer elisp files
   load-prefer-newer t
   ;; if native-comp is having trouble, there's not very much I can do
   native-comp-async-report-warnings-errors 'silent
   ;; unicode ellipses are better
   truncate-string-ellipsis "…"
   ;; I want to close these fast, so switch to it so I can just hit 'q'
   help-window-select t
   ;; don't keep duplicate entries in kill ring
   kill-do-not-save-duplicates t
   require-final-newline t
   ;; when opening a new file
   confirm-nonexistent-file-or-buffer nil
   ;; kill buffer and attached process without asking
   kill-buffer-query-functions
   (remq 'process-kill-buffer-query-function
	 kill-buffer-query-functions)
   ;; do not ask when reverting buffer
   auto-revert-verbose nil
   revert-without-query '(".*")
   )
#+end_src

It's good that Emacs supports the wide variety of file encodings it does,
but UTF-8 should be the default.

#+begin_src emacs-lisp
  (set-charset-priority 'unicode)
  (prefer-coding-system 'utf-8-unix)
#+end_src

Turn on a few modes to have behavior that's even remotely modern.

#+begin_src emacs-lisp
  (delete-selection-mode t)
  (global-display-line-numbers-mode t)
  (column-number-mode t)
  (savehist-mode t)
  (context-menu-mode t) ;; right mouse click shows commands
  (global-goto-address-mode) ;; URLs should be highlighted and linkified.
  (global-hl-line-mode t)
  (repeat-mode t)
  (winner-mode t)
  (setq x-select-enable-clipboard t)
  (setq yank-pop-change-selection t)
  (setq mouse-drag-copy-region t)
#+end_src

Emacs is super fond of littering filesystems with backups and autosaves, since it was built with the assumption that multiple users could be using the same Emacs instance on the same filesystem. This was valid in 1980. It is no longer the case.

#+begin_src emacs-lisp
  (setq
   make-backup-files nil
   auto-save-default nil
   create-lockfiles nil)
#+end_src

By default, Emacs stores any configuration you make through its UI by writing ~custom-set-variables~ invocations to your
init file, or to the file specified by ~custom-file~. Though this is convenient, it's also an excellent way to cause
aggravation when the variable you keep trying to modify is being set in some ~custom-set-variables~ invocation. We can
disable this by mapping it to a temporary file. (I used to map this to ~/dev/null~, but this started causing a bunch of
inane save dialogues.)

#+begin_src emacs-lisp
  (setq custom-file (make-temp-name "/tmp/"))
#+end_src


Emacs is also in love with showing you its NEWS file; it's bound to like four different keybindings.
Overriding the function makes it a no-op. 

#+begin_src emacs-lisp
  (defalias 'view-emacs-news 'ignore)
  (defalias 'describe-gnu-project 'ignore)
  (defalias 'describe-copying 'ignore)
#+end_src

** Keyboard macros
Fixing inconsistency in naming:

#+begin_src emacs-lisp
(require 'kmacro)
(defalias 'kmacro-insert-macro 'insert-kbd-macro)
(define-key kmacro-keymap (kbd "I") #'kmacro-insert-macro)
#+end_src

* Improving Help
** Better Help

#+begin_src emacs-lisp
  (use-package helpful
    :defer t
    :bind (
           ("C-h ."    . helpful-at-point)
           ([remap display-local-help] . helpful-at-point)
           ([remap describe-function]  . helpful-callable)
           ([remap describe-variable]  . helpful-variable)
           ([remap describe-symbol]    . helpful-symbol)
           ([remap describe-key]       . helpful-key)
           ([remap describe-command]   . helpful-command)
           ("C-h C-l" . find-library)      ;; source code file
           ("C-h C-c" . finder-commentary) ;; Display file commentary section
           ("C-h K"   . describe-keymap)
           ("C-h y"   . describe-personal-keybindings)
           ("C-h <help>" . nil)
           ("C-h <f1>" . nil)
           ("C-h C-h"  . nil)
           ("C-h C-f" . nil)
           ("C-h C-n" . nil)
           ("C-h C-W" . nil)
           ("C-h C-\\" . nil)
           ("C-h g"   . nil)
           ("C-h C-o" . nil)
           ("C-h C-p" . nil)
           ("C-h C-t" . nil)
           ("C-h h" . nil)
           ("C-h n" . nil)
           )
    )
#+end_src

** Help on available keys
#+begin_src emacs-lisp
    (use-package which-key
      :ensure t
      :diminish
      :custom
      (which-key-idle-delay 0.5)
      (which-key-enable-extended-define-key t)
      (which-key-sort-order 'which-key-description-order)
      (which-key-show-prefix nil)
      :config
      (which-key-mode t)
      ;;(which-key-setup-side-window-bottom)
      (which-key-setup-side-window-right)
      (setq which-key-side-window-max-width 0.8)
      ;; (setq which-key-popup-type 'minibuffer)
  )
#+end_src

** Minibuffer annotations
Rich annotations using the Marginalia package:

#+begin_src emacs-lisp
  (use-package marginalia
	 :ensure t
    ;; Bind `marginalia-cycle' locally in the minibuffer.  To make the binding
    ;; available in the *Completions* buffer, add it to the `completion-list-mode-map'.
    :bind (:map minibuffer-local-map
	   ("M-A" . marginalia-cycle))
    :init
    (marginalia-mode))
#+end_src


* User Interface - Key Bindings
** Hydras
#+begin_src emacs-lisp
  (message "at hydra")

  (use-package hydra
;;    :hook (emacs-lisp-mode . hydra-add-imenu)
  )
(use-package pretty-hydra
)
#+end_src

#+begin_src emacs-lisp
  (use-package major-mode-hydra
    :ensure t
    :bind
    ("C-S-SPC" . major-mode-hydra)
  )
#+end_src


* Windows
#+begin_src emacs-lisp
    (use-package ace-window
      :config
      (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
      :bind (
      ("M-o" . ace-window)
       )
      )
#+end_src


* Visuals

Every Emacs window should, by default occupy all the screen space it can.

#+begin_src emacs-lisp
  (add-to-list 'default-frame-alist '(fullscreen . maximized))
#+end_src

Window chrome both wastes space and looks unappealing.

#+begin_src emacs-lisp
  (when (window-system)
    (menu-bar-mode t)
    (tool-bar-mode -1)
    (scroll-bar-mode t)
    (tooltip-mode -1)
    (pixel-scroll-mode t))
#+end_src

** Titlebar
#+begin_src emacs-lisp
    (setq frame-title-format '("" "%b - " this-emacs "@" system-name))
#+end_src

** Modeline
Most major modes pollute the modeline, so we pull in diminish.el to quiesce them.

#+begin_src emacs-lisp
  (use-package diminish
    :config
    (diminish 'visual-line-mode))
#+end_src

** Display colors

#+begin_src emacs-lisp
  (use-package rainbow-mode
    :ensure t
    :config
    (add-hook 'text-mode-hook #'rainbow-mode)
    (add-hook 'prog-mode-hook #'rainbow-mode)
    (diminish 'rainbow-mode ""))
#+end_src

** Theme
modus-(vivendi|operandi)

#+begin_src emacs-lisp
  (use-package emacs
    :init
    ;; customization prior to loading the themes
    (setq modus-themes-italic-constructs t
          modus-themes-bold-constructs t
          modus-themes-region '(bg-only no-extend))
    :config
    (load-theme 'modus-operandi) 
    )
#+end_src

** Icons for Listings and Menues
use glyphs for symbol types (instead of images when using kind-icons))
#+begin_src emacs-lisp
  (use-package nerd-icons
    :diminish nerd-icons-dired-mode "" nerd-icons-ibuffer-mode ""
  )
#+end_src

* Editing
Quickly activate viper: <f8>

#+begin_src emacs-lisp
  (message "at viper")
  (use-package emacs
  :config
  (setq viper-custom-file-name "~/.viper")
  (setq viper-mode nil)
)
#+end_src

* Search
#+begin_src emacs-lisp
  (message "at isearch")

  (use-package emacs
  :config
  (setq isearch-lazy-count t)
  (setq lazy-count-prefix-format nil)
  (setq lazy-count-suffix-format "   (%s/%s)")

  (defun my-occur-from-isearch ()
    (interactive)
    (let ((query (if isearch-regexp
               isearch-string
             (regexp-quote isearch-string))))
      (isearch-update-ring isearch-string isearch-regexp)
      (let (search-nonincremental-instead)
        (ignore-errors (isearch-done t t)))
      (occur query)))

   (defun my-project-search-from-isearch ()
    (interactive)
    (let ((query (if isearch-regexp
               isearch-string
             (regexp-quote isearch-string))))
      (isearch-update-ring isearch-string isearch-regexp)
      (let (search-nonincremental-instead)
        (ignore-errors (isearch-done t t)))
      (project-find-regexp query)))
  :bind
  (:map isearch-mode-map
        ("C-f" . my-project-search-from-isearch)
          ("M-o" . my-occur-from-isearch))
  )
#+end_src

* Dired

#+begin_src emacs-lisp
  (require 'dired)
    (require 'dired-x)
    (require 'wdired)
#+end_src

** Packaged Extensions
Depends on nerd-the-icons -install font

#+begin_src emacs-lisp
  (use-package nerd-icons-dired
    :diminish dired-mode
    :after dired
    :hook (dired-mode . nerd-icons-dired-mode)
    )
#+end_src

#+begin_src emacs-lisp
  (use-package dired-filter
    :after dired
    )
#+end_src

#+begin_src emacs-lisp
  (use-package dired-open
       :after dired
    )
#+end_src

#+begin_src emacs-lisp
  (use-package diredfl
       :after dired
       :hook (dired-mode . diredfl-mode)
    )
#+end_src

A key is bound to "S". On windows, we need the path for "ls".
Otherwise, a lisp library is used for the listing, that does not
provide the means for sorting with this package.

#+begin_src emacs-lisp
  (use-package dired-quick-sort
    :ensure t
    :config
    (setq dired-quick-sort-suppress-setup-warning nil)
    (if sys/win32p
       (setq ls-lisp-use-insert-directory-program "/usr/bin/ls"))
    (dired-quick-sort-setup)
    :after dired
    )
#+end_src

** Dired and fast-find
Create dired-buffers from find commands.

#+begin_src emacs-lisp
  (use-package fd-dired
    :ensure t
    :after dired
  )
#+end_src


** Configuration

#+begin_src emacs-lisp
    (use-package emacs
      :init
      (setq
       dired-dwim-target t  ;; copy and move files
       dired-create-destination-dirs 'ask
       dired-kill-when-opening-new-dired-buffer t
       dired-auto-revert-buffer t
       dired-recursive-deletes 'always
       dired-recursive-copies 'always
       dired-mark-region t
       dired-listing-switches "-aBhl  --group-directories-first"
       )
      (put 'dired-find-alternate-file 'disabled nil)
      :bind (
           :map dired-mode-map (
                 ("#"          . wdired-change-to-wdired-mode)
                 ("C-<return>" . dired-open-xdg)
                 ;; emacs default: ("s"          . dired-sort-toggle-or-edit)
                 ("S-s"        . hydra-dired-quick-sort/body)
                 ("-"          . dired-hide-details-mode)
                 )
      )
      :hook (dired-mode . dired-hide-details-mode)
            (dired-mode . dired-filter-mode)
            )
#+end_src


* Buffer List (ibuffer)
** Group by version control
#+begin_src emacs-lisp
  (require 'ibuffer)
  (use-package ibuffer-vc
    :config
    (setq ibuffer-expert t)
    (setq ibuffer-auto-mode t)
    (setq ibuffer-display-summary nil)
    (setq ibuffer-use-header-line t)
    (setq ibuffer-show-empty-filter-groups nil)
    (setq ibuffer-default-sorting-mode 'filename/process)

    (setq ibuffer-saved-filter-groups
          '(("VED"
             ("Unsaved"  (modified))                      ; All unsaved buffers
             ("Dired"    (mode          . dired-mode))    ; Filter by mode
             ("Org"      (filename      . ".org"))        ; By filename
             ("notes"    (directory     . "~/notes*"))       ; By directory
             ("*buffer*" (starred-name))                  ; Group *starred*
             )))
    :hook (ibuffer-mode . ibuffer-vc-set-filter-groups-by-vc-root)
    :bind (([remap list-buffers]. ibuffer)
         :map ibuffer-mode-map (("\M-o" . nil)
                                ("C-v" . ibuffer-vc-set-filter-groups-by-vc-root)
                                ("C-r" . (lambda ()(interactive) (ibuffer-switch-to-saved-filter-groups "VED")))
                                )
         )
    )
#+end_src

** Icons
#+begin_src emacs-lisp
  (use-package nerd-icons-ibuffer
  :ensure t
  :config
    (setq nerd-icons-ibuffer-color-icon t)   ;; default
    (setq nerd-icons-ibuffer-icon-size 1.0)  ;; default
  :hook (ibuffer-mode . nerd-icons-ibuffer-mode))
#+end_src

* Recent Files
By default, the list of recent files gets cluttered up with the contents of downloaded packages.

#+begin_src emacs-lisp
    (use-package recentf
      :after dash
      :custom
      (recentf-exclude '("\\elpa"
                        )
           )
      (recentf-max-saved-items 100)
      (recentf-max-menu-items 50)
      :config (recentf-mode))
#+end_src


* Bookmarks

Leave M-o for ace-window

#+begin_src emacs-lisp
  (require 'bookmark+)
  (define-key bookmark-bmenu-mode-map "\M-o" nil)
#+end_src


* ediff
Setup recommended by Prot. Stavrou.

#+begin_src emacs-lisp
  (require 'ediff)
  (setq ediff-make-buffers-readonly-at-startup nil)
  (setq ediff-split-window-function 'split-window-horizontally)
  (setq ediff-window-setup-function 'ediff-setup-windows-plain)
#+end_src


* Quality-of-life improvements

** Augment use-package
With this auxiliary package for ~use-package~, we can instruct Emacs that a given package depends on the presence of a
system tool. It will even install this tool with the system's recommended package manager.

#+begin_src emacs-lisp
  (use-package use-package-ensure-system-package)
#+end_src

** Locations in Files

Remembers your location in a file when saving files

#+begin_src emacs-lisp
  (use-package saveplace
    :config
    (setq save-place-file (expand-file-name "saveplace" emacsen-dir))
    ;; activate it for all buffers
    (setq-default save-place t)
    )
#+end_src

** History of Commands
Persist history of commands over Emacs restarts. Vertico sorts by history position.

#+begin_src emacs-lisp
  (use-package savehist
      :config
      (setq savehist-additional-variables
	    ;; search entries
	    '(search-ring regexp-search-ring)
	    ;; save every minute
	    savehist-autosave-interval 60
	    ;; keep the home clean
	    savehist-file (expand-file-name "savehist" emacsen-dir))
      (savehist-mode +1))
#+end_src

** Augment Undo
From Prelude config:

#+begin_src emacs-lisp
(message "vundo")
  (use-package vundo
  :ensure t
  :commands (vundo)

  :config
  (setq vundo-compact-display t)
    (setq vundo-glyph-alist vundo-unicode-symbols)

  ;; Better contrasting highlight.
  (custom-set-faces
    '(vundo-node ((t (:foreground "#808080"))))
    '(vundo-stem ((t (:foreground "#808080"))))
    '(vundo-highlight ((t (:foreground "#FFFF00")))))

  ;; Use `HJKL` VIM-like motion, also Home/End to jump around.
  (define-key vundo-mode-map (kbd "l") #'vundo-forward)
  (define-key vundo-mode-map (kbd "h") #'vundo-backward)
  (define-key vundo-mode-map (kbd "j") #'vundo-next)
  (define-key vundo-mode-map (kbd "k") #'vundo-previous)
  (define-key vundo-mode-map (kbd "<home>") #'vundo-stem-root)
  (define-key vundo-mode-map (kbd "<end>")  #'vundo-stem-end)
  (define-key vundo-mode-map (kbd "q")   #'vundo-quit)
  (define-key vundo-mode-map (kbd "C-g") #'vundo-quit)
  (define-key vundo-mode-map (kbd "RET") #'vundo-confirm)
  )
#+end_src

** Writable grep
#+begin_src emacs-lisp
  (use-package wgrep
    :ensure t
    :config
    (setq wgrep-change-readonly-file t)
    (setq wgrep-auto-save-buffer t)
    :bind ( :map grep-mode-map
            ("e" . wgrep-change-to-wgrep-mode)
            :map wgrep-mode-map
            ("e" . wgrep-exit)
            ("c" . wgrep-finish-edit)
            ("d" . wgrep-mark-deletion)
            ("r" . wgrep-remove-change)
            ("R" . wgrep-remove-all-change)
            )
    )
#+end_src


## Usage:

You can edit the text in the *grep* buffer after typing `C-c C-p` .
After that the changed text is highlighted.
The following keybindings are defined:

*** Key Bindings
- `C-c C-u`: All changes are unmarked and ignored.
- `C-c C-d`: Mark as delete to current line (including newline).
- `C-c C-r`: Remove the changes in the region (these changes are not
  applied to the files. Of course, the remaining
  changes can still be applied to the files.)
- `C-c C-p`: Toggle read-only area.
- `C-c C-k`: Discard all changes and exit.
- `C-x C-q`: Exit wgrep mode.

*** Functions
- To save all buffers that wgrep has changed, run

    M-x wgrep-save-all-buffers

- To save buffer automatically when `wgrep-finish-edit'.

    (setq wgrep-auto-save-buffer t)

- You can change the default key binding to switch to wgrep.

    (setq wgrep-enable-key "r")

- To apply all changes regardless of whether or not buffer is read-only.

    (setq wgrep-change-readonly-file t)


** ripgrep

#+begin_src emacs-lisp
    (use-package rg
      :ensure-system-package rg
      :config
      (setq rg-command-line-flags (list "-C=2"))
      (setq rg-hide-command nil)
      )

(require 'rg-isearch)
    (define-key isearch-mode-map "\M-sr" 'rg-isearch-menu)


    (rg-define-search rg-word
      :format literal
      :flags ("--word-regexp")
      :menu ("Custom" "w" "Word")
      )
#+end_src



* Desktop management
#+begin_src emacs-lisp
  (require 'desktop)
#+end_src

* Tab-Bar
#+begin_src emacs-lisp
  (use-package tab-bar
    :config
    (setq tab-bar-show t
          tab-bar-close-button-show nil
          tab-bar-tab-hints t
          )
    (keymap-unset tab-bar-mode-map "C-<tab>" 'remove)
  )
#+end_src


* Search

** Buffers
Occur, ripgrep

** TODO Files
fd



* Completion and input

** Narrow the candidate list
Orderless is a valuable addition to completion-styles.
After narrowing the candidate list by builtin completion styles, it provides a
very flexible interface for quickly finding the best candidate.

Best reference:
Search with *rg "\(styles" emacsen/steal-from/

- Prots Emacs: prot/prot-emacs-modules/prot-emacs-completion.el
- Lunarymacs: lunarymacs/star/completion.el
- josh_moller-mara/jmm-emacs.org

#+begin_src emacs-lisp
  ;; from Prots config
  (use-package orderless
    :ensure t
    :demand t
    :after minibuffer
    :config
    ;; check 'completion-styles' and 'completion-category-overrides'.
    (setq orderless-matching-styles '(orderless-prefixes orderless-regexp))

    ;; SPC should never complete: use it for 'orderless' groups.
    ;; '?' is a regexp construct.
    :bind ( :map minibuffer-local-completion-map
	    ("SPC" . nil)
	    ("?" . nil)))
#+end_src

** Minibuffer

#+begin_src emacs-lisp
  (use-package emacs
    :custom
    ;; (completion-styles '(basic substring partial-completion initials flex orderless))
    (completion-styles '(basic partial-completion orderless))
    (completion-category-defaults nil)
    (completion-category-overrides '(
				   (file (styles . (basic initials orderless)))
				   (buffer (styles . (orderless)))
				   ;; (bookmark (styles . (orderless)))
				   ;; (eglot (styles . (substring orderless)))
				   ;;(library (styles . (basic substring)))
				   ;; (embark-keybinding (styles . (basic substring)))
				  ;; (imenu (styles . (basic substring orderless)))
				   ;; (consult-location (styles . (basic substring orderless)))
				   ;; (kill-ring (styles . (emacs22 orderless)))
				   ;; (eglot (styles . (flex basic)))
				   ;; (xref-location (styles . (orderless substring)))
				   ;;(unicode-name (styles . (orderless basic substring)))
				  ;; (project-file (styles . (orderless substring)))
				  ;; (info-menu (styles . (orderless basic substring)))
				  ;; (symbol-help (styles . (orderless basic shorthand substring)))
				   ))
    (completion-auto-select nil)
    (read-file-name-completion-ignore-case t)
    (read-buffer-completion-ignore-case t)
    (completion-ignore-case t)
    )
#+end_src

*** completion-styles

*** completion-category-overrides
**** file
From the *orderless* documentation (https://github.com/oantolin/orderless ):

Furthermore the ~basic~ completion style needs to be tried first (not as a fallback) for TRAMP hostname completion to work.
In addition, the partial-completion style allows you to use wildcards for file completion and partial paths, e.g., /u/s/l for /usr/share/local.

*** completion categories
A non-exhaustive list:
- bookmark
- buffer
- charset
- coding-system
- color
- command (M-x)
- customize-group
- environment-variable
- expression
- face
- file
- function (the 'describe-function' command bound to 'C-h f')
- info-menu
- imenu
- input-method
- kill-ring
- library
- minor-mode
- multi-category
- package
- project-file
- symbol (the 'describe-symbol' command bound to 'C-h o')
- theme
- unicode-name (the 'insert-char' command bound to 'C-x 8 RET')
- variable (the 'describe-variable' command bound to 'C-h v')
- consult-grep
- consult-isearch
- consult-kmacro
- consult-location
- embark-keybinding


*** Modern minibuffer completion: vertico

minibuffer-complete-word
        
#+begin_src emacs-lisp
(use-package vertico
    :init
    (vertico-mode 1)
    (vertico-multiform-mode 1)
    (vertico-reverse-mode 1)

    (defun my/vertico-smart-tab ()
      (interactive)
      (if (= vertico--total 1)
          (vertico-insert)
        (minibuffer-complete))
      )

    (setq vertico-multiform-categories
          '(
            (consult-buffer unobtrusive)
            ))
    (setq vertico-multiform-commands
          '(("flyspell-correct-*" grid)
            (consult-yank-pop     indexed)
            (consult-ripgrep      buffer)
            (consult-fd           buffer)
            (consult-imenu        buffer)
            (consult-flycheck     buffer)
            (consult-flymake      buffer)
            ))


    :custom
    (vertico-count (if window-system 16 10))
    (vertico-buffer-display-action '(display-buffer-same-window))

    ;; enable cycling for 'vertico-next' and 'vertico-previous'.
    (vertico-cycle t)
    :bind (:map vertico-map
               ("<deletechar>"      . vertico-directory-delete-char)
               ("C-<tab>"      . my/vertico-smart-tab)
               ;;                ("<tab>"      . vertico-insert)
               ("M-<return>" . vertico-exit-input)
               ("M-q"        . vertico-quick-jump)
               ("C-M-r"      . consult-history)
              )
    )
#+end_src

Changed <tab> and C-<tab> to match built-in behaviour.


** Buffer completion

#+begin_src emacs-lisp
  (use-package emacs
    :init
    ;; Emacs 28: Hide commands in M-x which do not apply to the current mode.
    ;; Corfu commands are hidden, since they are not supposed to be used via M-x.
    (setq read-extended-command-predicate #'command-completion-default-include-p)

    :config
    (setq-default
     tab-always-indent 'complete
     tab-first-completion 'word-or-paren-or-punct)
    )
#+end_src

*** Abbreviations
Abbreviations are used for solely for auto-correction and text expansion.
For Source Code template engines are preferred. 

#+begin_src emacs-lisp
(defun dont-insert-expansion-char ()  t) 
(put 'dont-insert-expansion-char 'no-self-insert t)

  (use-package emacs
     :config
       (setq abbrev-file-name (concat emacsen-dir "abbreviations/abbrev_defs.el"))
       (setq only-global-abbrevs nil)
       (setq save-abbrevs nil)
  )
#+end_src


*** Corfu!
Modern completion

#+begin_src emacs-lisp
  (use-package corfu
    ;; :disabled
    :bind (:map corfu-map
                ("C-g"      . corfu-quit)
                ("<return>" . corfu-insert)
                ("M-n"      . corfu-next)
                ("M-p"      . corfu-previous)
                ("M-m"      . corfu-move-to-minibuffer)
                ("M-d"      . corfu-show-documentation)
                ("M-l"      . corfu-show-location)
                )

    :custom
    (corfu-cycle t)                ;; Enable cycling for 'corfu-next/previous'
    (corfu-auto nil)                 ;; Enable auto completion
    (corfu-preselect-first nil)
    (corfu-echo-documentation t)
    (corfu-separator ?\s)               ;; Orderless field separator
    (corfu-quit-at-boundary 'separator) ;; Never quit at completion boundary
    (corfu-preview-current nil)         ;; Disable current candidate preview
    (corfu-on-exact-match 'insert)      ;; Configure handling of exact matches

    (corfu-excluded-modes nil)          ;; add modes where corfu is disabled
    (corfu-popupinfo-mode nil)
    :init
   ;; (global-corfu-mode)
  )
#+end_src

#+begin_src emacs-lisp
  (use-package nerd-icons-corfu
       :config
    (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)
  )
#+end_src

*** cape
Completion sources:

#+begin_src emacs-lisp
  (use-package cape
    :config
    (add-to-list 'completion-at-point-functions #'cape-keyword)
    (add-to-list 'completion-at-point-functions #'cape-dabbrev)
    :custom
    (cape-dabbrev-check-other-buffers nil)
    )
#+end_src


;; Alternative prefix keys: C-c p, M-p, M-+, ...
         ("C-c p t" . complete-tag)        ;; etags
         ("C-c p d" . cape-dabbrev)        ;; dabbrev-completion
         ("C-c p h" . cape-history)        ;; shell
         ("C-c p f" . cape-file)
         ("C-c p k" . cape-keyword)        ;; mode-specific keyword lists - is that useful?
         ("C-c p s" . cape-elisp-symbol)
         ("C-c p e" . cape-elisp-block)
         ("C-c p a" . cape-abbrev)         ;; do not use
         ("C-c p l" . cape-line)
         ("C-c p w" . cape-dict)          ;; text-mode
         ("C-c p :" . cape-emoji)
         ("C-c p ^" . cape-tex)           ;; julia
         ("C-c p &" . cape-sgml)          ;; html, julia
         ("C-c p r" . cape-rfc1345))

*** Dynamic Abbreviatons
#+begin_src emacs-lisp
  (use-package emacs
    :config
    (setq dabbrev-abbrev-char-regexp "\\sw\\|\\s_")
    (setq dabbrev-abbrev-skip-leading-regexp "[$*/=~']")
    (setq dabbrev-backward-only nil)
    (setq dabbrev-case-distinction 'case-replace)
    (setq dabbrev-case-fold-search nil)
    (setq dabbrev-case-replace 'case-replace)
    (setq dabbrev-check-other-buffers nil)
    (setq dabbrev-eliminate-newlines t)
    (setq dabbrev-upcase-means-case-search t)
    )
#+end_src


** Templates
prefer tempo/tempel to yasnippets!

*** tempel/tempo
see https://github.com/minad/tempel

- no abbrev-mode triggering
- used as a capf for completion-at-point (in buffer-completion)

#+begin_src emacs-lisp
  (use-package tempel
   ;; Require trigger prefix before template name when completing.
   :custom
   (tempel-trigger-prefix "<")

   :config
    (setq tempel-path (concat emacsen-dir "templates/tempel/ve-templates"))
;;    (add-to-list 'tempel-template-sources 'my-global-templates)
    )
  :init
  ;; Setup completion at point
  (defun tempel-setup-capf ()
    ;; Add the Tempel Capf to 'completion-at-point-functions'.
    ;; 'tempel-expand' only triggers on exact matches. Alternatively use
    ;; 'tempel-complete' if you want to see all matches, but then you
    ;; should also configure 'tempel-trigger-prefix', such that Tempel
    ;; does not trigger too often when you don't expect it. NOTE: We add
    ;; 'tempel-expand' *before* the main programming mode Capf, such
    ;; that it will be tried first.
    (setq-local completion-at-point-functions
                (cons #'tempel-complete
                      completion-at-point-functions)))
#+end_src


A community curated list of templates.
#+begin_src emacs-lisp
  (use-package tempel-collection
    :after tempel
  )
#+end_src

*** Yasnippets
important commands:
- yas-*expand
- yas-insert-snippet 
  
There is no trigger key (like TempEL has).
That functionality is activated via yas-minor mode 

#+begin_src emacs-lisp
  (use-package yasnippet
    :defer 15 ;; takes a while to load, so do it async
    :diminish yas-minor-mode "yas"
    :config
   (setq yas-alias-to-yas/prefix-p nil)
   (setq yas-snippet-dirs (list (concat emacsen-dir "/templates/yas"))
          )
    :custom (yas-prompt-functions '(yas-completing-prompt))
    :bind (
         :map yas-minor-mode-map  (
           ("M-+"   . yas-insert-snippet)
           ("<tab>" . nil)
          )
    )
  )
#+end_src

nur so funktioniert es:
(setq yas-snippet-dirs '("~/emacs.d/mysnippets"
                           "~/Downloads/interesting-snippets"))

;; OR, keeping YASnippet defaults try out ~/Downloads/interesting-snippets
(setq yas-snippet-dirs (append yas-snippet-dirs
                               '("~/Downloads/interesting-snippets")))

funktioniert nicht!
(add-to-list 'yas-snippet-dirs (concat emacsen-dir "templates/yas"))

*** Snippet Collection

#+begin_src emacs-lisp
  (use-package yasnippet-snippets)
#+end_src

*** Completion At Point

#+begin_src emacs-lisp
  (use-package yasnippet-capf
    :disabled
    :after cape

    :init ;; Setup completion at point
    (defun yas-setup-capf ()
      (setq-local completion-at-point-functions
                  (cons #'yasnippet-capf
                        completion-at-point-functions)))

    (add-hook 'conf-mode-hook 'yas-setup-capf)
    (add-hook 'prog-mode-hook 'yas-setup-capf)
    (add-hook 'text-mode-hook 'yas-setup-capf)
  )

#+end_src



*** File Headers
#+begin_src emacs-lisp
      (require 'autoinsert)
      (setq auto-insert-mode t)
      (setq auto-insert-query t)

      (setq auto-insert-directory (concat emacsen-dir "templates/header"))
      (setq auto-insert-alist '(
                                (julia-mode     . julia-skeleton)
                                (vegalite-mode  . vegalite-skeleton)
                                (java-mode      . "java.template")
                                (clojure-mode   . "clojure.template")
                                (gnuplot-mode   . "gnuplot.template")
                                (asy-mode       . "asymptote.template")
                                (org-mode       . "org.template")
                                (python-mode    . "python.template")
                                ))

      (add-hook 'find-file-hook 'auto-insert)


      (define-skeleton julia-skeleton
        "Inserts a skeletal Julia file"
        nil
        "# author: " (user-full-name) \n
        "# created: " (current-time-string) \n
        "# project: "
        (setq project (skeleton-read "Project (Return to discard)? "))
        (if project
            project
            )
        \n \n)

        (define-skeleton vegalite-skeleton
        "Inserts a skeletal"
        nil
        "{
           \"$schema\": \"https://vega.github.io/schema/vega-lite/v5.json\",
           \"description\": \"\",
           \"data\": {
            },
           \"mark\": {
               \"type\": \"\"
            },
           \"encoding\": {
            }
         }"
        \n)
#+end_src


* TODO Consult:  Search and Navigation for completion
Consult provides search and navigation commands based on the Emacs completion function completing-read.

#+begin_src emacs-lisp
  (use-package consult
      :custom
      (consult-narrow-key (kbd ";"))
      (completion-in-region-function #'consult-completion-in-region)
      (xref-show-xrefs-function #'consult-xref)
      (xref-show-definitions-function #'consult-xref)
      (consult-preview-key '(:debounce 0.25 any))
      )

  (use-package consult-dir
    :ensure t
    :bind (
           ("C-x C-d" . consult-dir)
           ("C-x b"   . consult-buffer)
           :map vertico-map
           ("C-x C-d" . consult-dir)
           ("C-x C-j" . consult-dir-jump-file))
    )
#+end_src


* TODO Embark: Discover actions

see https://karthinks.com/software/fifteen-ways-to-use-embark/

#+begin_src emacs-lisp
    (use-package embark
    :bind
    (
;;     ("."     . embark-dwim)
     ("C-."   . embark-act)
     ("C-S-." . embark-act-all)
     ("C-e"   . embark-export)
     ;;     ("C->"     . embark-become)
     ("C-?"     . embark-bindings) ;; alternative for 'describe-bindings'
     ) 

    :init
    ;; replace the key help with a completing-read interface
    (setq prefix-help-command #'embark-prefix-help-command)

    :config
    ;; Hide the mode line of the Embark live/completions buffers
    (add-to-list 'display-buffer-alist
                 '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                   nil
                   (window-parameters (mode-line-format . none))))
  )
#+end_src

Glue for consult and embark.

#+begin_src emacs-lisp
    (require 'consult-flycheck)
      (require 'consult-flymake)

  (use-package embark-consult
    :ensure t
    :after (embark consult)
    :config


    (add-to-list
     'embark-exporters-alist
     '(consult-flymake-error . embark-export-flymake)
     '(consult-flycheck-error . embark-export-flycheck)
     )

    (defun embark-export-flymake (_errors)
      (flymake-show-buffer-diagnostics))
    ;; TODO: flycheck  
    :bind (:map embark-file-map
                ("x" . embark-open-externally))
  :demand t ; necessary for consult previews (hook!)
  :hook
  (embark-collect-mode . consult-preview-at-point-mode)
  )
#+end_src

lots of actions:

** File: karthink/lisp/setup-embark.el
(define-key embark-file-map (kbd "o") (my/embark-ace-action find-file))


  ;;  (use-package embark-vc
  ;;               :after embark)


* Quick Movement: avy can do anything

#+begin_src emacs-lisp
  (use-package avy
    :config
    (defun my/avy-goto-char-this-window (&optional arg)
      "Goto char in this window with hints."
      (interactive "P")
      (let ((avy-all-windows nil)
            (current-prefix-arg (if arg 4)))
        (call-interactively 'avy-goto-char-timer)))
  
    (setq avy-timeout-seconds 0.75)
    (setq avy-single-candidate-jump nil)
    (setq avy-background t)
    (defun avy-action-embark (pt)
      (unwind-protect
          (save-excursion
            (goto-char pt)
            (embark-act))
        (select-window
         (cdr (ring-ref avy-ring 0))))
      t)

    (setf (alist-get ?. avy-dispatch-alist) 'avy-action-embark)
    :bind (("C-M-j"   . avy-resume)
           ("C-j"     . my/avy-goto-char-this-window)
           ("M-j"     . avy-goto-char-timer)
           :map isearch-mode-map ("M-j" . avy-isearch)
           )
    )
#+end_src

** File: karthink/lisp/setup-avy.el

* casual transient
Alle casuals, die ich *definitiv* nicht benutze, wurden geloescht.
Mit den Keyboard Shortcuts C-o kann ich mich nicht anfreunden.

#+begin_src emacs-lisp
;;  (require 'casual-suite)

;;  (casual-ediff-install) ; run this to enable Casual Ediff
;;  (add-hook 'ediff-keymap-setup-hook
;;            (lambda ()
;;              (keymap-set ediff-mode-map "C-o" #'casual-ediff-tmenu)))

;;  (keymap-set calc-mode-map "C-c c" #'casual-calc-tmenu)
;;  (keymap-set isearch-mode-map "C-c c" #'casual-isearch-tmenu)
#+end_src

in keybindings.org
- rectangle
- windows
- registers
- bookmarks

zu ueberladen, daher verworfen:
- ibuffer
- edit kit
- agenda
- info

  offen:
  (keymap-set reb-mode-map "C-o" #'casual-re-builder-tmenu)
  (keymap-set reb-lisp-mode-map "C-o" #'casual-re-builder-tmenu)
  (keymap-set symbol-overlay-map "C-o" #'casual-symbol-overlay-tmenu)


* TODO Regular Expressions

* Terminal
** ELisp Terminal emulation
Currently(2023-06-30) not running on Windows.

(use-package bytecomp
    :config
    (setq byte-compile-log-buffer " *Compile-Log*"))

(use-package comp
    :config
    (setq comp-log-buffer-name " *Native-compile-Log*")
    (setq comp-async-buffer-name " *Async-native-compile-log*"))

#+begin_src emacs-lisp
  (defmacro apply-split-nest (callable arguments count body)
    (setq arguments (copy-sequence arguments))
    (setq count (1- count))
    (let* ((forms (list 'unused))
           (last-cons forms))
        (while arguments
            (setcdr last-cons (list (cons callable arguments)))
            (setq last-cons (nthcdr count arguments))
            (setq arguments (cdr last-cons)))
        (setcdr last-cons body)
        (cadr forms)))
  
  (defun advice-remove-all (symbol)
      (dolist (advice (advice-list symbol))
          (seq-let (_how function) advice
              (advice-remove symbol function))))

  (defmacro with-advice-1 (advice-add-arguments &rest body)
      (let ((state (make-symbol "--with-advice--")))
          `(let ((,state (list ,@advice-add-arguments)))
               (unwind-protect
                   (progn
                       (condition-case error
                           (apply 'advice-add ,state)
                           (wrong-number-of-arguments
                               (setq ,state nil)
                               (signal (car error) (cdr error))))
                       ,@body)
                   (when ,state
                       (setcdr ,state (cddr ,state))
                       (setcdr (cdr ,state) nil)
                       (apply 'advice-remove ,state))))))

  (defmacro with-advice (advice-list &rest body)
      (declare (indent 1))
      `(apply-split-nest with-advice-1 ,advice-list 1 ,body))

    (defun best-compile (function)
        (if (native-comp-available-p)
            (native-compile function)
            (byte-compile function)))

    (defun function-lisp (function)
        (let ((raw (indirect-function function)))
            (while (advice--p raw)
                (setq raw (advice--cdr raw)))
            (if (or (subr-native-elisp-p raw)
                    (byte-code-function-p raw)
                    (autoloadp raw))
                (if-let* ((source (find-function-library function))
                          (file (cdr source)))
                    (function-lisp--read-from-source (car source) file)
                    nil)
                (if (subrp raw)
                    nil
                    (if (interpreted-function-p raw)
                        (interpreted-function-lisp raw)
                        raw)))))

    (defun function-lisp--read-from-source (name file)
        (let* ((buffers (buffer-list))
               (found (find-function-search-for-symbol name nil file))
               (buffer   (car found))
               (position (cdr found))
               (was-already-open (memq buffer buffers)))
            (prog1
                (read (set-marker (make-marker) position buffer))
                (unless was-already-open
                    (kill-buffer buffer)))))

    (defun function-lisp-anonymize (definition)
        (cond
            ((memq (car definition) '(defun defsubst))
                (cons 'lambda (cddr definition)))
            ((eq (car definition) 'defmacro)
                (cons 'macro (cons 'lambda (cddr definition))))
            (t
                definition)))

      
        (defun form-replace (from-forms to-forms in-forms)
          (when in-forms
              (let ((unmatched-in-forms in-forms)
                    (unmatched-from-forms from-forms))
                  (while (and unmatched-in-forms
                              unmatched-from-forms
                              (equal (car unmatched-in-forms)
                                     (car unmatched-from-forms)))
                      (pop unmatched-in-forms)
                      (pop unmatched-from-forms))
                  (if unmatched-from-forms
                      (nconc
                          (form-replace--car from-forms to-forms (car in-forms))
                          (form-replace      from-forms to-forms (cdr in-forms)))
                      (nconc
                          (copy-sequence to-forms)
                          (form-replace from-forms to-forms unmatched-in-forms))))))

      (defun form-replace--car (from-forms to-forms nested-form)
          (if (consp nested-form)
              (list (form-replace from-forms to-forms nested-form))
              (if (and (equal nested-form (car from-forms))
                       (not (cdr from-forms)))
                  (copy-sequence to-forms)
                  (list nested-form))))
#+end_src

#+begin_src emacs-lisp
      (defvar-local pop-to-command-buffer nil)
      (defvar pop-to-command-setup-hook nil)
      (defvar-local pop-to-command--callback nil)
      (defun pop-to-command-buffer-name (command &optional context name)
          (setq-if-nil name (string-join command " "))
          (if context
              (concat "*" name " (" context ")*")
              (concat "*" name "*")))
      (defun pop-to-command (command &optional context name callback)
          (require 'eshell)
        (setq name (pop-to-command-buffer-name command context name))
        (let ((program   (car command))
              (arguments (cdr command))
              (directory default-directory)
              (buffer    (get-buffer name)))
            (if buffer
                (with-current-buffer buffer
                    (when eshell-process-list
                        (eshell-kill-process)
                        (sleep-for 0.04)))
                (setq buffer (get-buffer-create name))
                (set-buffer buffer)
                (setq histdir nil)
                (let ((eshell-non-interactive-p t)
                      (eshell-history-file-name nil))
                    (eshell-mode)))
            (pop-to-buffer buffer)
            (use-local-map (make-sparse-keymap))
            (set-keymap-parent (current-local-map) eshell-mode-map)
            (local-set-key "\C-m" 'ignore)
            (setq-local pop-to-command-buffer t)
            (setq-local pop-to-command--callback callback)
            (setq default-directory directory)
            (end-of-buffer)
            (add-hook 'eshell-post-command-hook 'pop-to-command--done-eshell nil t)
            (run-hooks 'pop-to-command-setup-hook)
            (let ((parsed-command (eshell-parse-command program arguments t)))
                (eshell-eval-command parsed-command))
            buffer))

    (defun pop-to-command--done-eshell ()
        (insert "\nCommand " (buffer-name) " done.\n")
        (end-of-buffer)
        (when pop-to-command--callback
            (funcall pop-to-command--callback)))

    (provide 'pop-to-command) 
#+end_src

#+begin_src emacs-lisp
        (use-package eat
            :if sys/linuxp
        	:custom
        	(eat-kill-buffer-on-exit t)
        	:config
        	(eat-eshell-mode)
        	(setq eshell-visual-commands '())
            (defun hack-make-process (arguments)
              (let* ((cell (cdr (plist-member arguments :command)))
                     (command (car cell)))
                  (when (and (equal (car command) "/usr/bin/env")
                             (equal (cadr command) "jimsh"))
                      (setcar cell (cdr command))))
              arguments)
          (defun fixed-eat--make-process (function &rest arguments)
              (with-advice (('make-process :filter-args 'hack-make-process))
                  (let ((process-environment process-environment))
                      (when (equal (eat-term-name) "eat-truecolor")
                          (push "COLORTERM=truecolor" process-environment))
                      (apply function arguments))))
          (advice-add 'eat--eshell-adjust-make-process-args
              :around 'fixed-eat--make-process)
          (advice-add 'eat-exec :around 'fixed-eat--make-process)
          (eval
              (form-replace
                  '(defun eat--t-write)
                  '(defun fixed-eat--t-write)
                  (form-replace
                      '((+ written wrote))
                      '((+ written max))
                      (form-replace
                          '((- end e))
                          '((- max wrote))
                          (function-lisp 'eat--t-write))))
              t)
          (best-compile 'fixed-eat--t-write)
          (advice-add 'eat--t-write :override 'fixed-eat--t-write)
          (defun hack-eat-exec (arguments)
              (when (equal (caddr arguments) "/usr/bin/env")
                  (setcar (cddr arguments) "env"))
              arguments)
          (advice-add 'eat-exec :filter-args 'hack-eat-exec)
          (defun eat-point ()
              (when eat-terminal
                  (marker-position
                      (eat-term-display-cursor eat-terminal))))
          (setq eat-enable-shell-prompt-annotation nil)
          (set-face-foreground 'eat-term-color-0  "#505050")
          (set-face-foreground 'eat-term-color-1  "#C00000")
          (set-face-foreground 'eat-term-color-2  "#00C000")
          (set-face-foreground 'eat-term-color-3  "#C0C000")
          (set-face-foreground 'eat-term-color-4  "#6060C0")
          (set-face-foreground 'eat-term-color-5  "#C000C0")
          (set-face-foreground 'eat-term-color-6  "#00C0C0")
          (set-face-foreground 'eat-term-color-7  "#E0E0E0")
          (set-face-foreground 'eat-term-color-8  "#707070")
          (set-face-foreground 'eat-term-color-9  "#FF0000")
          (set-face-foreground 'eat-term-color-10 "#00FF00")
          (set-face-foreground 'eat-term-color-11 "#FFFF00")
          (set-face-foreground 'eat-term-color-12 "#8080FF")
          (set-face-foreground 'eat-term-color-13 "#FF00FF")
          (set-face-foreground 'eat-term-color-14 "#00FFFF")
          (set-face-foreground 'eat-term-color-15 "#FFFFFF")
          (eat-eshell-mode 1)
          (eat-eshell-visual-command-mode 1))

#+end_src

* Emac Shell
https://howardism.org/Technical/Emacs/piper-presentation.html

Howard Abrahams configuration:

  #+BEGIN_SRC elisp
      (use-package eshell
	:init
	(setq eshell-buffer-shorthand t
	      eshell-scroll-to-bottom-on-input 'all
	      eshell-error-if-no-glob t
	      eshell-hist-ignoredups t
	      eshell-save-history-on-exit t
	      eshell-prefer-lisp-functions nil
	      eshell-destroy-buffer-when-process-dies t)
    )
#+END_SRC

** Visuals
*** Prompt
#+begin_src emacs-lisp
  (use-package eshell-prompt-extras
    :ensure t
    :config
     (with-eval-after-load "esh-opt"
  (autoload 'epe-theme-lambda "eshell-prompt-extras")
  (setq eshell-highlight-prompt nil
        eshell-prompt-function 'epe-theme-lambda))
  )
#+end_src


*** Syntax Highlighting

#+begin_src emacs-lisp
(use-package eshell-syntax-highlighting
  :ensure t
  :after eshell-mode
  :config
  (eshell-syntax-highlighting-global-mode +1))

#+end_src

** Help

#+begin_src emacs-lisp
  (use-package esh-help
    :ensure t
    :after eshell-mode
    :config
     (setup-esh-help-eldoc)
  )
#+end_src

** Change Directories quickly
from https://karthinks.com/software/jumping-directories-in-eshell/

replaces Melpa Package eshell-z

#+begin_src emacs-lisp
  (defun eshell/z (&optional regexp)
    "Navigate to a previously visited directory in eshell, or to
     any directory proferred by 'consult-dir'."
    (let ((eshell-dirs (delete-dups
                        (mapcar 'abbreviate-file-name
                                (ring-elements eshell-last-dir-ring)))))
      (cond
       ((and (not regexp) (featurep 'consult-dir))
        (let* ((consult-dir--source-eshell `(:name "Eshell"
                                             :narrow ?e
                                             :category file
                                             :face consult-file
                                             :items ,eshell-dirs))
               (consult-dir-sources (cons consult-dir--source-eshell
                                          consult-dir-sources)))
          (eshell/cd (substring-no-properties
                      (consult-dir--pick "Switch directory: ")))))
       (t (eshell/cd (if regexp (eshell-find-previous-directory regexp)
                            (completing-read "cd: " eshell-dirs)))))))
#+end_src

* Bye
#+begin_src emacs-lisp
;;; basic-setup.el ends here
#+end_src