emacs.d
文件大小: unknow
源码售价: 5 个金币 积分规则     积分充值
资源说明:emacs dotfiles and plugins
#+TITLE: ~.emacs.d~

* Synopsis

Emacs configuration files written with the help of [[https://orgmode.org/][org-mode]] and [[https://orgmode.org/worg/org-contrib/babel/][org-babel]]

* Install Emacs with ~homebrew~

#+BEGIN_SRC shell
brew install emacs-plus@28 --with-mailutils --with-no-frame-refocus --with-xwidgets --with-native-comp
#+END_SRC

To start a bg service, run:

#+BEGIN_SRC xml
brew services start d12frosted/emacs-plus/emacs-plus@28
#+END_SRC

* Tidy up .emacs.d mess

#+begin_src emacs-lisp
(use-package no-littering)
#+end_src

* Better package management
** Better list-package mode

#+BEGIN_SRC emacs-lisp
(use-package paradox
  :custom
  (paradox-github-token t)
  :config
  (paradox-enable))
#+END_SRC

** Quelpa & use-packlage

#+begin_src emacs-lisp
(use-package quelpa-use-package
  :ensure nil
  :config
  (unless (package-installed-p 'quelpa)
    (with-temp-buffer
      (url-insert-file-contents "https://raw.githubusercontent.com/quelpa/quelpa/master/quelpa.el")
      (eval-buffer)
      (quelpa-self-upgrade)
      (quelpa
       '(quelpa-use-package
         :fetcher git
         :url "https://github.com/quelpa/quelpa-use-package.git"))
      (require 'quelpa-use-package))))
#+end_src

** Auto minor-mode for use-package

#+BEGIN_SRC emacs-lisp
(use-package auto-minor-mode)
#+END_SRC

** Ensure system-package

#+BEGIN_SRC emacs-lisp
(use-package system-packages
  :custom
  (system-packages-package-manager 'brew))

(use-package use-package-ensure-system-package :after system-packages)
#+END_SRC

* Initialiation defaults

** Async

#+begin_src emacs-lisp
(use-package async)
#+end_src

** Measure startup time

#+BEGIN_SRC emacs-lisp
(add-hook 'emacs-startup-hook
          (lambda ()
            (message "*** Emacs loaded in %s with %d garbage collections."
                     (format "%.2f seconds"
                             (float-time
                              (time-subtract after-init-time before-init-time)))
                     gcs-done)))
#+END_SRC

** Starting the server if not already started

#+begin_src emacs-lisp
(if (and (fboundp 'server-running-p)
         (not (server-running-p)))
   (server-start))
#+end_src

** Electric pairs only for prog-mode

#+begin_src emacs-lisp
(add-hook 'prog-mode-hook
          (lambda ()
            (electric-pair-mode 1)))
#+end_src

** Focus new frame

#+begin_src emacs-lisp
(when (featurep 'ns)
  (defun ns-raise-emacs ()
    "Raise Emacs."
    (ns-do-applescript "tell application \"Emacs\" to activate"))

  (defun ns-raise-emacs-with-frame (frame)
    "Raise Emacs and select the provided frame."
    (with-selected-frame frame
      (when (display-graphic-p)
        (ns-raise-emacs))))

  (add-hook 'after-make-frame-functions 'ns-raise-emacs-with-frame)
  (when (display-graphic-p)
    (ns-raise-emacs)))
#+end_src

** Errors handling and ignore server errors

When running as a deamon emacs checks if custom.el is in safe place. Here were
setting custom.el in ~/tmp~ dir and it will sometimes throw an
errors. Here is a dirty hack.

#+BEGIN_SRC emacs-lisp
(defadvice server-ensure-safe-dir
    (around
     my-around-server-ensure-safe-dir
     activate)
  "Ignores any errors raised from server-ensure-safe-dir"
  (ignore-errors ad-do-it))
#+end_src

Disable native-compile warnings when starting emacs. Warnings should
not break the init of Emacs.

#+begin_src emacs-lisp
(setq warning-minimum-level :error)
#+end_src

** Setting default coding system

#+BEGIN_SRC emacs-lisp
(set-language-environment 'utf-8)
(set-keyboard-coding-system 'utf-8-mac) ; For old Carbon emacs on OS X only
(setq locale-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
#+END_SRC

** Setting default display and editing options

#+BEGIN_SRC emacs-lisp
(set-default 'truncate-lines t)
(global-hl-line-mode 0)
(set-window-margins nil 0 0)
(electric-pair-mode 0)
(line-number-mode 1)
(column-number-mode 1)
(global-linum-mode 0)
(delete-selection-mode 1)
(global-auto-revert-mode 1)
(menu-bar-mode -1)

(use-package desktop
  :ensure nil
  :custom
  (desktop-save 'ask-if-new)
  (desktop-restore-eager 5)
  (desktop-load-locked-desktop t)
  (desktop-auto-save-timeout 30)
  (desktop-base-lock-name "lock")
  (desktop-files-not-to-save "^$")
  :config
  (desktop-save-mode +1))

(setq left-fringe-width  16
      right-fringe-width  16
      auto-save-default nil
      frame-resize-pixelwise t
      frame-title-format nil
      inhibit-startup-screen t
      make-backup-files nil
      ns-use-proxy-icon nil
      pop-up-frames nil
      ring-bell-function 'ignore
      show-paren-mode 1
      show-trailing-whitespace nil
      transient-mark-mode t
      vc-handled-backends nil
      ns-right-alternate-modifier nil
      create-lockfiles nil
      visible-bell t
      split-height-threshold 80
      split-width-threshold 160
      compilation-scroll-output t)

(fset 'yes-or-no-p 'y-or-n-p)

;;http://mbork.pl/2021-11-13_y-or-n-p_but_with_RET_meaning_yes
(defconst y-or-n-p-ret-yes-map
  (let ((map (make-sparse-keymap)))
    (set-keymap-parent map y-or-n-p-map)
    (define-key map [return] 'act)
    map)
  "A keymap for y-or-n-p with RET meaning \"yes\".")

(setq y-or-n-p-map y-or-n-p-ret-yes-map)

(global-unset-key (kbd "C-x C-c"))
(global-unset-key (kbd "S-w"))
(global-unset-key (kbd "C-x C-z"))
(windmove-default-keybindings 'super)
(winner-mode 1)

;; font sizes
(global-set-key (kbd "s-=")
                (lambda ()
                  (interactive)
                  (let ((old-face-attribute (face-attribute 'default :height)))
                    (message (format "Changed font size to %d" (+ old-face-attribute 10)))
                    (set-face-attribute 'default nil :height (+ old-face-attribute 10)))))

(global-set-key (kbd "s--")
                (lambda ()
                  (interactive)
                  (let ((old-face-attribute (face-attribute 'default :height)))
                    (message (format "Changed font size to %d" (- old-face-attribute 10)))
                    (set-face-attribute 'default nil :height (- old-face-attribute 10)))))

(global-set-key "\C-l" 'goto-line)
(global-set-key (kbd "") 'keyboard-escape-quit)

(global-set-key (kbd "M-s-") 'tab-next)
(global-set-key (kbd "M-s-") 'tab-previous)
(tab-bar-mode 1)
#+END_SRC

** Alerter - notifications for macos

#+begin_src emacs-lisp
(defun alerter--symbol-value (symbol)
  "Stripts keyword symbol name from a colon"
  (replace-regexp-in-string "^:" "" (symbol-name symbol)))

(defun alerter--option (args)
  "Returns a function that will generate single argument for alerter using ARGS as a string"
  (lambda (key)
    (concat "-" (alerter--symbol-value key) " " (plist-get args key))))

(setq alerter-default-args
      '(:title "Emacs" :sender "org.gnu.Emacs" :timeout "5"))

(defun alerter (message &rest args)
  "Notify user using native macOS notifications. MESSAGE will be displayed using alerter package, with additional ARGS"
  (if (executable-find "alerter")
      (let* ((args (append alerter-default-args args))
             (options (seq-filter (lambda (element) (keywordp element)) args))
	     (config (mapconcat (alerter--option args) options " "))
	     (cmd (concat "alerter " config " -message \"" (replace-regexp-in-string "\"" "\\\"" message  t t) "\" &")))
        (message cmd)
        (call-process-shell-command cmd))
    (error "Can't find alerter executable")))
#+end_src

** Check on save if config is valid

#+begin_src emacs-lisp
(setq check-if-config-valid-files '("init.el" "early-init.el" "README.org"))

(defun check-if-config-valid ()
  (alerter "Checking config..." :group "check-config" )
  (async-start (lambda ()
		 (call-process-shell-command "./scripts/validate"))
	       (lambda (results)
		 (if (< 0 results )
		     (alerter "Problem with emacs config!" :group "check-config" :sound "funky" )
		   (alerter "Config valid!" :group "check-config" )))))

(defun current-file-is-config ()
  (member t (mapcar (lambda (file)
		      (message (expand-file-name file user-emacs-directory))
		      (message (buffer-file-name))
		      (equal (expand-file-name file user-emacs-directory) (buffer-file-name))) check-if-config-valid-files)))

(add-hook 'after-save-hook
	  (lambda ()
	    (if (current-file-is-config)
		(check-if-config-valid))))
#+end_src

** xwidget-webkit problem with emacsclient

We need to redefine ~xwidget-webkit-enable-plugins~ variable for webkit
to work properly

#+begin_src emacs-lisp
(if (boundp 'xwidget-webkit-enable-plugins)
      (setq xwidget-webkit-enable-plugins t)
  (defvar xwidget-webkit-enable-plugins t))
#+end_src

** Default trash behavior

#+BEGIN_SRC emacs-lisp
(use-package osx-trash
  :if (eq system-type 'darwin)
  :ensure-system-package trash
  :init
  (osx-trash-setup)
  :custom
  (delete-by-moving-to-trash t))
#+END_SRC

** System specific defaults

#+BEGIN_SRC emacs-lisp
(when (eq system-type 'darwin)
  (defvar ls-lisp-use-insert-directory-program)
  (defvar powerline-image-apple-rgb)
  (setq ns-use-srgb-colorspace t)
  (setq powerline-image-apple-rgb t)
  (require 'ls-lisp)
  (setq ls-lisp-use-insert-directory-program nil))
#+END_SRC

** Disabling suspend-frame binding

Very annoying binding, lets get rid of it.

#+BEGIN_SRC emacs-lisp
(global-unset-key (kbd "C-z"))
#+END_SRC

** Browser Url

Set build-in module defaults to handle chrome as a default browser

#+BEGIN_SRC emacs-lisp
(use-package browse-url
  :custom
  (browse-url-browser-function 'browse-url-default-browser))

(use-package browse-url-dwim
  :config
  (browse-url-dwim-mode 1))
#+END_SRC

** Mac Only - initialize emacs with proper PATH

Move your env variables to ~.zshenv~ befre setting this up

#+BEGIN_SRC emacs-lisp
(use-package exec-path-from-shell
  :custom
  (exec-path-from-shell-arguments nil)
  :config
  (when (or (memq window-system '(ns x))
            (daemonp))
    (exec-path-from-shell-initialize)
    (exec-path-from-shell-copy-env "GOPATH")
    (when (eq (length (getenv "NODE_PATH")) 0)
      (setenv "NODE_PATH" "/usr/local/lib/node_modules"))))
#+END_SRC

** EasyGP Assistant

#+begin_src emacs-lisp
(use-package epa
  :if (eq system-type 'darwin)
  :ensure-system-package (gpg pinentry-mac))

(use-package epa
  :if (eq system-type 'gnu/linux))
#+end_src

when staring, we should prepare our [[https://cerb.ai/guides/mail/gpg-setup-on-mac/][gpg config]]

#+begin_src sh
gpg --list-keys
echo "pinentry-program /usr/local/bin/pinentry-mac" >> $HOME/.gnupg/gpg-agent.conf
gpg --expert --full-generate-key
#+end_src

* Window management and frame management

** Pooper (link)

#+begin_src emacs-lisp
(use-package popper
  :ensure t ; or :straight t
  :bind (("s-§"   . popper-toggle-latest)
         ("M-§" . popper-cycle)
         ("s-M-§" . popper-toggle-type)
         ("s-"   . popper-toggle-latest)
         ("M-" . popper-cycle)
         ("s-M-" . popper-toggle-type))
  :custom
  (popper-reference-buffers
   '("\\*Messages\\*"
     "Output\\*$"
     "\\*Async Shell Command\\*"
     compilation-mode
     vterm-mode))
  (popper-mode-line '(:eval
                      (propertize " POP " 'face 'mode-line-emphasis)))
  :config
  (popper-mode +1)
  (popper-echo-mode +1))
#+end_src

** Shackle ([[https://github.com/wasamasa/shackle][link]])

*Shackle* gives you the means to put an end to popped up buffers not
behaving they way you'd like them to. By setting up simple rules you
can for instance make Emacs always select help buffers for you or make
everything reuse your currently selected window.

#+BEGIN_SRC emacs-lisp
(use-package shackle
  :custom
  (shackle-rules
   '(("*eshell*"               :select t   :other t)
     (flycheck-error-list-mode :select t   :align below :size 0.25)
     (compilation-mode         :select nil :align below :size 0.25)
     (messages-buffer-mode     :select t   :align below :size 0.25)
     (inferior-emacs-lisp-mode :select t   :align below :size 0.25)
     (help-mode                :select t   :align right :size 0.5)
     (helpful-mode             :select t   :align right :size 0.5)
     ("*rg*"                   :select t   :other t)
     (" *Deletions*"           :select t   :align below :size 0.25)
     (" *Marked Files*"        :select t   :align below :size 0.25)
     ("*Org Select*"           :same t)
     ("*Org Note*"             :select t   :align below :size 0.33)
     ("*Org Links*"            :select t   :align below :size 0.2)
     (" *Org todo*"            :select t   :align below :size 0.2)
     ("*Man.*"                 :select t   :align below :size 0.5  :regexp t)
     ("*Org Src.*"             :select t   :align right :size 0.5  :regexp t)))
  :config
  (shackle-mode t))
#+END_SRC

* Packages

** Bufler

#+begin_src emacs-lisp
(use-package bufler
  :quelpa (bufler :fetcher github :repo "alphapapa/bufler.el"
                  :files (:defaults (:exclude "helm-bufler.el"))))
#+end_src

** Eshell ([[https://masteringemacs.org/article/complete-guide-mastering-eshell][link]])

*Eshell* is a shell written entirely in Emacs-Lisp, and it replicates
most of the features and commands from GNU CoreUtils and the
Bourne-like shells. So by re-writing common commands like ls and cp in
Emacs-Lisp, Eshell will function identically on any environment Emacs
itself runs on.

#+BEGIN_SRC emacs-lisp
(use-package eshell
  :custom
  (eshell-banner-message "")
  (eshell-scroll-to-bottom-on-input t)
  (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)
  (eshell-highlight-prompt nil)

  :config
  (setenv "PAGER" "cat")
  (setenv "PATH"
          (concat
           "/usr/local/bin:/usr/local/sbin:"
           (getenv "PATH")))

  (defun eshell/gst (&rest args)
    (magit-status (pop args) nil)
    (eshell/echo)))

(use-package xterm-color
  :after (eshell eshell-toggle)
  :hook
  (eshell-before-prompt . (lambda ()
                            (setq xterm-color-preserve-properties t)))
  (eshell-preoutput-filter-functions . xterm-co§§§§§§§§§§§§lor-filter)
  (shell-mode . (lambda ()
                  ;; Disable font-locking in this buffer to improve performance
                  (font-lock-mode -1)
                  ;; Prevent font-locking from being re-enabled in this buffer
                  (make-local-variable 'font-lock-function)
                  (setq font-lock-function (lambda (_) nil))
                  (add-hook 'comint-preoutput-filter-functions 'xterm-color-filter nil t)))
  :custom
  (comint-output-filter-functions
   (remove 'ansi-color-process-output comint-output-filter-functions))
  (eshell-output-filter-functions
   (remove 'eshell-handle-ansi-color eshell-output-filter-functions))
  :config)

(use-package eshell-up
  :after eshell)

(use-package shrink-path
  :after eshell
  :custom
  ((eshell-prompt-regexp "^.*❯ ")
   (eshell-prompt-function
    (lambda nil
      (let ((base/dir (shrink-path-prompt default-directory)))
        (concat (propertize (car base/dir)
                            'face 'font-lock-comment-face)
                (propertize (cdr base/dir)
                            'face 'font-lock-constant-face)
                (propertize " ❯" 'face 'eshell-prompt-face)
                ;; needed for the input text to not have prompt face
                (propertize " " 'face 'default)))))))
#+END_SRC

** Toogle undecorated frame

#+BEGIN_SRC emacs-lisp
(defun toggle-frame-maximized-undecorated ()
  (interactive)
  (let* ((frame (selected-frame))
         (on? (and (frame-parameter frame 'undecorated)
                   (eq (frame-parameter frame 'fullscreen) 'maximized)))
         (geom (frame-monitor-attribute 'geometry))
         (initial-x (first geom))
         (display-height (first (last geom))))
    (if on?
        (progn
          (set-frame-parameter frame 'undecorated nil)
          (toggle-frame-maximized))
      (progn
        (set-frame-position frame initial-x 0)
        (set-frame-parameter frame 'fullscreen 'maximized)
        (set-frame-parameter frame 'undecorated t)
        (set-frame-height frame (- display-height 26) nil t)
        (set-frame-position frame initial-x 0)))))
#+END_SRC

** Scratch ([[https://github.com/ieure/scratch-el][link]])

Scratch is an extension to Emacs that enables one to create scratch
buffers that are in the same mode as the current buffer. This is
notably useful when working on code in some language; you may grab
code into a scratch buffer, and, by virtue of this extension, do so
using the Emacs formatting rules for that language.

#+BEGIN_SRC emacs-lisp
(use-package scratch)
#+END_SRC

** Eshell Toggle ([[https://github.com/4DA/eshell-toggle][link]])

Simple functionality to show/hide eshell/ansi-term (or almost any
other buffer, see eshell-toggle-init-function description below) at
the bottom of active window with directory of its buffer.

#+BEGIN_SRC emacs-lisp
(use-package eshell-toggle
  :after eshell
  :bind
  ("s-`" . eshell-toggle)
  :custom
  (eshell-toggle-name-separator " ❯ ")
  (eshell-toggle-size-fraction 3)
  (eshell-toggle-use-projectile-root t))
#+END_SRC

** ESUP

#+begin_src emacs-lisp
(use-package esup)
#+end_src

** vterm

#+BEGIN_SRC emacs-lisp
(use-package vterm
  :after consult
  :custom
  (vterm-always-compile-module t))

(use-package multi-vterm
  :after vterm)
#+END_SRC

** Marginalia

#+begin_src emacs-lisp
;; Enable richer annotations using the Marginalia package
(use-package marginalia
  ;; Either bind `marginalia-cycle` globally or only in the minibuffer
  :bind (:map minibuffer-local-map
         ("M-A" . marginalia-cycle))

  ;; The :init configuration is always executed (Not lazy!)
  :init

  ;; Must be in the :init section of use-package such that the mode gets
  ;; enabled right away. Note that this forces loading the package.
  (marginalia-mode))
#+end_src

** Editor Config ([[https://github.com/editorconfig/editorconfig-emacs][link]])

*EditorConfig* helps maintain consistent coding styles for multiple
developers working on the same project across various editors and
IDEs. The EditorConfig project consists of a file format for defining
coding styles and a collection of text editor plugins that enable
editors to read the file format and adhere to defined
styles. EditorConfig files are easily readable and they work nicely
with version control systems.

#+BEGIN_SRC emacs-lisp
(use-package editorconfig
  :init
  (editorconfig-mode 1))
#+END_SRC

** Posframe

#+BEGIN_SRC emacs-lisp
(use-package posframe
  :ensure t)
#+END_SRC

** Expand region

#+BEGIN_SRC emacs-lisp
(use-package expand-region
  :bind ("C-=" . er/expand-region))
#+END_SRC

** Restart Emacs

#+BEGIN_SRC emacs-lisp
(use-package restart-emacs)
#+END_SRC

** All the icons ([[https://github.com/domtronn/all-the-icons.el][link]])

A utility package to collect various Icon Fonts and propertize them
within Emacs.

#+BEGIN_SRC emacs-lisp
(use-package all-the-icons
  :custom
  (inhibit-compacting-font-caches t))
#+END_SRC

** Projectile ([[https://github.com/bbatsov/projectile][link]])

Projectile is a project interaction library for Emacs. Its goal is to
provide a nice set of features operating on a project level without
introducing external dependencies (when feasible)

#+BEGIN_SRC emacs-lisp
  (use-package projectile
    :demand t
    :bind-keymap
    ("C-c p" . projectile-command-map)
    :custom
    (projectile-enable-caching t)
    (projectile-sort-order 'recently-active)
    :config
    (projectile-mode)
    ;; Projectile is testing in the reverse order so more specific must me at the end
    (projectile-register-project-type
     'npm '("package.json")
     :compile "npm i"
     :test "npm test"
     :run "npm start"
     :test-suffix ".spec.js")

    (projectile-register-project-type
     'opera '("desktop/BUILD.gn" "desktop/gn_opera.py")
     :project-file "desktop/BUILD.gn"
     :configure "desktop/gn_opera.py --release --force product=\\\"gx\\\" use_jumbo_build=false rich_hints_test_build=true use_goma=true goma_dir=\"\\\"/Users/opera_user/goma\\\"\""
     :compile "ninja -j 150 -C chromium/src/out/Release opera"))
#+END_SRC

** ibuffer-projectile ([[https://github.com/purcell/ibuffer-projectile][link]])

#+begin_src emacs-lisp
(use-package ibuffer-projectile
  :hook
  (ibuffer . (lambda ()
               (ibuffer-projectile-set-filter-groups)
               (unless (eq ibuffer-sorting-mode 'alphabetic)
                 (ibuffer-do-sort-by-alphabetic)))))
#+end_src

** Vertico ([[https://github.com/minad/vertico][link]])

#+begin_src emacs-lisp
(use-package vertico
  :init
  :custom
  (vertico-resize nil)
  (vertico-cycle t)
  :config
  (vertico-mode 1))
#+end_src

also helpful emacs config just for vertico

#+begin_src emacs-lisp
(use-package emacs
  :ensure nil
  :init
  ;; Add prompt indicator to `completing-read-multiple'.
  ;; Alternatively try `consult-completing-read-multiple'.
  (defun crm-indicator (args)
    (cons (concat "[CRM] " (car args)) (cdr args)))
  (advice-add #'completing-read-multiple :filter-args #'crm-indicator)

  :hook
  (minibuffer-setup . cursor-intangible-mode)

  :custom
  ;; Do not allow the cursor in the minibuffer prompt
  (minibuffer-prompt-properties
   '(read-only t cursor-intangible t face minibuffer-prompt))
  ;; Emacs 28: Hide commands in M-x which do not work in the current mode.
  ;; Vertico commands are hidden in normal buffers.
  (read-extended-command-predicate
        #'command-completion-default-include-p)
  ;; Enable recursive minibuffers
  (enable-recursive-minibuffers t))
#+end_src

** Orderless ([[https://github.com/oantolin/orderless][link]])

#+begin_src emacs-lisp
(use-package orderless
  :custom
  (completion-styles '(orderless))
  (completion-category-defaults nil)
  (completion-category-overrides
   '((file (styles partial-completion)))
  (orderless-component-separator #'orderless-escapable-split-on-space)))
#+end_src

** Savehist

#+begin_src emacs-lisp
(use-package savehist
  :after no-littering
  :init
  (savehist-mode))
#+end_src

** Consult ([[https://github.com/minad/consult][link]])

#+begin_src emacs-lisp
;; Example configuration for Consult
(use-package consult
  :after projectile
  :demand t
  ;; Replace bindings. Lazily loaded due by `use-package'.
  :bind (;; C-c bindings (mode-specific-map)
         ("C-c h" . consult-history)
         ("C-c m" . consult-mode-command)
         ("C-c b" . consult-bookmark)
         ("C-c k" . consult-kmacro)
         ;; C-x bindings (ctl-x-map)
         ("C-x M-:" . consult-complex-command)     ;; orig. repeat-complex-command
         ("C-x b" . consult-buffer)                ;; orig. switch-to-buffer
         ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
         ("C-x 5 b" . consult-buffer-other-frame)  ;; orig. switch-to-buffer-other-frame
         ;; Custom M-# bindings for fast register access
         ("M-#" . consult-register-load)
         ("M-'" . consult-register-store)          ;; orig. abbrev-prefix-mark (unrelated)
         ("C-M-#" . consult-register)
         ;; Other custom bindings
         ("M-y" . consult-yank-pop)                ;; orig. yank-pop
         (" a" . consult-apropos)            ;; orig. apropos-command
         ;; M-g bindings (goto-map)
         ("M-g e" . consult-compile-error)
         ("M-g f" . consult-flymake)               ;; Alternative: consult-flycheck
         ("M-g g" . consult-goto-line)             ;; orig. goto-line
         ("M-g M-g" . consult-goto-line)           ;; orig. goto-line
         ("M-g o" . consult-outline)               ;; Alternative: consult-org-heading
         ("M-g m" . consult-mark)
         ("M-g k" . consult-global-mark)
         ("M-g i" . consult-imenu)
         ("M-g I" . consult-imenu-multi)
         ;; M-s bindings (search-map)
         ("M-s f" . consult-find)
         ("M-s F" . consult-locate)
         ("M-s g" . consult-grep)
         ("M-s G" . consult-git-grep)
         ("M-s r" . consult-ripgrep)
         ("M-s l" . consult-line)
         ("M-s L" . consult-line-multi)
         ("M-s m" . consult-multi-occur)
         ("M-s k" . consult-keep-lines)
         ("M-s u" . consult-focus-lines)
         ;; Isearch integration
         ("M-s e" . consult-isearch-history)
         :map isearch-mode-map
         ("M-e" . consult-isearch-history)         ;; orig. isearch-edit-string
         ("M-s e" . consult-isearch-history)       ;; orig. isearch-edit-string
         ("M-s l" . consult-line)                  ;; needed by consult-line to detect isearch
         ("M-s L" . consult-line-multi))           ;; needed by consult-line to detect isearch

  ;; Enable automatic preview at point in the *Completions* buffer.
  ;; This is relevant when you use the default completion UI,
  ;; and not necessary for Vertico, Selectrum, etc.

  ;; The :init configuration is always executed (Not lazy)
  :init

  ;; Optionally configure the register formatting. This improves the register
  ;; preview for `consult-register', `consult-register-load',
  ;; `consult-register-store' and the Emacs built-ins.
  (setq register-preview-delay 0
        register-preview-function #'consult-register-format)

  ;; Optionally tweak the register preview window.
  ;; This adds thin lines, sorting and hides the mode line of the window.
  (advice-add #'register-preview :override #'consult-register-window)

  ;; Optionally replace `completing-read-multiple' with an enhanced version.
  (advice-add #'completing-read-multiple :override #'consult-completing-read-multiple)

  ;; Use Consult to select xref locations with preview
  (setq xref-show-xrefs-function #'consult-xref
        xref-show-definitions-function #'consult-xref)

  ;; Configure other variables and modes in the :config section,
  ;; after lazily loading the package.
  :config

  ;; Optionally configure preview. The default value
  ;; is 'any, such that any key triggers the preview.
  ;; (setq consult-preview-key 'any)
  ;; (setq consult-preview-key (kbd "M-."))
  ;; (setq consult-preview-key (list (kbd "") (kbd "")))
  ;; For some commands and buffer sources it is useful to configure the
  ;; :preview-key on a per-command basis using the `consult-customize' macro.
  (consult-customize
   consult-theme
   :preview-key '(:debounce 0.2 any)
   consult-ripgrep consult-git-grep consult-grep
   consult-bookmark consult-recent-file consult-xref
   consult--source-buffer consult--source-project-buffer consult--source-bookmark
   :preview-key (kbd "M-."))

  ;; Optionally configure the narrowing key.
  ;; Both < and C-+ work reasonably well.
  (setq consult-narrow-key "<") ;; (kbd "C-+")

  (autoload 'projectile-project-root "projectile")
  (setq consult-project-root-function #'projectile-project-root))
#+end_src

** Consult Projectile ([[https://github.com/emacsmirror/consult-projectile][link]])

#+begin_src emacs-lisp
(use-package consult-projectile
  :demand t
  :after (consult projectile)
  :bind-keymap ("C-c p" . projectile-command-map)
  :bind (:map projectile-command-map
              ("p" . consult-projectile))
  :custom
  (projectile-switch-project-action 'consult-projectile))
#+end_src

** Embark ([[https://github.com/oantolin/embark/][link]])

#+begin_src emacs-lisp
(defun embark-which-key-indicator ()
  "An embark indicator that displays keymaps using which-key.
The which-key help message will show the type and value of the
current target followed by an ellipsis if there are further
targets."
  (lambda (&optional keymap targets prefix)
    (if (null keymap)
        (which-key--hide-popup-ignore-command)
      (which-key--show-keymap
       (if (eq (plist-get (car targets) :type) 'embark-become)
           "Become"
         (format "Act on %s '%s'%s"
                 (plist-get (car targets) :type)
                 (embark--truncate-target (plist-get (car targets) :target))
                 (if (cdr targets) "…" "")))
       (if prefix
           (pcase (lookup-key keymap prefix 'accept-default)
             ((and (pred keymapp) km) km)
             (_ (key-binding prefix 'accept-default)))
         keymap)
       nil nil t (lambda (binding)
                   (not (string-suffix-p "-argument" (cdr binding))))))))

(use-package embark
  :after which-key
  :demand t
  :bind
  (("s-." . embark-act)         ;; pick some comfortable binding
   ("C-;" . embark-dwim)        ;; good alternative: M-.
   ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'

  :custom
  (embark-indicators
   '(embark-which-key-indicator
     embark-highlight-indicator
     embark-isearch-highlight-indicator))

  (prefix-help-command #'embark-prefix-help-command)

  :config
  ;; Unbind help-command so completing-read interface can do it's job
  (unbind-key "C-h " global-map)
  (unbind-key "C-h" help-map)
  ;;(unbind-key "C-h" ehelp-map)

  ;; 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)))))

(defun embark-hide-which-key-indicator (fn &rest args)
  "Hide the which-key indicator immediately when using the completing-read prompter."
  (which-key--hide-popup-ignore-command)
  (let ((embark-indicators
         (remq #'embark-which-key-indicator embark-indicators)))
    (apply fn args)))

(advice-add #'embark-completing-read-prompter
            :around #'embark-hide-which-key-indicator)
#+end_src

** Embark Consult ([[https://github.com/oantolin/embark/blob/master/embark-consult.el][link]])

Consult users will also want the embark-consult package.

#+begin_src emacs-lisp
(use-package embark-consult
  :after (embark consult)
  :demand t
  :hook
  (embark-collect-mode . consult-preview-at-point-mode))
#+end_src

** Confu

#+begin_src emacs-lisp
(use-package corfu
  ;; Optional customizations
  :custom
  (completion-cycle-threshold 3)
  (tab-always-indent 'complete)
  (tab-first-completion 'word-or-paren-or-punct)
  (corfu-cycle t)
  (corfu-auto t)
  (corfu-commit-predicate nil)
  (corfu-quit-at-boundary t)
  (corfu-quit-no-match t)        ;; Automatically quit if there is no match
  (corfu-echo-documentation 0.5) ;; Disable documentation in the echo area
  :init
  (corfu-global-mode))

;; Use dabbrev with Corfu!
(use-package dabbrev
  ;; Swap M-/ and C-M-/
  :bind (("M-/" . dabbrev-completion)
         ("C-M-/" . dabbrev-expand)))

;; Enable Corfu completion UI
;; See the Corfu REA DME for more configuration tips.
(use-package corfu
  :init
  (corfu-global-mode))

;; Add extensions
(use-package cape
  ;; Bind dedicated completion commands
  :bind (("C-." . completion-at-point)
         ("C-c /" . completion-fil))
  :init
  (add-to-list 'completion-at-point-functions #'cape-file)
  (add-to-list 'completion-at-point-functions #'cape-tex)
  (add-to-list 'completion-at-point-functions #'cape-dabbrev)
  (add-to-list 'completion-at-point-functions #'cape-keyword))
#+end_src

** kind-icon ()

#+begin_src emacs-lisp
(use-package kind-icon
  :ensure t
  :after corf
  :custom
  (kind-icon-default-face 'corfu-default) ; to compute blended backgrounds correctly
  :config
  (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))
#+end_src

** K8s

#+BEGIN_SRC emacs-lisp
(use-package kubernetes
  :commands (kubernetes-overview)
  :custom
  ((kubernetes-commands-display-buffer-function 'display-buffer)
   (Kubernetes-Commands-display-buffer-select nil)))
#+END_SRC

** Multiple Cursors ([[https://github.com/magnars/multiple-cursors.el][link]])

Multiple cursors for Emacs. This is some pretty crazy functionality,
so yes, there are kinks. Don't be afraid tho, I've been using it since
2011 with great success and much merriment.

#+BEGIN_SRC emacs-lisp
(use-package multiple-cursors
  :bind
  ("C->" . mc/mark-next-like-this)
  ("C-<" . mc/mark-previous-like-this))
#+END_SRC

** Org ([[https://orgmode.org/][link]])

Org mode is for keeping notes, maintaining TODO lists, planning
projects, and authoring documents with a fast and effective plain-text
syste.

#+BEGIN_SRC emacs-lisp
(defmacro org-babel-add-langs (langs)
  `(org-babel-do-load-languages
   'org-babel-load-languages
   (append org-babel-load-languages
           ',langs)))

(defun alist-unique (alist)
  (reduce (lambda (output value)
            (let* ((key (car value))
                   (existing-value (alist-get key output)))
              (cond ((not output) (list value))
                    ((not existing-value) (append output (list value)))
                    (t output))))
          alist :initial-value nil))

(defun append-alist-unique (values alist)
  "Add unique VALUE to ALIST when car of VALUE is unique, returns ALIST otherwise"
  (alist-unique (append alist values)))

(use-package org
  :hook
  (org-mode . turn-on-auto-fill)
  (org-src-mode . (lambda ()
                    (setq-local flycheck-disabled-checkers '(emacs-lisp-checkdoc))))
  :bind
  ("C-c l" . org-store-link)
  ("C-c a" . org-agenda)
  ("C-c c" . org-capture)

  :config
  (org-babel-add-langs ((emacs-lisp .  t)))
  (org-indent-mode t)
  (custom-set-faces '(org-ellipsis ((t (:foreground "gray40" :underline nil)))))
  (org-babel-add-langs
   ((ditaa . t)))
  :custom
  (org-modules
   '(org-protocol
     org-habit
     org-mouse
     org-tempo
     org-notify
     org-mac-link
     org-mac-iCal
     org-panel))
  (org-blank-before-new-entry
   '((heading . t)
     (plain-list-item . t)))
  (org-hide-leading-stars t)
  (org-src-tab-acts-natively t)
  (org-startup-indented t)
  (org-babel-min-lines-for-block-output 1)
  (org-speed-command-help t)
  (org-startup-folded "showeverything")
  (org-startup-with-inline-images t)
  (org-src-preserve-indentation t)
  (org-ellipsis " … " )
  (org-pretty-entities t)
  (org-hide-emphasis-markers t)
  (org-agenda-block-separator "")
  (org-fontify-whole-heading-line t)
  (org-fontify-done-headline t)
  (org-fontify-quote-and-verse-blocks t)
  (org-tags-column 0)
  (org-indent-indentation-per-level 1)
  (org-directory "~/Dropbox/org")
  (org-default-notes-file "notes.org")
  (org-agenda-files
   (list "inbox.org"
         "links.org"
         "todo.org"
         "done.org"
         "journal.org"))
  (org-refile-targets '((org-agenda-files :maxlevel . 1)))
  (org-refile-allow-creating-parent-nodes 'confirm)
  (org-capture-templates
   '(("a" "Appointment" entry (file  "gcal.org" )
      "* %?\n\n%^T\n\n:PROPERTIES:\n\n:END:\n\n")
     ("l" "Link" entry (file+headline "links.org" "Links")
      "* %? %^L %^g \n%T" :prepend t)
     ("b" "Blog idea" entry (file+headline "todo.org" "Blog Topics:")
      "* %?\n%T" :prepend t)
     ("t" "Todo Item" entry
      (file+headline "todo.org" "Todo")
      "* TODO %?\n:PROPERTIES:\n:CREATED: %u\n:END:" :prepend t :empty-lines 1)
     ("n" "Note" entry (file+headline "todo.org" "Note space")
      "* %?\n%u" :prepend t)
     ("j" "Journal" entry (file+olp+datetree "journal.org")
      "* %?\nEntered on %U\n  %i\n  %a")
     )))
#+END_SRC

#+BEGIN_SRC emacs-lisp
(use-package org-habit
  :ensure nil)

(use-package org-contacts
  :ensure nil)

(use-package org-tree-slide
  :custom
  (org-tree-slide-skip-outline-level 4)
  (org-tree-slide-skip-done nil)
  :config
  (global-set-key (kbd "") 'org-tree-slide-mode)
  (global-set-key (kbd "S-") 'org-tree-slide-skip-done-toggle)
  (define-key org-tree-slide-mode-map (kbd "")
    'org-tree-slide-move-previous-tree)
  (define-key org-tree-slide-mode-map (kbd "")
    'org-tree-slide-move-next-tree)
  (define-key org-tree-slide-mode-map (kbd "")
    'org-tree-slide-content)
  (org-tree-slide-narrowing-control-profile))

(use-package org-bullets
  :hook (org-mode . org-bullets-mode))

;; org-babel
(org-babel-add-langs
 ((emacs-lisp . t)
  (shell . t)))

(use-package ob-restclient
  :config
  (org-babel-add-langs
   ((restclient . t))))

(use-package ob-js
  :ensure nil
  :config
  (org-babel-add-langs
   ((js . t)))

  (add-to-list 'org-babel-tangle-lang-exts '("js" . "js")))

(use-package ob-deno
  :config
  (org-babel-add-langs
   ((deno . t))))

(use-package org-super-agenda
  :init
  :custom
  (org-super-agenda-groups
   ;; Each group has an implicit boolean OR operator between its selectors.
   '((:name "Today"        ; Optionally specify section name
            :time-grid t   ; Items that appear on the time grid
            :todo "TODAY") ; Items that have this TODO keyword
     (:name "Important"
            ;; Single arguments given alone
            :tag "bills"
            :priority "A")
     ;; Set order of multiple groups at once
     (:order-multi (2 (:name "Shopping in town"
                             ;; Boolean AND group matches items that match all subgroups
                             :and (:tag "shopping" :tag "@town"))
                      (:name "Food-related"
                             ;; Multiple args given in list with implicit OR
                             :tag ("food" "dinner"))
                      (:name "Personal"
                             :habit t
                             :tag "personal")
                      (:name "Space-related (non-moon-or-planet-related)"
                             ;; Regexps match case-insensitively on the entire entry
                             :and (:regexp ("space" "NASA")
                                           ;; Boolean NOT also has implicit OR between selectors
                                           :not (:regexp "moon" :tag "planet")))))
     ;; Groups supply their own section names when none are given
     (:todo "WAITING" :order 8)  ; Set order of this section
     (:todo ("SOMEDAY" "TO-READ" "CHECK" "TO-WATCH" "WATCHING")
            ;; Show this group at the end of the agenda (since it has the
            ;; highest number). If you specified this group last, items
            ;; with these todo keywords that e.g. have priority A would be
            ;; displayed in that group instead, because items are grouped
            ;; out in the order the groups are listed.
            :order 9)
     (:priority<= "B"
                  ;; Show this section after "Today" and "Important", because
                  ;; their order is unspecified, defaulting to 0. Sections
                  ;; are displayed lowest-number-first.
                  :order 1)
     ;; After the last group, the agenda will display items that didn't
     ;; match any of these groups, with the default order position of 99
     ))
  (org-super-agenda-mode))

(defun make-orgcapture-frame ()
  "Create a new frame and run org-capture."
  (interactive)
  (make-frame '((name . "remember") (width . 80) (height . 16)
                (top . 400) (left . 300)
                (font . "-apple-Monaco-medium-normal-normal-*-13-*-*-*-m-0-iso10646-1")
                ))
  (select-frame-by-name "remember")
  (org-capture)
  (delete-other-windows))

(use-package yequake
  :custom
  (yequake-frames
   '(("org-capture"
      (buffer-fns . (yequake-org-capture))
      (width . 0.75)
      (height . 0.5)
      (alpha . 0.95)
      (frame-parameters . ((undecorated . t)
                           (skip-taskbar . t)
                           (sticky . t)))))))
#+END_SRC

** Org Roam

#+begin_src emacs-lisp
(defun org-roam-node-insert-immediate (arg &rest args)
  "This will allow you to quickly create new notes for topics
you're mentioning while writing so that you can go back later and
fill those notes in with more details!"
  (interactive "P")
  (let ((args (cons arg args))
        (org-roam-capture-templates (list (append (car org-roam-capture-templates)
                                                  '(:immediate-finish t)))))
    (apply #'org-roam-node-insert args)))

(defun my/org-roam-filter-by-tag (tag-name)
  "returns a filter function for "
  (lambda (node)
    (member tag-name (org-roam-node-tags node))))

(defun my/org-roam-list-notes-by-tag (tag-name)
  "Returns list of noted with given filetag"
  (mapcar #'org-roam-node-file
          (seq-filter
           (my/org-roam-filter-by-tag tag-name)
           (org-roam-node-list))))

(defun my/org-roam-refresh-agenda-list ()
  "Refreshes the agenda list adding Project notes to the list"
  (interactive)
  (setq org-agenda-files (my/org-roam-list-notes-by-tag "Project")))

(use-package org-roam
  :custom
  (org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
  (org-roam-directory "~/Dropbox/OrgRoam")
  (org-roam-completion-everywhere t)
  (org-roam-capture-templates
   '(("d" "default" plain
      "%?"
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+date: %U\n")
      :unnarrowed t)
     ("p" "project" plain
      (file "~/Dropbox/OrgRoam/Templates/Project.org")
      :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+date: %U\n#+category: ${title}\n#+filetags: Project")
      :unnarrowed t)))

  :bind (("C-c n l" . org-roam-buffer-toggle)
         ("C-c n f" . org-roam-node-find)
         ("C-c n g" . org-roam-graph)
         ("C-c n i" . org-roam-node-insert)
         ("C-c n c" . org-roam-capture)
         ("C-c n I" . org-roam-node-insert-immediate)
         ;; Dailies
         ("C-c n j" . org-roam-dailies-capture-today)

         :map org-mode-map
         ("C-M-i"    . completion-at-point)

         :map org-roam-dailies-map
         ("Y" . org-roam-dailies-capture-yesterday)
         ("T" . org-roam-dailies-capture-tomorrow))

  :bind-keymap
  ("C-c n d" . org-roam-dailies-map)
  :custom-face
  (org-roam-link ((t (:foreground "#e24888" :underline t))))
  (org-roam-link-current ((t (:foreground "#e24888" :underline t))))
  :config
  (org-roam-setup)
  (require 'org-roam-dailies)
  (org-roam-db-autosync-mode)
  (my/org-roam-refresh-agenda-list))
#+end_src

** Htmlize for org-mode

#+BEGIN_SRC emacs-lisp
(use-package htmlize)
#+END_SRC

** Load theme

#+BEGIN_SRC emacs-lisp
(use-package doom-themes
  :config
  (load-theme 'doom-molokai t)
  (doom-themes-org-config)
  (doom-themes-visual-bell-config)
  (doom-themes-neotree-config))
#+END_SRC

** Better defaults

#+BEGIN_SRC emacs-lisp
(use-package better-defaults)
#+END_SRC

** Key suffixes popup

#+BEGIN_SRC emacs-lisp
(use-package which-key
  :init
  (which-key-mode)
  :custom
  ((which-key-popup-type 'side-window)
   (which-key-side-window-location 'bottom)
   (which-key-side-window-max-width 0.33)
   (which-key-side-window-max-height 0.25)))
#+END_SRC

** Editing forms in chrome

#+BEGIN_SRC emacs-lisp
(use-package atomic-chrome
  :config
  (atomic-chrome-start-server))
#+END_SRC

** Better help dialogs

#+BEGIN_SRC emacs-lisp
(use-package helpful
  :bind (("C-h f"  . helpful-callable)
         ("C-h v"  . helpful-variable)
         ("C-h k"  . helpful-key)))
#+END_SRC

** Better list-package mode

#+BEGIN_SRC emacs-lisp
(use-package paradox
  :custom
  (paradox-github-token t)
  :config
  (paradox-enable))
#+END_SRC


** Cycling between different var notations

#+BEGIN_SRC emacs-lisp
(use-package string-inflection
  :bind
  ("C-c C-u" . string-inflection-all-cycle))
#+END_SRC

** Open dash at point

#+BEGIN_SRC emacs-lisp
(use-package dash-at-point
  :bind
  ("C-c d" . dash-at-point)
  ("C-c e" . dash-at-point-with-docset))
#+END_SRC

** Move lines using alt + arrows

#+BEGIN_SRC emacs-lisp
(use-package move-text
  :config
  (move-text-default-bindings))
#+END_SRC

** Anzu - current match / all matches in modeline

#+BEGIN_SRC emacs-lisp
(use-package anzu
  :init
  (global-anzu-mode +1)
  :bind
  ("M-%" . anzu-query-replace)
  ("C-M-%" . anzu-query-replace-regexp))
#+END_SRC

** Modeline

#+BEGIN_SRC emacs-lisp
(use-package doom-modeline
  :after all-the-icons
  :custom
  ((doom-modeline-icon t)
   (doom-modeline-major-mode-icon t)
   (doom-modeline-major-mode-color-icon t)
   (doom-modeline-buffer-state-icon t)
   (doom-modeline-buffer-modification-icon t)
   (doom-modeline-minor-modes nil)
   (doom-modeline-checker-simple-format t))
  :hook (after-init . doom-modeline-mode))
#+END_SRC

** Magit - best git client ever

#+BEGIN_SRC emacs-lisp
(use-package magit
  :init
  :bind ("C-x g" . magit-status)
  :hook (global-git-commit-mode . flyspell-mode)
  :custom

  (vc-handled-backends nil)
  (magit-process-finish-apply-ansi-colors t)
  (magit-refresh-status-buffer t)
  (magit-blame-goto-chunk-hook '(magit-blame-maybe-show-message))

  :config
  (remove-hook 'magit-refs-sections-hook 'magit-insert-tags)
  (add-hook 'magit-process-find-password-functions
            'magit-process-password-auth-source)

  (transient-define-suffix magit-submodule-update-all ()
    "Update all submodules"
    :description "Update All (git submodule update --init --recursive)"
    (interactive)
    (magit-with-toplevel
      (magit-run-git-async "submodule" "update" "--init" "--recursive"))))
#+END_SRC

#+BEGIN_SRC emacs-lisp
(use-package forge
  :after magit
  :config
  (add-to-list 'forge-alist '("gitlab.services.ams.osa" "gitlab.services.ams.osa/api/v4" "gitlab.services.ams.osa" forge-gitlab-repository)))
#+END_SRC

** magit-todos ([[https://github.com/alphapapa/magit-todos][link]])

#+begin_src emacs-lisp
(use-package magit-todos
  :after (magit)
  :config
  (magit-todos-mode 1))
#+end_src

** Magit Delta

#+begin_src emacs-lisp
  (use-package magit-delta
    :ensure-system-package git-delta
    :hook (magit-mode . magit-delta-mode))
#+end_src

** git-gutter

#+begin_src emacs-lisp
(use-package git-gutter
  :hook (text-mode . git-gutter-mode)
  :config
  (setq git-gutter:update-interval 1))

(use-package git-gutter-fringe
  :config
  (define-fringe-bitmap 'git-gutter-fr:added [224] nil nil '(center repeated))
  (define-fringe-bitmap 'git-gutter-fr:modified [224] nil nil '(center repeated))
  (define-fringe-bitmap 'git-gutter-fr:deleted [128 192 224 240] nil nil 'bottom))
#+end_src

** hl-todo-mode ([[https://github.com/tarsius/hl-todo][link]])

#+begin_src emacs-lisp
(use-package hl-todo
  :config
  :hook (prog-mode . hl-todo-mode))
#+end_src

** goto-line-preview

#+BEGIN_SRC emacs-lisp
(use-package goto-line-preview
  :bind ([remap goto-line] . goto-line-preview)
  :config)
#+END_SRC

** unfill

#+BEGIN_SRC emacs-lisp
(use-package unfill
  :bind ([remap fill-paragraph] . unfill-toggle))
#+END_SRC

** Snippets

#+BEGIN_SRC emacs-lisp
(use-package yasnippet
  :hook (prog-mode . yas-minor-mode))

(use-package yasnippet-snippets
  :after yasnippet
  :config
  (yas-reload-all))
#+END_SRC

** Prescient

#+begin_src emacs-lisp
(use-package prescient
  :config
  (prescient-persist-mode))
#+end_src

** command-log

#+BEGIN_SRC emacs-lisp
(use-package command-log-mode)
#+END_SRC

** Key statistics

#+BEGIN_SRC emacs-lisp
(use-package keyfreq
  :config
  (setq keyfreq-excluded-commands
        '(
          mwheel-scroll
          self-insert-command
          forward-char
          left-char
          right-char
          backward-char
          previous-line
          next-line))

  (keyfreq-mode 1)
  (keyfreq-autosave-mode 1))
#+END_SRC

** rg - ripgrep frontend

#+BEGIN_SRC emacs-lisp
(use-package rg
  :ensure-system-package rg
  :custom
  (rg-custom-type-aliases
   '(("svelte" .    "*.svelte")))
  :config
  (rg-enable-menu))
#+END_SRC

** Dired

I've tried ~[[https://github.com/ralesi/ranger.el][ranger-mode~]] with it's simplier ~[[https://github.com/ralesi/ranger.el#minimal-ranger-mode-deer][deer-mode~]] and I must say, nothing beets good old [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html][Dired]].

With some additions of course, like [[https://github.com/purcell/diredfl][~diredfl~]] for colors and [[https://gitlab.com/xuhdev/dired-quick-sort][~dired-quick-sort~]] for better sorting with native ~gnu ls~

#+BEGIN_SRC emacs-lisp
(use-package dired
  :ensure nil
  :custom
  (dired-dwim-target t)
  :config
  (cond ((string-equal system-type "darwin")
         (setq insert-directory-program "gls"
               dired-use-ls-dired t)
         (setq dired-listing-switches "-alXv --group-directories-first"))))

(use-package diredfl
  :after dired
  :init
  (diredfl-global-mode 1))

(use-package dired-quick-sort
  :after dired
  :custom
  (ls-lisp-use-insert-directory-program t)
  :config
  (dired-quick-sort-setup))

(use-package dired-subtree
  :after dired
  :bind (:map dired-mode-map
              ("TAB" . dired-subtree-toggle)))
#+END_SRC

** Flycheck

#+BEGIN_SRC emacs-lisp
(use-package flycheck
  :custom
  (flycheck-idle-change-delay 1)
  :custom-face
  (flycheck-error ((t (:underline (:color "#e74c3c" :style wave)))))
  (flycheck-info ((t (:underline (:color "#b6e63e" :style wave)))))
  :config
  (global-flycheck-mode 1))
#+END_SRC

** restclient

#+BEGIN_SRC emacs-lisp
(use-package restclient
  :defer t
  :mode (("\\.http\\'" . restclient-mode))
  :bind (:map restclient-mode-map
              ("C-c C-f" . json-mode-beautify)))
#+END_SRC

** jq

#+BEGIN_SRC emacs-lisp
(use-package jq-mode
  :after (org-mode json-mode)
  :commands (jq-mode jq-interactively)
  :mode ("\\.jq$" . js-mode)
  :bind (:map json-mode-map
              ("C-c C-j" . jq-interactively))
  :config
  (org-babel-add-langs
   ((jq . t))))
#+END_SRC

** LSP Mode

#+BEGIN_SRC emacs-lisp
(use-package lsp-mode
  :commands (lsp lsp-deferred)
  :custom
  (lsp-auto-guess-root t)
  (lsp-keymap-prefix "C-c l")
  (lsp-enable-indentation nil)
  (lsp-enable-on-type-formatting nil)
  (lsp-clients-typescript-init-opts
   '(:includeCompletionsForModuleExports nil :generateReturnInDocTemplate t))
  (lsp-yaml-schema-store-local-db
   (no-littering-expand-var-file-name "./lsp/lsp-yaml-schemas.json"))

  :hook (lsp-mode . lsp-enable-which-key-integration)
  :custom-face
  '((lsp-lsp-flycheck-info-unnecessary-face ((t (:underline (:color "#b6e63e" :style wave)))) t)))

(use-package lsp-ui
  :after lsp-mode
  :hook (lsp-mode . lsp-ui-mode)
  :custom
  (lsp-ui-sideline-enable nil)
  (lsp-ui-sideline-show-hover nil)
  (lsp-ui-doc-position 'at-point))

(use-package lsp-tailwindcss
  :custom
  (lsp-tailwindcss-add-on-mode t))
#+END_SRC

** DAP Mode

Run ~dap-chrome-setup~ after requiring ~dab-chrome~

#+begin_src emacs-lisp
(use-package dap-mode
  :config
  (require 'dap-chrome)
  (dap-ui-mode 1)
  (dap-tooltip-mode 1)
  (dap-ui-controls-mode 1)
  (dap-register-debug-template
   "Opera GX Corner [laungh]"
   (list :type "chrome"
         :name "Opera GX Corner [laungh]"
         :request "laungh"
         :url "https://local.op-test.net/"
         :runtimeExecutable "/Applications/Opera GX.app/Contents/MacOS/Opera"
         :webRoot "${workspaceFolder}/dist/"
         :userDataDir t
         :sourceMaps t
         ))
  (dap-register-debug-template
   "Opera GX Corner [attach]"
   (list :type "chrome"
         :name "Opera GX Corner [attach]"
         :request "attach"
         :port 9222
         :url "https://local.op-test.net/"
         :webRoot "${workspaceFolder}/dist/"
         :userDataDir t
         :sourceMaps t
         )))
#+end_src

** File types
*** .env

#+begin_src emacs-lisp
(use-package dotenv-mode
  :mode ("\\.env\\..*\\'" . dotenv-mode))
#+end_src

*** Elisp

#+begin_src emacs-lisp
(use-package elisp
  :ensure nil
  :mode ("\\.el\\'" . emacs-lisp-mode))
#+end_src

*** Markdown

#+BEGIN_SRC emacs-lisp
(use-package markdown-mode
  :mode (("README\\.md\\'" . gfm-mode)
         ("\\.md\\'" . markdown-mode)
         ("\\.markdown\\'" . markdown-mode)))

(use-package grip-mode
  :bind
  (:map markdown-mode-command-map
        ("g" . grip-mode))
  :config
  (let ((credential (auth-source-user-and-password "github.com")))
    (setq grip-github-user (car credential)
          grip-github-password (cadr credential))))

(use-package edit-indirect
  :after markdown-mode)
#+END_SRC

*** Htmlize for org-mode

#+BEGIN_SRC emacs-lisp
(use-package htmlize)
#+END_SRC

*** YAML

#+BEGIN_SRC emacs-lisp
(use-package yaml-mode
  :mode "\\.yaml")
#+END_SRC

*** GO

#+BEGIN_SRC emacs-lisp
(use-package go-mode
  :mode "\\.go"
  :config
  (add-hook 'go-mode-hook
            (lambda ()
              (add-hook 'before-save-hook 'gofmt-before-save)
              (local-set-key (kbd "M-.") 'godef-jump))))
#+END_SRC

*** JSON

#+BEGIN_SRC emacs-lisp
(use-package json-mode
  :mode "\\.json$"
  :interpreter "json"
  :config
  (setq js-indent-level 2))

#+END_SRC

*** CSS

#+BEGIN_SRC emacs-lisp
(use-package css-mode
  :mode "\\.css")
#+END_SRC

*** SCSS

#+BEGIN_SRC emacs-lisp
(use-package scss-mode
  :mode "\\.scss"
  :hook (scss-mode . lsp-deferred))
#+END_SRC

*** LUA

#+BEGIN_SRC emacs-lisp
(use-package lua-mode
  :mode ("\\.lua"))
#+END_SRC

*** JS

#+BEGIN_SRC emacs-lisp
(use-package typescript-mode
  :after lsp-mode
  :mode ("\\.ts$")
  :custom
  (typescript-indent-level 2)
  :hook
  (typescript-mode . lsp-deferred))

(use-package js2-mode
  :mode ("\\.[cm]*js$")
  :hook (js2-mode . lsp-deferred))

(use-package eslintd-fix
  :hook (js2-mode . eslintd-fix-mode))

(use-package apheleia
  :config
  (apheleia-global-mode +1))

(use-package web-mode
  :after lsp-mode
  :mode
  ("\\.html\\'"
   "\\.tsx\\'"
   "\\.svelte\\'")

  :hook
  (web-mode . lsp-deferred)
  :custom
  (web-mode-content-types-alist
   '(("jsx" . "\\.tsx\\'")
     ("jsx" . "\\.jsx\\'")
     ("svelte" . "\\.svelte\\'")
     ("html" . "\\.html\\'")))
  (web-mode-enable-auto-indentation nil)
  (web-mode-indentation-params
   '(("lineup-args" . t)
     ("lineup-calls" . t)
     ("lineup-concats" . t)
     ("lineup-quotes" . t)
     ("lineup-ternary" . nil)
     ("case-extra-offset" . t))))
#+END_SRC

*** Py

#+BEGIN_SRC emacs-lisp
(use-package python-mode
  :mode "\\.py"
  :interpreter "py"
  :config
  (setq python-shell-interpreter "ipython"
        python-shell-interpreter-args "-i --simple-prompt"))
#+END_SRC

*** Dockerfile and docker-compose.yml

#+begin_src emacs-lisp
(use-package dockerfile-mode
  :mode "Dockerfile$")

(use-package docker-compose-mode
  :mode "docker-compose.yml.py$")
#+end_src

* Other

#+BEGIN_SRC emacs-lisp
;; TODO: Use general for keybindings
(defun my-delete-trailing-whitespace ()
  "Deleting trailing whitespaces."
  (when (derived-mode-p 'prog-mode)
    (delete-trailing-whitespace)))

(message ".emacs loaded successfully.")

(put 'downcase-region 'disabled nil)
(put 'upcase-region 'disabled nil)
#+END_SRC

本源码包内暂不包含可直接显示的源代码文件,请下载源码包。