;;; See https://www.emacswiki.org/wiki/Alex_Schroeder

;; Install use-package if necessary. The use-package expressions then
;; contain :ensure t for further installations.
(package-initialize)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(unless (package-installed-p 'use-package)
  (package-install 'use-package))

;; No PuTTY
(eval-after-load "tramp" '(tramp-without-putty))

(defun tramp-without-putty ()
  "Disable all putty related stuff."
  ;; PuTTY: no snooping for credentials in the registry (Talk to IT security: Patrick)
  (setq tramp-completion-function-alist-putty nil)
  (defun tramp-parse-putty (&rest ignore) "Never parse PuTTY sessions." nil))

;; UTF-8
(prefer-coding-system 'utf-8)

;; No tabs
(setq-default indent-tabs-mode nil)

;; disable fancy stuff
(dolist (mode '(blink-cursor-mode
		tool-bar-mode
		menu-bar-mode
		scroll-bar-mode))
  (when (fboundp mode)
    (funcall mode -1)))

;; active some other bling
;; (toggle-frame-fullscreen)
(show-paren-mode 1)
(winner-mode 1)
;; (windmove-default-keybindings)
(column-number-mode 1)

;; save minibuffer history
(savehist-mode 1)

;; settings
(setq visible-bell t
      completion-ignore-case t
      read-buffer-completion-ignore-case t
      ;; use flex everywhere!
      completion-styles '(basic partial-completion flex)
      completion-category-overrides nil
      completion-category-defaults nil)
(setq sentence-end-double-space nil)

;; on Windows, the menu button of the Atreus keyboard I use is not
;; mapped to M-x
(global-set-key (kbd "<apps>") 'execute-extended-command)

;; buffers
(use-package ibuffer
  :ensure t
  :bind ("C-x C-b" . ibuffer)
  :config (setq ibuffer-formats
                ;; switch formats using `
                '((mark " "
                        (name 40 40 :left :elide)
                        " " filename-and-process)
                  (mark " "
                        (name 20 20 :left :elide)
                        " " filename))))

(global-set-key (kbd "C-x b") 'switch-buffer-or-find-file)

(defvar asc:file-names-seen nil
  "List of file names seen.")

(defun asc:file-names-seen-update ()
  "Add the current file name to `asc:file-names-seen'."
  (let ((name (or buffer-file-name dired-directory)))
    (when name
      (setq asc:file-names-seen
            (cons name (delete name asc:file-names-seen))))))

(add-hook 'find-file-hook 'asc:file-names-seen-update)
(add-hook 'dired-after-readin-hook 'asc:file-names-seen-update)

(defvar switch-buffer-or-find-file-history nil
  "History of file names or buffers picked.")

;; default history-length is 100 which is not enough
(put 'switch-buffer-or-find-file-history 'history-length 1000)

(defun switch-buffer-or-find-file ()
  "Switch buffer or find file."
  (interactive)
  (let ((buffer-names (mapcar 'buffer-name (buffer-list)))
        (file-names nil)
        (file-names-alist nil)
        (default nil)n
        (this-buffer-name (buffer-name (current-buffer))))
    ;; build filename list (reversed!)
    (dolist (full-name asc:file-names-seen)
      (let* ((name (if (file-directory-p full-name)
                       ;; parent directory with a slash…
                       (file-name-as-directory
                        (file-name-nondirectory
                         (directory-file-name full-name)))
                     ;; filename
                     (file-name-nondirectory full-name)))
             (full-names (assoc name file-names-alist)))
        (setq file-names (cons name file-names))
        (if full-names
            (setcdr full-names (cons full-name (cdr full-names)))
          (setq file-names-alist (cons (cons name (list full-name))
                                       file-names-alist)))))
    ;; filter beginning of the buffer name list and figure out the default
    (while (and (not default) buffer-names)
      (let ((name (car buffer-names)))
        (if (or (string= (substring name 0 1) " ")
                (eq this-buffer-name name))
            (setq buffer-names (cdr buffer-names))
          (setq default name))))
    (setq candidates (completion-table-merge buffer-names file-names))
    (let* ((name (completing-read
                  (format "Switch to (%s): " default)
                  candidates
                  (lambda (s)
                    (and (not (string-empty-p s))
                         (not (or (string= (substring s 0 1) " ")
                                  (eq this-buffer-name s)))))
                  nil nil
                  'switch-buffer-or-find-file-history
                  default))
           (buf (get-buffer name))
           (files (cdr (assoc name file-names-alist))))
      (cond (buf (switch-to-buffer buf))
            ((= 1 (length files))
             (find-file (car files)))
            (t (find-file
                (completing-read "Which one of these files: " files)))))))

;; no casual window splitting
(setq special-display-buffer-names
      '("*compilation*" "*info*" "*Help*" "*grep*")
      special-display-function 'display-buffer-same-window)

;; selection
(use-package expand-region
  :ensure t
  :bind ("C-'" . er/expand-region))

;; German
(setq default-input-method 'german-prefix)

;; completion
(global-set-key (kbd "C-<tab>") #'hippie-expand)
(setq hippie-expand-try-functions-list
      '(try-expand-all-abbrevs try-expand-dabbrev
	try-expand-dabbrev-all-buffers try-expand-dabbrev-from-kill
	try-complete-lisp-symbol-partially try-complete-lisp-symbol))
(define-key minibuffer-local-map (kbd "C-<tab>") #'hippie-expand)

;; move line with M-up and M-down
(use-package move-text
  :ensure t
  :config (move-text-default-bindings))

;; idle highlight
(use-package idle-highlight-mode
  :ensure t
  :config (global-idle-highlight-mode))

;; http://endlessparentheses.com/fill-and-unfill-paragraphs-with-a-single-key.html
(defun endless/fill-or-unfill ()
  "Like `fill-paragraph', but unfill if used twice."
  (interactive)
  (let ((fill-column
         (if (eq last-command 'endless/fill-or-unfill)
             (progn (setq this-command nil)
                    (point-max))
           fill-column)))
    (call-interactively #'fill-paragraph)))

(global-set-key [remap fill-paragraph]
                #'endless/fill-or-unfill)

;; Dired
(setq dired-recursive-deletes 'always
      dired-recursive-copies 'always
      dired-deletion-confirmer 'y-or-n-p
      dired-clean-up-buffers-too nil
      delete-by-moving-to-trash t
      dired-dwim-target t
      ;; add -v for the natural sort of (version) numbers within text
      dired-listing-switches "-alv")

;; Hunspell
(setenv "LANG" "de_CH.UTF-8")
(setenv "DICTPATH" "c:/msys64/ucrt64/share/hunspell/")
(setq ispell-local-dictionary "de_CH"
      ispell-local-dictionary-alist
      '(("de_CH" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil nil nil utf-8)
        ;; add apostrophe
        ("en_US" "[[:alpha:]]" "[^[:alpha:]]" "['0-9]" t ("-d" "en_US") nil utf-8)))

(use-package dictionary
  :bind ("C-c d" . dictionary-search))

;; Swiper
(use-package swiper :ensure t
  :bind ("C-o" . swiper))

;; Number Mark
(add-to-list 'load-path (expand-file-name "asc" user-emacs-directory))
(autoload 'number-mark-mode "number-mark.el" "Working with numbers." t)

;; AsciiDoc
(use-package adoc-mode
  :ensure t
  :mode "\\.ad\\(oc\\)?\\'"
  :bind ("C-c C-o" . asc:adoc-follow-xref)
  :config
  (add-hook 'adoc-mode-hook 'visual-line-mode)
  (add-hook 'adoc-mode-hook 'flyspell-mode)
  (add-hook 'adoc-mode-hook 'abbrev-mode)
  (add-hook 'adoc-mode-hook 'number-mark-mode)
  (add-hook 'adoc-mode-hook (lambda () (setq ispell-local-dictionary "en_US"))))

(defun asc:modules-directory ()
  "Return the modules directory we're in."
  (let ((dir default-directory))
    (while (not (string= "modules"
                         (file-name-nondirectory
                          (directory-file-name dir))))
      (setq dir (expand-file-name
                 (file-name-concat dir ".."))))
    dir))

(defun asc:module-name ()
  "Return the name of the module we're in."
  (let ((dir default-directory)
        last)
    (while (not (string= "modules"
                         (file-name-nondirectory
                          (directory-file-name dir))))
      (setq last (file-name-nondirectory
                  (directory-file-name dir))
            dir (expand-file-name
                 (file-name-concat dir ".."))))
    last))

(defun asc:adoc-follow-xref ()
  "Follow the xref at point."
  (interactive)
  (let ((data (or (adoc-example-at-point)
                  (adoc-image-at-point)
                  (adoc-page-at-point)
                  (error "No Asciidoc reference at point")))
        module dir file)
    (cond ((= 3 (length data)) (setq module (nth 1 data) dir (nth 0 data) file (nth 2 data)))
          ((= 2 (length data)) (setq module (asc:module-name) dir (nth 0 data) file (nth 1 data)))
          (t (error "Cannot parse %S" data)))
    (find-file (file-name-concat (asc:modules-directory) module dir file))))

(defun adoc-example-at-point ()
  "Return the example at point."
  (save-excursion
    (goto-char (line-beginning-position))
    (when (looking-at "include::example\\$\\([^[]+\\)")
      (append '("examples") (split-string (match-string 1) ":")))))

(defun adoc-image-at-point ()
  "Return the image at point."
  (save-excursion
    (goto-char (line-beginning-position))
    (when (looking-at "image::\\([^[]+\\)")
      (append '("images") (split-string (match-string 1) ":")))))

(defun adoc-page-at-point ()
  "Return the page at point."
  (save-excursion
    (let ((id (adoc-xref-id-at-point)))
      (when id
        (append '("pages") (split-string id ":"))))))

;; See (edit-abbrevs)

(define-skeleton adoc:good-example "{goodexample}" nil
  "====\n"
  "{goodexample} " _ "\n"
  "====")

(define-skeleton adoc:bad-example "{badexample}" nil
  "====\n"
  "{badexample} " _ "\n"
  "====")

(define-skeleton adoc:ok-example "{okexample}" nil
  "====\n"
  "{okexample} " _ "\n"
  "====")

(define-skeleton adoc:code-example "code example" nil
  "." _ "\n"
  "[source#,]\n"
  "----\n"
  "\n"
  "----")

(defun adoc:nav-entry ()
  "Insert navigation entry and open file."
  (interactive)
  (unless (string= (file-name-nondirectory (buffer-file-name)) "nav.adoc")
    (error "Only works in nav.adoc files"))
  (let ((filename (string-replace " " "-"
                   (string-replace ".adoc" ""
                    (read-string "New file name: ")))))
    (dotimes (n (read-number "Level: " 3))
      (insert "*"))
    (insert " xref:" filename ".adoc[]")
    (find-file-other-window (concat "pages/" filename ".adoc"))
    (insert "= " (string-replace "-" " "
                                 (concat (capitalize (substring filename 0 1))
                                         (substring filename 1)))
            "\n"
            "include::ROOT:partial$attributes.adoc[]\n"
            "{help_url}/BSI%20CRM/Wertelisten/H_Wertelisten.htm[{help},role=mod]\n"
            "{spec_url}/Wertelisten/CTL_Wertelisten.htm[{spec},role=mod]\n")))

(defun adoc:image ()
  "Insert image with caption."
  (interactive)
  (let ((caption (read-string "Caption: "))
        (slug (read-string "Slug: "))
        (filename (file-name-nondirectory
                   (read-file-name "Image: " "../images/" nil t))))
    (insert "." caption "\n"
            "[#" slug "]\n"
            "image::" filename "[]\n")))

(defun adoc:xref ()
  "Insert xref to existing file."
  (interactive)
  (let* ((filename (read-file-name "File: " nil nil t))
         (path-elements (split-string filename "/"))
         (module (nth (- (length path-elements) 3) path-elements))
         (file (file-name-nondirectory filename))
         (this-path-elements (split-string default-directory "/"))
         (this-module (nth (- (length this-path-elements) 3) this-path-elements)))
    (if (string= module this-module)
        (insert "xref:" file "[]")
      (insert "xref:" module ":" file "[]"))))

(defun adoc:example ()
  "Insert example with existing file."
  (interactive)
  (let ((caption (read-string "Caption: "))
        (slug (read-string "Slug: "))
        (prefix (expand-file-name "../examples/"))
        (filename (read-file-name "Example: " "../examples/" nil t)))
    (setq filename (substring filename (length prefix))) ; doesn't work for examples from elsewhere!
    (insert "." caption "\n"
            "[source#" slug ",java]\n"
            "----\n"
            "include::example$" filename "[tags=]\n"
            "----\n"
            "<1>")))

(defconst asc:java-style
  '((c-basic-offset . 2)
    (c-comment-only-line-offset 0 . 0)
    (c-offsets-alist
     (inline-open . 0)
     (topmost-intro-cont . +)
     (statement-block-intro . +)
     (knr-argdecl-intro . 5)
     (substatement-open . +)
     (substatement-label . +)
     (label . +)
     (statement-case-open . +)
     (statement-cont . +)
     (arglist-intro . c-lineup-arglist-intro-after-paren)
     (arglist-close . c-lineup-arglist)
     (brace-list-intro first c-lineup-2nd-brace-entry-in-arglist c-lineup-class-decl-init-+ +)
     (access-label . 0)
     (inher-cont . c-lineup-java-inher)
     (func-decl-cont . c-lineup-java-throws)))
  "My C Programming Style")
(c-add-style "java" asc:java-style)

;; Customizations for all modes in CC Mode.
(defun asc:java-mode-common-hook ()
  (setq tab-width 8
        indent-tabs-mode nil))
(add-hook 'java-mode-hook 'asc:java-mode-common-hook)

(setq langtool-language-tool-jar "/dev/doc/LanguageTool-6.1/languagetool-commandline.jar"
      langtool-default-language "en-US"
      langtool-java-user-arguments '("-Dfile.encoding=UTF-8"))

(use-package langtool
  :ensure t
  :bind (("\C-x4w" . langtool-check)
         ("\C-x4W" . langtool-check-done)
         ("\C-x4l" . langtool-switch-default-language)
         ("\C-x44" . langtool-show-message-at-point)
         ("\C-x4c" . langtool-interactive-correction)))
(use-package langtool-popup
  :ensure t)
(use-package langtool-ignore-fonts
  :ensure t)
(langtool-ignore-fonts-add
 'adoc-mode '(markup-anchor-face
              markup-attribute-face
              ;; markup-big-face
              ;; markup-bold-face
              markup-code-face
              markup-command-face
              ;; markup-comment-face
              markup-complex-replacement-face
              ;; markup-emphasis-face
              markup-error-face
              markup-gen-face
              markup-internal-reference-face
              ;; markup-italic-face
              ;; markup-list-face
              markup-meta-face
              markup-meta-hide-face
              markup-passthrough-face
              markup-preprocessor-face
              markup-reference-face
              markup-replacement-face
              ;; markup-secondary-text-face
              ;; markup-small-face
              ;; markup-strong-face
              ;; markup-subscript-face
              ;; markup-superscript-face
              ;; markup-table-cell-face
              ;; markup-table-face
              ;; markup-table-row-face
              ;; markup-title-0-face
              ;; markup-title-1-face
              ;; markup-title-2-face
              ;; markup-title-3-face
              ;; markup-title-4-face
              ;; markup-title-5-face
              ;; markup-typewriter-face
              ;; markup-underline-face
              ;; markup-value-face
              markup-verbatim-face))
;; magit
(use-package magit
  :ensure t
  :bind ("C-c g" . magit-status))

;; magit and Cygwin
(defadvice magit-expand-git-file-name
    (before magit-expand-git-file-name-cygwin activate)
  "Handle Cygwin directory names such as /cygdrive/c/*
by changing them to C:/*"
  (when (string-match "^/cygdrive/\\([a-z]\\)/\\(.*\\)" filename)
    (setq filename (concat (match-string 1 filename) ":/"
			   (match-string 2 filename)))))

(defun un-cygwin-buffer-file-name ()
  (when (string-match "^\\([a-z]\\):/cygdrive/\\([a-z]\\)/\\(.*\\)" buffer-file-name)
    ;; assertion:  filename should look like "c:/cygwin/c/Users..." i.e. the drive is repeated
    (when (equal (match-string 1 buffer-file-name) (match-string 2 buffer-file-name))
      (set-visited-file-name
       (concat (match-string 1 buffer-file-name) ":/"
	       (match-string 3 buffer-file-name)) 't))))

(add-hook 'git-commit-mode-hook 'un-cygwin-buffer-file-name)

;; grep

;; default to case insensitive
(eval-after-load "grep"
  '(grep-apply-setting 'grep-command "grep --color -niH -e "))

(defun grep-word-at-point (word)
  "Grep for the region, or thing at point.
Per default, the same extension is used as the file-name of the
current buffer. Use a prefix argument to override either."
  (interactive (list (thing-at-point 'symbol)))
  (when (use-region-p)
    (setq word (buffer-substring-no-properties
		(region-beginning) (region-end))))
  (let* ((file-name (buffer-file-name))
	 (extension (and file-name (file-name-extension file-name)))
	 (pattern (if extension (concat "*." extension) "*")))
    (when current-prefix-arg
      (setq word (read-string "Grep for: " word)
	    pattern (read-string "Files to grep: " pattern)))
    (setq word (replace-regexp-in-string "\"" "\\\"" word))
    (grep (format "grep --color -niH -e \"%s\" %s" word pattern))))

(global-set-key (kbd "C-c s") 'grep-word-at-point)

(use-package wgrep
  :ensure t)

;; eshell

(global-set-key (kbd "C-z") 'asc:eshell-here)

(defun asc:eshell-here (&optional arg)
  (interactive "P")
  (if (and arg (buffer-file-name))
      (let ((dir (file-name-directory (buffer-file-name))))
	(eshell)
	(cd dir))
    (eshell arg)))

(global-set-key (kbd "C-x 4 C-z") 'asc:eshell-other-window)

(defun asc:eshell-other-window (&optional arg)
  (interactive "P")
  (if (one-window-p)
      (split-window)
    (other-window 1))
  (eshell arg))

(setq eshell-history-size 500
      eshell-save-history-on-exit t
      eshell-hist-ignoredups t
      eshell-last-dir-ring-size 500)

(add-hook 'eshell-mode-hook #'asc:eshell-init)

(defun asc:eshell-init ()
  (local-set-key (kbd "C-z") 'bury-buffer)
  (local-set-key (kbd "C-a") 'eshell-bol)
  (local-set-key (kbd "C-w") 'asc:kill-region)
  (local-set-key (kbd "<up>") 'previous-line)
  (local-set-key (kbd "<down>") 'next-line)
  (eldoc-mode 1)
  (eshell-smart-initialize)
  (setenv "PAGER" "cat")
  (setenv "EDITOR" "emacsclient"))

(defun asc:kill-region (begin end)
  "Since `eshell' adds read-only prompts, I need to override this."
  (interactive "r")
  (let ((inhibit-read-only t))
    (kill-region (region-beginning) (region-end))))

(setq shell-file-name (executable-find "cmdproxy")
      shell-file-name "C:/tools/emacs/libexec/emacs/28.2/x86_64-w64-mingw32/cmdproxy.exe")

;; initial frame size not so tall because the font size is so large
(setq initial-frame-alist
      '((top . 1) (left . 1) (width . 100) (height . 30)))

;; Theme at the end
(use-package brutalist-theme
  :ensure t
  :config
  (let
      ((fg "#111111")
       (fg-table "#222291")
       (fg-dim "dim gray")
       (fg-slight-dim "grey70")
       (bg "#fffff8")
       (bg-light "#ddddd8")
       (fg-light "#ddddd8")
       (bg-highlight "#FFF1AA")
       (bg-highlight-2 "LightCyan")
       (bg-highlight-3 "LightGreen")
       (bg-highlight-dim "#eeeee8")
       (diff-added "#e9ffe9")
       (diff-added-highlight "#a4f4a3")
       (diff-removed "#ffecec")
       (diff-removed-highlight "#f9cbca")
       (powerline1 "grey22")
       (powerline2 "grey40")
       (string "blue")
       (cursor "white smoke")
       (paren-match "blue")
       (paren-mismatch "red"))
    (custom-theme-set-faces
     'brutalist
     `(markup-list-face ((t (:background ,bg :foreground ,fg-table))))
     `(markup-complex-replacement-face ((t (:background ,bg-highlight :foreground ,fg))))
     `(markup-internal-reference-face ((t (:underline t :foreground ,fg-slight-dim))))
     `(markup-meta-face ((t (:background ,bg :foreground ,fg-dim))))
     `(markup-secondary-text-face ((t (:background ,bg :foreground ,fg-dim))))
     `(mode-line-inactive ((t (:inherit mode-line :foreground ,fg-dim)))))))
;; if you add to the above, (disable-theme 'brutalist) and enable the theme again
(enable-theme 'brutalist)

(add-hook 'after-init-hook
          (lambda ()
            ;; ensure this face really does get set!
            (set-face-foreground 'mode-line-inactive "dim gray")))

;; font even further back
(defface markup-replacement-face '((t (:inherit default))) "")
(when (find-font (font-spec :name "Iosevka"))
  (dolist (face '(default fixed-pitch))
    (set-face-attribute face nil :family "Iosevka" :height 120)))

;; Meow

(defun meow-setup ()
  (setq meow-cheatsheet-layout meow-cheatsheet-layout-qwerty)
  (meow-motion-overwrite-define-key
   '("j" . meow-next)
   '("k" . meow-prev)
   '("<escape>" . ignore))
  (meow-leader-define-key
   ;; SPC j/k will run the original command in MOTION state.
   '("j" . "H-j")
   '("k" . "H-k")
   ;; Use SPC (0-9) for digit arguments.
   '("1" . meow-digit-argument)
   '("2" . meow-digit-argument)
   '("3" . meow-digit-argument)
   '("4" . meow-digit-argument)
   '("5" . meow-digit-argument)
   '("6" . meow-digit-argument)
   '("7" . meow-digit-argument)
   '("8" . meow-digit-argument)
   '("9" . meow-digit-argument)
   '("0" . meow-digit-argument)
   '("/" . meow-keypad-describe-key)
   '("?" . meow-cheatsheet))
  (meow-normal-define-key
   '("0" . meow-expand-0)
   '("9" . meow-expand-9)
   '("8" . meow-expand-8)
   '("7" . meow-expand-7)
   '("6" . meow-expand-6)
   '("5" . meow-expand-5)
   '("4" . meow-expand-4)
   '("3" . meow-expand-3)
   '("2" . meow-expand-2)
   '("1" . meow-expand-1)
   '("-" . negative-argument)
   '(";" . meow-reverse)
   '("," . meow-inner-of-thing)
   '("." . meow-bounds-of-thing)
   '("[" . meow-beginning-of-thing)
   '("]" . meow-end-of-thing)
   '("a" . meow-append)
   '("A" . meow-open-below)
   '("b" . meow-back-word)
   '("B" . meow-back-symbol)
   '("c" . meow-change)
   '("d" . meow-delete)
   '("D" . meow-backward-delete)
   '("e" . meow-next-word)
   '("E" . meow-next-symbol)
   '("f" . meow-find)
   '("g" . meow-cancel-selection)
   '("G" . meow-grab)
   '("h" . meow-left)
   '("H" . meow-left-expand)
   '("i" . meow-insert)
   '("I" . meow-open-above)
   '("j" . meow-next)
   '("J" . meow-next-expand)
   '("k" . meow-prev)
   '("K" . meow-prev-expand)
   '("l" . meow-right)
   '("L" . meow-right-expand)
   '("m" . meow-join)
   '("n" . meow-search)
   '("o" . meow-block)
   '("O" . meow-to-block)
   '("p" . meow-yank)
   '("q" . meow-quit)
   '("Q" . meow-goto-line)
   '("r" . meow-replace)
   '("R" . meow-swap-grab)
   '("s" . meow-kill)
   '("t" . meow-till)
   '("u" . meow-undo)
   '("U" . meow-undo-in-selection)
   '("v" . meow-visit)
   '("w" . meow-mark-word)
   '("W" . meow-mark-symbol)
   '("x" . meow-line)
   '("X" . meow-goto-line)
   '("y" . meow-save)
   '("Y" . meow-sync-grab)
   '("z" . meow-pop-selection)
   '("'" . repeat)
   '("<escape>" . ignore)))

(defface meow-normal-indicator '((t (:foreground "orange"))) "N")

(use-package meow :ensure t
  :config (progn
            (meow-setup)
            (meow-global-mode 1)))

;; add isearch

(require 'transient)
(transient-define-prefix cc/isearch-menu ()
  "isearch Menu"
  [["Edit Search String"
    ("e"
     "Edit the search string (recursive)"
     isearch-edit-string
     :transient nil)
    ("w"
     "Pull next word or character word from buffer"
     isearch-yank-word-or-char
     :transient nil)
    ("s"
     "Pull next symbol or character from buffer"
     isearch-yank-symbol-or-char
     :transient nil)
    ("l"
     "Pull rest of line from buffer"
     isearch-yank-line
     :transient nil)
    ("y"
     "Pull string from kill ring"
     isearch-yank-kill
     :transient nil)
    ("t"
     "Pull thing from buffer"
     isearch-forward-thing-at-point
     :transient nil)]

   ["Replace"
    ("q"
     "Start ‘query-replace’"
     isearch-query-replace
     :if-nil buffer-read-only
     :transient nil)
    ("x"
     "Start ‘query-replace-regexp’"
     isearch-query-replace-regexp
     :if-nil buffer-read-only     
     :transient nil)]]

  [["Toggle"
    ("X"
     "Toggle regexp searching"
     isearch-toggle-regexp
     :transient nil)
    ("S"
     "Toggle symbol searching"
     isearch-toggle-symbol
     :transient nil)
    ("W"
     "Toggle word searching"
     isearch-toggle-word
     :transient nil)
    ("F"
     "Toggle case fold"
     isearch-toggle-case-fold
     :transient nil)
    ("L"
     "Toggle lax whitespace"
     isearch-toggle-lax-whitespace
     :transient nil)]

   ["Misc"
    ("o"
     "occur"
     isearch-occur
     :transient nil)]])

(define-key isearch-mode-map (kbd "<f2>") 'cc/isearch-menu)

;; at the very end, resume where we left off
(setq desktop-restore-frames nil
      desktop-save t
      desktop-load-locked-desktop t
      ;; don't save any files
      desktop-files-not-to-save ""
      desktop-globals-to-save
      '(desktop-missing-file-warning
        search-ring
        regexp-search-ring
        file-name-history
        asc:file-names-seen)
      desktop-modes-not-to-save
      '(tags-table-mode Info-mode
	dired-mode eww-mode))
(desktop-save-mode 1)

;; emacs-client
(server-start)

;; enable disabled stuff
(put 'narrow-to-region 'disabled nil)
(put 'downcase-region 'disabled nil)
(custom-set-variables
 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(package-selected-packages
   '(swiper expand-region expand-selection langtool langtool-ignore-fonts langtool-popup rw-hunspell brutalist-theme wgrep magit adoc-mode idle-highlight-mode move-text use-package)))
(custom-set-faces
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 )
