EmacsWiki: Alex Schroeder on Windows (original) (raw)

Download Git

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

(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 "") '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. )